Coverage for zombie_nomnom/engine/commands.py: 100%
37 statements
« prev ^ index » next coverage.py v7.6.8, created at 2024-12-05 01:14 +0000
« prev ^ index » next coverage.py v7.6.8, created at 2024-12-05 01:14 +0000
1from abc import ABC, abstractmethod
2import sys
4from pydantic import validate_call
5from .models import RoundState
8class Command(ABC):
9 """
10 Used to modify round state. Cannot be used to reset game.
11 """
13 @abstractmethod
14 def execute(self, round: RoundState) -> RoundState: # pragma: no cover
15 """
16 Method to generate a new RoundState that represents modifications on the command.
18 **Parameters**
19 - round(`RoundState`): the round we are on.
21 **Returns** `RoundState`
23 New instance of round with modified state.
24 """
27class DrawDice(Command):
28 """
29 The core command that represents handling a draw action in the game.
30 This will attempt to draw dice in your hand to fill in any dice that
31 are not re-rollable then roll the dice for the turn. Then it will
32 check to make sure you are still alive and if so keep dice in your hand
33 and return a new round object.
35 **Parameters**
36 - amount_drawn (`int`): Dice this action will attempt to draw.
37 """
39 amount_drawn: int
40 """Amount of dice that this action will attempt to draw."""
42 def __init__(self, amount_drawn: int = 3) -> None:
43 if amount_drawn <= 0:
44 raise ValueError("Cannot draw a no or a negative amount of dice.")
45 self.amount_drawn = amount_drawn
47 @validate_call
48 def execute(self, round: RoundState) -> RoundState:
49 """
50 Executes a dice draw on a round that is active.
52 If round is already over will return given round context.
54 **Parameters**
55 - round(`RoundState`): the round we are on.
57 **Returns** `RoundState`
59 New instance of a round with player adding dice to hand.
60 """
61 if round.ended:
62 return round
63 player = round.player
64 dice_to_roll = player.rerolls
65 total_dice = len(dice_to_roll)
66 try:
67 bag = (
68 round.bag.clear_drawn_dice()
69 if total_dice == self.amount_drawn
70 else round.bag.draw_dice(amount=self.amount_drawn - total_dice)
71 )
72 except ValueError as exc:
73 return self.execute(
74 round=RoundState(
75 bag=round.bag.add_dice(player.brains),
76 player=player,
77 ended=round.ended,
78 )
79 )
80 dice_to_roll.extend(bag.drawn_dice)
81 player = player.add_dice(*bag.drawn_dice)
83 for die in dice_to_roll:
84 die.roll()
86 ended = player.is_player_dead()
87 if ended:
88 player = player.clear_hand()
90 return RoundState(
91 bag=bag,
92 player=player,
93 ended=ended,
94 )
97class Score(Command):
98 """
99 Command to score the hand of a player and add the brains they have as points to their total.
100 """
102 def execute(self, round: RoundState) -> RoundState:
103 """
104 Scores the hand of the current player by rolling up all the scoring faces and adding it to their hand.
106 **Parameters**
107 - round (`RoundState`): The round we are currently in.
109 **Returns** `RoundState`
111 Roundstate that is now ended with the player with hand cleared and new score added to them.
112 """
113 if round.ended:
114 return round
115 player = round.player.calculate_score()
116 return RoundState(
117 bag=round.bag,
118 player=player,
119 ended=True,
120 )