class Client(threading.Thread): def __init__(self, group, find_move, host=DEFAULT_HOST, port=DEFAULT_PORT, game_start_callback=None, game_end_callback=None, move_callback=None): super().__init__() self.logger = logging.getLogger("Client ({})".format(group)) self.client = BasicClient(group, host, port) self.find_move = find_move self.game_start_callback = game_start_callback self.game_end_callback = game_end_callback self.move_callback = move_callback self.game_state = None def run(self): self.client.start() self.game_state = GameState(self.client.board) if self.game_start_callback: self.game_start_callback(self.game_state, self.client.player) self._game_loop() self.logger.info("Game Ended") if self.game_end_callback: self.game_end_callback(self.game_state) self.client.stop() def _game_loop(self): while True: message = self.client.read_message() if isinstance(message, EndPhaseTwoMessage): return elif isinstance(message, EndPhaseOneMessage): self.game_state.bomb_phase = True self.logger.info("Phase One Ended") elif isinstance(message, MoveRequestMessage): self.logger.info("Move Request from server ({}, {})".format( message.time_limit, message.depth_limit)) (player, pos, choice) = self.find_move(self.game_state, message.time_limit, message.depth_limit) self.logger.info("Answer: {}, {}".format(pos, choice)) move_message = MoveResponseMessage(pos, choice) self.client.send_message(move_message) elif isinstance(message, DisqualificationMessage): self.logger.info("Player {} Disqualified!".format( message.player)) self.game_state.disqualify_player(message.player) if message.player == self.client.player: self.logger.info( "Client was disqualified, shutting down...") return elif isinstance(message, MoveNotificationMessage): old_game_state = self.game_state self.game_state = self.game_state.execute_move( message.player, message.pos, message.choice) if self.move_callback: self.move_callback( old_game_state, (message.player, message.pos, message.choice), self.game_state)
class Server(threading.Thread): def __init__(self, board, time, depth, port=DEFAULT_PORT, group_to_player=None): super().__init__() self.logger = logging.getLogger("Server ({})".format(port)) self.game = GameState(board) self.server = BasicServer(board, port) self.time = time * 1000 self.depth = depth self.group_to_player = group_to_player self.times = dict() for player in self.game.players: self.times[player] = 0 def run(self): self.server.start() groups = [] for i in range(self.game.board.n_players): self.logger.info( "Waiting for {} more players to connect...".format( self.game.board.n_players - i)) groups.append(self.server.accept_client()) self.logger.info( "All players connected, distributing maps and player numbers.") if self.group_to_player: for g, p in self.group_to_player.items(): self.server.set_player_for_group(g, p) else: for i in range(self.game.board.n_players): self.server.set_player_for_group(groups[i], Field.PLAYER_ONE + i) self.logger.info("Starting Game") self._game_loop() self.server.stop() def _game_loop(self): while True: was_in_bomb_phase = self.game.bomb_phase next_moves = self.game.get_next_possible_moves() if len(next_moves) == 0: self._end_game() return if next_moves[0].bomb_phase != was_in_bomb_phase: self.server.broadcast_message(EndPhaseOneMessage()) (player, _, _) = next_moves[0].last_move self._let_player_move(player) if len(self.game.players) <= 1: self._end_game_disqualified() return def _let_player_move(self, player): try: self._inc_player_time(player) self._send_move_request(player) start_time = time.time() self._process_move_answer(player) move_time_in_ms = int((time.time() - start_time) * 1000) self.times[player] = self.times[player] - move_time_in_ms self.logger.info("Turn took {} ms".format(move_time_in_ms)) self._broadcast_last_move_notification() except DisqualifiedError as err: self._disqualify_player(player, err) def _send_move_request(self, player): self.logger.info( "Send move request to player {} ({} ms, depth {}).".format( player.value, self.times[player], self.depth)) move_request = MoveRequestMessage(self.times[player], self.depth) self.server.send_player_message(player, move_request) def _process_move_answer(self, player): move_response = \ self.server.read_player_message(player, MoveResponseMessage, self.times[player]/1000) self.logger.info("Player Move: ({}, {})".format( move_response.pos, move_response.choice)) self.game = self.game.execute_move(player, move_response.pos, move_response.choice) if not self.game: raise DisqualifiedError("Client send invalid move!", player) self.logger.info(self.game.board.board_string()) def _broadcast_last_move_notification(self): (player, pos, choice) = self.game.last_move move_notification = MoveNotificationMessage(pos, choice, player) self.server.broadcast_message(move_notification) def _inc_player_time(self, player): if self.times[player] < 0: self.times[player] = 0 self.times[player] = self.times[player] + self.time def _end_game_disqualified(self): if not self.game.bomb_phase: self.server.broadcast_message(EndPhaseOneMessage()) self.server.broadcast_message(EndPhaseTwoMessage()) self.logger.info("Everyone is disqualified, ending game...") def _end_game(self): self.server.broadcast_message(EndPhaseTwoMessage()) self.logger.info("No more moves, ending game...") def _disqualify_player(self, player, err): self.logger.info("Player {} Disqualified! {}".format(player, err)) self.game.disqualify_player(player) self.server.broadcast_message(DisqualificationMessage(player))