game.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. import random
  2. from typing import List, Dict
  3. from color import Color
  4. from cards import Card, shuffle
  5. from option import OptionCode, Option
  6. from player import Player, StateCode, ErrorCode
  7. all_colors = [Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN]
  8. class Game(object):
  9. """description of class"""
  10. players: List[Player]
  11. current_player: Player
  12. current_dealer: Player
  13. stock: List[str]
  14. number_of_cards: int
  15. def __init__(self):
  16. self.stock = []
  17. self.number_of_cards = 0
  18. self.players = []
  19. self.current_player = None
  20. self.current_dealer = None
  21. def join_player(self, name, color=None):
  22. if color is not None:
  23. color_player = next((p for p in self.players if p.color == color and p.Name is None), None)
  24. if color_player is not None:
  25. color_player.name = name
  26. return color_player
  27. player = Player(None, name)
  28. self.players.append(player)
  29. player.state = StateCode.PICK_COLOR
  30. if color is not None:
  31. self.pick_color(player, color)
  32. else:
  33. self.set_pick_color_state()
  34. return player
  35. def unjoin_player(self, player):
  36. if player.color is None:
  37. self.players.remove(player)
  38. else:
  39. player.name = None
  40. self.set_pick_color_state()
  41. def pick_color(self, player, color):
  42. color_player = next((p for p in self.players if p.color == color), None)
  43. if color_player is not None:
  44. if color_player.name is None:
  45. # reconnect, merge
  46. player.merge_from(color_player)
  47. self.players.remove(color_player)
  48. else:
  49. # error
  50. player.message = f"Kleur {color} is al gekozen door een andere speler. " + player.message
  51. player.set_error(ErrorCode.COLOR_ALREADY_CHOSEN, color=color)
  52. return
  53. player.color = color
  54. self.set_pick_color_state()
  55. def set_pick_color_state(self):
  56. used_colors = [player.color for player in self.players if player.color is not None and player.name is not None]
  57. available_colors = [color for color in all_colors if color not in used_colors]
  58. for player in self.players:
  59. if player.state == StateCode.PICK_COLOR:
  60. player.options = [Option(OptionCode.PICK_COLOR, str(color), color=color) for color in available_colors]
  61. if len(used_colors) == 4 and player.color is not None:
  62. player.options.append(Option(OptionCode.DEAL, "Delen"))
  63. if player.color is None:
  64. player.message = "Kies een kleur om mee te spelen"
  65. else:
  66. player.message = "Wie begint er met delen?"
  67. player.set_others(self.players)
  68. def deal(self, dealer):
  69. self.current_player = dealer
  70. self.current_dealer = dealer
  71. if self.number_of_cards <= 2:
  72. self.stock = shuffle(2)
  73. self.number_of_cards = 6
  74. else:
  75. self.number_of_cards -= 1
  76. for player in self.players:
  77. if player.color is not None:
  78. player.hand = self.stock[:self.number_of_cards]
  79. self.stock = self.stock[self.number_of_cards:]
  80. player.options = [Option(OptionCode.SWAP_CARD, card.denom, card=card) for card in player.hand]
  81. player.message = "Kies een kaart om te wisselen"
  82. player.state = StateCode.SWAP_CARD
  83. player.swap_card = None
  84. player.card_is_swapped = False
  85. player.passed = False
  86. player.set_current(dealer)
  87. def swap_card(self, player, card):
  88. if player.swap_card is not None:
  89. player.hand.append(player.swap_card)
  90. player.swap_card = None
  91. player.hand.remove(card)
  92. partner = self.partner(player)
  93. if partner.swap_card is None:
  94. player.swap_card = card
  95. player.message = "Wacht op je maat"
  96. player.state = StateCode.SWAP_CARD
  97. player.options = [Option(OptionCode.SWAP_CARD, card.denom, card=card) for card in player.hand]
  98. player.options.append(Option(OptionCode.UNDO_CARD, "Terug"))
  99. return
  100. player.hand.append(partner.swap_card)
  101. partner.swap_card = None
  102. partner.hand.append(card)
  103. player.card_is_swapped = True
  104. partner.card_is_swapped = True
  105. partner.options.clear()
  106. player.options.clear()
  107. player.message = ""
  108. if all(player.card_is_swapped for player in self.players if player.color is not None):
  109. self.next_turn()
  110. else:
  111. player.message = "Wacht op het andere team"
  112. player.state = StateCode.SWAP_CARD_OTHERS
  113. partner.message = "wacht op het andere team"
  114. partner.state = StateCode.SWAP_CARD_OTHERS
  115. def play_card(self, player, card):
  116. if player.play_card is not None:
  117. player.hand.append(player.play_card)
  118. player.play_card = None
  119. player.hand.remove(card)
  120. player.play_card = card
  121. player.options = [Option(OptionCode.UNDO_CARD, "Terug"), Option(OptionCode.READY, "Klaar"), Option(OptionCode.SKIP_TURN, "Pas")]
  122. player.options.extend(Option(OptionCode.PLAY_CARD, card.denom, card=card) for card in self.current_player.hand)
  123. player.message = f"Je speelt {card.denom}"
  124. player.state = StateCode.PLAY_CARD
  125. for other in self.players:
  126. if other.color != player.color:
  127. other.message = f"{player.name} speelt een {card.denom}"
  128. other.state = StateCode.PLAY_CARD_OTHER
  129. other.play_card = card
  130. def drop_cards(self, player):
  131. player.hand = []
  132. player.options = []
  133. player.passed = True
  134. player.play_card = None
  135. self.next_turn()
  136. def ready(self, player):
  137. player.options.clear()
  138. player.play_card = None
  139. self.next_turn()
  140. def undo_card(self, player):
  141. if player.swap_card is not None:
  142. player.hand.append(player.swap_card)
  143. player.swap_card = None
  144. player.options = [Option(OptionCode.SWAP_CARD, card.denom, card=card) for card in player.hand]
  145. player.message = "Kies een kaart om te wisselen"
  146. player.state = StateCode.SWAP_CARD
  147. else:
  148. player.hand.append(player.play_card)
  149. player.play_card = None
  150. self.turn()
  151. def play_option(self, player, option):
  152. if option.code == OptionCode.PICK_COLOR:
  153. return self.pick_color(player, option.color)
  154. elif option.code == OptionCode.DEAL:
  155. return self.deal(player)
  156. elif option.code == OptionCode.SWAP_CARD:
  157. return self.swap_card(player, option.card)
  158. elif option.code == OptionCode.PLAY_CARD:
  159. return self.play_card(player, option.card)
  160. elif option.code == OptionCode.READY:
  161. return self.ready(player)
  162. elif option.code == OptionCode.UNDO_CARD:
  163. return self.undo_card(player)
  164. elif option.code == OptionCode.SKIP_TURN:
  165. return self.drop_cards(player)
  166. else:
  167. raise Exception(f"Unknown option {option.code}")
  168. def next_player(self, player):
  169. if player.color == Color.RED:
  170. color = Color.BLUE
  171. elif player.color == Color.BLUE:
  172. color = Color.YELLOW
  173. elif player.color == Color.YELLOW:
  174. color = Color.GREEN
  175. elif player.color == Color.GREEN:
  176. color = Color.RED
  177. else:
  178. raise Exception(f"Unknown color {player.Color}")
  179. return next(player for player in self.players if player.color == color)
  180. def next_turn(self):
  181. if all(len(player.hand) == 0 for player in self.players):
  182. self.next_deal()
  183. else:
  184. self.current_player = self.next_player(self.current_player)
  185. self.current_player.play_card = None
  186. while len(self.current_player.hand) == 0:
  187. self.current_player = self.next_player(self.current_player)
  188. self.turn()
  189. def next_deal(self):
  190. dealer = self.next_player(self.current_dealer)
  191. self.current_player = dealer
  192. dealer.options = [Option(OptionCode.DEAL, "Delen")]
  193. dealer.message = f"Jij bent aan de beurt om te delen."
  194. dealer.state = StateCode.DEAL
  195. for player in self.players:
  196. player.set_current(dealer)
  197. player.play_card = None
  198. if player.color != dealer.color:
  199. player.message = f"{dealer.name} is aan de beurt om te delen"
  200. player.state = StateCode.DEAL_OTHER
  201. def turn(self):
  202. player = self.current_player
  203. player.options = [Option(OptionCode.PLAY_CARD, card.denom, card=card) for card in player.hand]
  204. player.options.append(Option(OptionCode.SKIP_TURN, "Pas"))
  205. player.message = "Kies een kaart om te spelen"
  206. player.state = StateCode.PLAY_CARD
  207. for player in self.players:
  208. player.set_current(self.current_player)
  209. player.play_card = None
  210. if player.color != self.current_player.color:
  211. player.message = f"{self.current_player.name} is aan de beurt"
  212. player.state = StateCode.PLAY_CARD_OTHER
  213. def partner(self, player):
  214. if player.color == Color.RED:
  215. color = Color.YELLOW
  216. elif player.color == Color.BLUE:
  217. color = Color.GREEN
  218. elif player.color == Color.YELLOW:
  219. color = Color.RED
  220. elif player.color == Color.GREEN:
  221. color = Color.BLUE
  222. else:
  223. raise Exception(f"Unknown color {player.Color}")
  224. return next(player for player in self.players if player.color == color)
  225. if __name__ == "__main__":
  226. game = Game()
  227. red = game.join_player("Rood")
  228. blue = game.join_player("Blauw")
  229. yellow = game.join_player("Geel")
  230. green = game.join_player("Groen")
  231. olive = game.join_player("Olijf")
  232. players = [blue, yellow, green, red]
  233. game.pick_color(red, Color.RED)
  234. game.pick_color(blue, Color.BLUE)
  235. game.pick_color(yellow, Color.YELLOW)
  236. game.pick_color(green, Color.GREEN)
  237. for round in range(2):
  238. for deal in [6, 5, 4, 3, 2]:
  239. player = players[0]
  240. print(f"{player.name} deals {deal} cards")
  241. game.deal(player)
  242. for player in game.players:
  243. print(player.get_json(), end="\n\n")
  244. game.swap_card(yellow, yellow.hand[deal - 1])
  245. game.swap_card(red, red.hand[1])
  246. if round == 0:
  247. game.swap_card(green, green.hand[0])
  248. else:
  249. game.swap_card(olive, olive.hand[0])
  250. game.swap_card(blue, blue.hand[-1])
  251. players = players[1:] + players[:1]
  252. for turn in range(deal):
  253. for player in players:
  254. card = player.hand[0]
  255. game.play_card(player, card)
  256. print(f"{player.name} plays {card.denom} of {card.suit}")
  257. game.ready(player)
  258. if round == 0:
  259. print(green.get_json(), end="\n\n")
  260. green.name = None
  261. game.pick_color(olive, Color.GREEN)
  262. players = [yellow, olive, red, blue]