game.py 11 KB

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