game.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #!usr/bin/python
  2. import enum
  3. import json
  4. import board
  5. import server_socket
  6. from player import Player
  7. class MSG_TYPE(enum.Enum):
  8. ERROR = -1
  9. UNKNOWN = 0
  10. START = 1
  11. QUIT = 2
  12. GIVE_CARD = 3
  13. class GAME_STATE(enum.Enum):
  14. LOBBY = 0
  15. QUIT = 1
  16. PLAY = 2
  17. class Game:
  18. def __init__(self, serversocket, score_limit=66, nturn=10):
  19. self.players = {}
  20. self.board = None
  21. self.ssock = serversocket
  22. self.turn = 1
  23. self.score_limit = score_limit
  24. self.cards_dealt = nturn # CARDS In Hand
  25. self.game_state = GAME_STATE.LOBBY
  26. def get_controll_message_action(self, msg): # TODO: classmethod
  27. try:
  28. print('json:', msg)
  29. res = json.loads(msg)
  30. action = res.get('action')
  31. print('action:', action)
  32. if action == 'start':
  33. return MSG_TYPE.START
  34. elif action == 'quit':
  35. return MSG_TYPE.QUIT
  36. return MSG_TYPE.UNKNOWN
  37. except(json.decoder.JSONDecodeError):
  38. print('json decode error...', msg)
  39. return MSG_TYPE.ERROR
  40. def run(self):
  41. print('game: running')
  42. print('waiting to start...')
  43. while self.game_state != GAME_STATE.QUIT:
  44. if self.game_state == GAME_STATE.LOBBY:
  45. self.lobby()
  46. else:
  47. self.game()
  48. def lobby(self):
  49. for client, msg, op in self.ssock.listen():
  50. if op == server_socket.SOCKET_OP.DATA_IN:
  51. action = self.get_controll_message_action(msg)
  52. if action == MSG_TYPE.START:
  53. self.game_state = GAME_STATE.PLAY
  54. break
  55. elif action == MSG_TYPE.QUIT:
  56. self.game_state = GAME_STATE.QUIT
  57. break
  58. else:
  59. self.process_connections(client, msg, op)
  60. def game(self):
  61. self.new_game()
  62. while self.turn <= self.cards_dealt:
  63. self.broadcast_turn()
  64. self.play_turn()
  65. self.game_state = GAME_STATE.LOBBY
  66. self.print_scoreboard()
  67. def play_turn(self):
  68. for client, msg, op in self.ssock.listen():
  69. if op != server_socket.SOCKET_OP.DATA_IN:
  70. print('Unexpected socket messages!')
  71. continue
  72. self.process_message(client, msg)
  73. def print_scoreboard(self):
  74. for i, p in enumerate(sorted(self.players.values(), key=lambda p: p.name)):
  75. print(i + 1, ':', p.name, '-', p.score)
  76. def process_connections(self, client, data_in_bytes, playerOperation):
  77. if playerOperation == server_socket.SOCKET_OP.NEW_CONNECTION:
  78. self.handle_new_connection(client)
  79. elif playerOperation == server_socket.SOCKET_OP.HANGUP:
  80. self.handle_disconnect(client)
  81. # elif playerOperation == server_socket.SOCKET_OP.DATA_IN:
  82. # return
  83. else:
  84. print('process_connections: unknown operation:', playerOperation)
  85. exit(1)
  86. def handle_new_connection(self, client):
  87. self.players[client] = Player(client, random.sample(string.ascii_uppercase, 10))
  88. def handle_disconnect(self, client):
  89. del self.players[client]
  90. def process_message(self, client, bmsg):
  91. msg_type, payload = self.parse_message(bmsg)
  92. if msg_type == MSG_TYPE.GIVE_CARD:
  93. try:
  94. current_card = int(payload)
  95. except:
  96. print('error parsing GIVE_CARD', payload)
  97. return
  98. self.get_card(client, current_card)
  99. else:
  100. print('unknown command')
  101. def parse_message(self, bmsg):
  102. try:
  103. msg = json.loads(str(bmsg, 'utf-8').strip())
  104. if msg.get('action') == 'give_card':
  105. return MSG_TYPE.GIVE_CARD, msg.get('card')
  106. return MSG_TYPE.ERROR, None
  107. except json.decoder.JSONDecodeError:
  108. print('json decode error...', bmsg)
  109. return MSG_TYPE.ERROR, None
  110. def new_game(self):
  111. self.board = board.Board()
  112. for player in self.players.values():
  113. player.set_hand(self.board.draw(self.cards_dealt))
  114. def get_card(self, client, card):
  115. if not self.players[client].set_card(card):
  116. send_json = json.dumps({'type': 'error', 'Not in your hand': str(card)})
  117. self.ssock.broadcast([client], send_json) # TODO: broadcast?
  118. return
  119. players_ready = [p for p in self.players.values() if p.card]
  120. if len(players_ready) != len(self.players):
  121. return
  122. self.place_all_cards()
  123. def place_all_cards(self):
  124. players_ready = sorted(self.players.values(), key=lambda p: p.card)
  125. for p in players_ready:
  126. ret, penalty_for_5_card = self.board.place_card(p.card)
  127. if ret == board.CANDIDATE.TOO_LOW:
  128. selection = p.select_row(self.board.rows)
  129. penalty = self.board.reset_row(selection, p.card)
  130. p.score = p.score + penalty
  131. # print(p.name, p.card, 'low: ', p.score)
  132. elif ret == board.CANDIDATE.PENALTY:
  133. p.score += penalty_for_5_card
  134. # print(p.name, p.card, 'penalty:', p.score)
  135. elif ret == board.CANDIDATE.PUT:
  136. # print(p.name, p.card, 'ok')
  137. pass
  138. else:
  139. print('place_cards: unknown operation:', ret)
  140. exit(1)
  141. # print(self.board.rows)
  142. for p in players_ready:
  143. p.hand.remove(p.card) # TODO: move to player.py
  144. p.card = None
  145. self.turn = self.turn + 1
  146. self.print_scoreboard()
  147. def broadcast_game_format(self):
  148. msg = {
  149. 'type': 'info',
  150. 'score_limit': self.score_limit,
  151. 'nturns': self.cards_dealt,
  152. 'nrows': len(self.board.rows),
  153. 'row_len': self.board.max_row_len,
  154. 'nplayers': len(self.players)}
  155. self.ssock.broadcast(self.players.keys(), json.dumps(msg))
  156. def broadcast_turn(self):
  157. board = {'type': 'query', 'action': 'give_card', 'board': self.board.rows, 'turn': self.turn}
  158. for p in self.players.values():
  159. msg = board.copy()
  160. msg['hand'] = p.hand
  161. self.ssock.broadcast([p.socket], json.dumps(msg))