Coverage for zombie_nomnom/models/dice.py: 100%

43 statements  

« prev     ^ index     » next       coverage.py v7.6.8, created at 2024-12-05 01:14 +0000

1""" 

2This module contains everything we care about when it comes to the die. 

3We define a class to contain the faces as well as be able to select one 

4using the random built-in library. 

5 

6We can instatation an instance like this 

7```python 

8from zombie_nomnom.models.dice import Die, Face 

9 

10custom_die = Die(faces=[ 

11 Face.BRAIN, 

12 Face.BRAIN, 

13 Face.BRAIN, 

14 Face.SHOTGUN 

15 Face.SHOTGUN, 

16 Face.SHOTGUN, 

17]) 

18 

19# is currently set to None because it was not set. 

20custom_die.current_face  

21 

22# roll and calculate the current face 

23custom_die.roll() 

24 

25# will be one of the faces in the in the faces array 

26custom_die.current_face 

27``` 

28 

29Most of the time you will want to use a preconfigured recipe 

30To build your dice which you can use our `create_die` method. 

31 

32```python 

33from zombie_nomnom.models.dice import create_die, DieColor 

34 

35green_die = create_die(DieColor.GREEN) 

36 

37yellow_die = create_die(DieColor.YELLOW) 

38 

39red_die = create_die(DieColor.RED) 

40``` 

41 

42Most of the die in the game are already pre-defined so you can expirement 

43and use different dice as you make your own custom games. 

44 

45""" 

46 

47from enum import Enum 

48from pydantic import BaseModel, Field, field_validator 

49import random 

50 

51 

52class Face(str, Enum): 

53 """ 

54 Face of the die for the game. 

55 

56 There are three core ones: 

57 - BRAIN: Single point scoring face 

58 - FOOT: Neutral dice that will be re-rolled first before any other die are given. 

59 - SHOTGUN: Damaging dice where you are limited to only so many before your turn is over. 

60 """ 

61 

62 BRAIN = "BRAIN" 

63 """Scoring `Face` worth a single point. 

64 """ 

65 FOOT = "FOOT" 

66 """Neutral `Face` that we will reroll. 

67 """ 

68 SHOTGUN = "SHOTGUN" 

69 """Damaging `Face` that may end the turn. 

70 """ 

71 

72 

73class DieFace(BaseModel): 

74 """ 

75 Represents a custom face on a die. Used to allow us to be able to score extra points or damage on a player when drawn. 

76 """ 

77 

78 name: str 

79 """Name of the face.""" 

80 score: int 

81 """Amount of points a player will gain from face.""" 

82 damage: int 

83 """Amount of damage a player will take from face.""" 

84 

85 

86class DieColor(str, Enum): 

87 """ 

88 Names of special core dice in the game. 

89 There are only three to begin with: RED, YELLOW, GREEN 

90 """ 

91 

92 RED = "RED" 

93 """The hardest die to score on in the game with only a single side. 

94 """ 

95 YELLOW = "YELLOW" 

96 """The most medium die to score on with an equal number of brain and shot sides. 

97 """ 

98 GREEN = "GREEN" 

99 """The most forgiving dice with only a single side that will damage you. 

100 """ 

101 

102 

103# TODO(Milo): Update this for custom exception on invalid dice. 

104class Die(BaseModel): 

105 """ 

106 Represents the die we are rolling in the game. 

107 This is currently enforced to only support 6 sided dice. 

108 """ 

109 

110 name: str | None = None 

111 """ 

112 The plaintext name of the die. 

113 """ 

114 faces: list[DieFace | Face] = Field(min_length=6, max_length=6) 

115 """ 

116 faces of the dice. It is currently only allowed to have 6 values. 

117 """ 

118 current_face: Face | DieFace | None = None 

119 """ 

120 The currently displayed face of the die. Defaults to None. 

121 """ 

122 

123 def roll(self) -> Face: 

124 """Rolls the dice using the `builtins.random` and updates the current_face field. 

125 

126 **Returns** 

127 - `Face`: The face that the die is now on. 

128 """ 

129 self.current_face = random.choice(self.faces) 

130 return self.current_face 

131 

132 

133_dice_face_mapping = { 

134 DieColor.RED: {Face.BRAIN: 1, Face.FOOT: 2, Face.SHOTGUN: 3}, 

135 DieColor.YELLOW: {Face.BRAIN: 2, Face.FOOT: 2, Face.SHOTGUN: 2}, 

136 DieColor.GREEN: {Face.BRAIN: 3, Face.FOOT: 2, Face.SHOTGUN: 1}, 

137} 

138 

139 

140# TODO(Milo): Update this with custom exception for invalid dice. 

141def create_die(color: DieColor) -> Die: 

142 """Factory method to take in a `DieColor` and then create a die based on that. 

143 Only supports the first three colors defined: `DieColor.RED`, `DieColor.YELLOW`, `DieColor.GREEN`. 

144 

145 **Parameters** 

146 - color (`DieColor`): The color of the dice you want the factory to produce. 

147 

148 `Raises`: 

149 - `ValueError`: When we are unable to resolve the color to a known recipe. 

150 

151 `Returns` 

152 - `Die`: The dice defined by the color given. 

153 """ 

154 if color not in _dice_face_mapping: 

155 raise ValueError(f"Unknown Die Color: {color}") 

156 

157 mapped_color = _dice_face_mapping[color] 

158 faces = [] 

159 for face, amount in mapped_color.items(): 

160 faces.extend([face] * amount) 

161 return Die(faces=faces, name=color)