def __init__(self, max_num_players, randomize): # the number of players that must be in the game before it starts self.max_num_players = max_num_players self.randomize = randomize # number of players currently connected to this game self.num_active_players = 0 # mechanism to access all players connected to this game self.players = [] self.hex_board = HexBoard(randomize) self.state = GameState.PLAYER_SETUP self.cur_player = None # whose turn is it? # for visibility, define the fields which are going to be used only # in the context of the various state functions # used in SETTLEMENT_SETUP: self.select_settlement = None self.second_round = None # used in PLAYER_TURN self.finish_dice_roll = False self.state_methods = {GameState.PLAYER_SETUP: self.add_player_info, GameState.SETTLEMENT_SETUP: self.initial_setup, GameState.PLAYER_TURN: self.player_turn, GameState.ROLL_DICE: self.roll_dice}
def test_board(self): hex_board: HexBoard = HexBoard(3, HexBoard1.BLUE_CODE) hex_board.place_with_color((0, 0), HexBoard1.BLUE_CODE) hex_board.place_with_color((1, 0), HexBoard1.BLUE_CODE) hex_board.place_with_color((0, 2), HexBoard1.BLUE_CODE) hex_board.place_with_color((1, 2), HexBoard1.BLUE_CODE) hex_board.place_with_color((0, 1), HexBoard1.RED_CODE) hex_board.place_with_color((1, 1), HexBoard1.RED_CODE) hex_board.place_with_color((2, 1), HexBoard1.RED_CODE) hex_board.place_with_color((2, 2), HexBoard1.RED_CODE) hex_board.place_with_color((2, 0), HexBoard1.BLUE_CODE) print("hex_board.is_game_over: ", hex_board.is_game_over) hex_board.print_board_ui() self.assertTrue(True)
def test_hex_board(self): data_list = [1, 1, 1, 1, 2, 2, 2, 2, 2] combination_list = [] combination_set = set(generate_all_combinations(data_list)) print(combination_set.__len__()) idx = 1 for combination in combination_set: hexBoard: HexBoard = HexBoard(3, HexBoard1.BLUE_CODE) HexBoard1.place_with_color((0, 0), combination[0]) HexBoard1.place_with_color((0, 1), combination[1]) HexBoard1.place_with_color((0, 2), combination[2]) if HexBoard1.is_game_over: continue HexBoard1.place_with_color((1, 0), combination[3]) if HexBoard1.is_game_over: continue HexBoard1.place_with_color((1, 1), combination[4]) if HexBoard1.is_game_over: continue HexBoard1.place_with_color((1, 2), combination[5]) if HexBoard1.is_game_over: continue HexBoard1.place_with_color((2, 0), combination[6]) if HexBoard1.is_game_over: continue HexBoard1.place_with_color((2, 1), combination[7]) if HexBoard1.is_game_over: continue HexBoard1.place_with_color((2, 2), combination[8]) if HexBoard1.is_game_over: continue if not HexBoard1.is_game_over: HexBoard1.print_board_ui() raise Exception(hexBoard)
import numpy as np from hex_board import HexBoard from search import Search # sanity check that wins are detected for i in range(0, 2): winner = HexBoard.RED if i == 0 else HexBoard.BLUE loser = HexBoard.BLUE if i == 0 else HexBoard.RED board = HexBoard(3) board.place((1, 1), loser) board.place((2, 1), loser) board.place((1, 2), loser) board.place((2, 2), loser) board.place((0, 0), winner) board.place((1, 0), winner) board.place((2, 0), winner) board.place((0, 1), winner) board.place((0, 2), winner) assert (board.check_win(winner) == True) assert (board.check_win(loser) == False) board.print() endable_board = HexBoard(4) # sanity check that random play will at some point end the game while not endable_board.game_over: endable_board.place((np.random.randint(0, 4), np.random.randint(0, 4)), HexBoard.RED) assert (endable_board.game_over == True) assert (endable_board.check_win(HexBoard.RED) == True) assert (endable_board.check_win(HexBoard.BLUE) == False) print("Randomly filled board") endable_board.print()
def play_game(player1: Search, player2: Search, board_size=3, print_statements=True): """ :arg color1: The color of player 1. Either 'red' or 'blue'. Blue starts the game. :arg player1: :arg player2: :return: """ board = HexBoard(board_size) starting_color = HexBoard.BLUE player2.color = HexBoard.get_opposite_color(player1.color) current_player: Search = player1 if player1.color == starting_color else player2 round_counter = 1 if print_statements: print("Start: Random placing sample") print("Initial Game settings:") print("- board size: ", board_size) print("- starting color:", starting_color) print("Initializing Game ") board.print() print("Blue has the horizontal borders, red the vertical borders") while not board.game_over: if print_statements: board.print() # print("==============================================================\n") # print("Round", round_counter, ': ', ['Blue', 'Red'][current_player.color - 1], "'s turn") start_time = time.time() next_move = current_player.generate_move(board) time_diff_secs = time.time().__sub__(start_time) print(current_player.color, " generate_move completed. secs: ", time_diff_secs) board.place(next_move, current_player.color) current_player = player1 if player1.color == HexBoard.get_opposite_color( current_player.color) else player2 round_counter += 1 if print_statements: print(board.get_winner(), ' has won!') """ELO rating""" # if board.check_win(player1.color): # player1.rating, player2.rating = ts.rate_1vs1(player1.rating, player2.rating) # player 1 is winner # elif board.check_win(player2.color): # player1.rating, player2.rating = ts.rate_1vs1(player2.rating, player1.rating)[::-1] # player 2 is winner # else: # player1.rating, player2.rating = ts.rate_1vs1(player1.rating, player2.rating, drawn=True) # draw return board.get_winner()
# for blue_player1, red_player2 in combinations([player_random_3, player_dijkstra_3, player_dijkstra_4, player_mcts], 2): # match_players_list.append([blue_player1, red_player2]) match_players_list = [[player_mcts, player_random_3]] # win_record_list = [] win_dict = {} nu_rounds = 5 for nu in range(nu_rounds): for match_players in match_players_list: player1 = match_players[0] player2 = match_players[1] winner_color_name = play_game(player1, player2, board_size=3, print_statements=False) winner_serach_name = None if winner_color_name == HexBoard.obtain_color_name(None, player1.color): winner_serach_name = player1.method + " " + str(player1.search_depth) elif winner_color_name == HexBoard.obtain_color_name(None, player2.color): winner_serach_name = player2.method + " " + str(player2.search_depth) else: raise Exception(winner_serach_name) player1.color, player2.color = player2.color, player1.color player_random_3.rating_vs_time_list.append(player_random_3.rating) player_dijkstra_3.rating_vs_time_list.append(player_dijkstra_3.rating) player_dijkstra_4.rating_vs_time_list.append(player_dijkstra_4.rating) player_mcts.rating_vs_time_list.append(player_mcts.rating) print("nu: ", nu, winner_serach_name, "won")
class Game: """An individual game of Catan to be played be some number of users""" def __init__(self, max_num_players, randomize): # the number of players that must be in the game before it starts self.max_num_players = max_num_players self.randomize = randomize # number of players currently connected to this game self.num_active_players = 0 # mechanism to access all players connected to this game self.players = [] self.hex_board = HexBoard(randomize) self.state = GameState.PLAYER_SETUP self.cur_player = None # whose turn is it? # for visibility, define the fields which are going to be used only # in the context of the various state functions # used in SETTLEMENT_SETUP: self.select_settlement = None self.second_round = None # used in PLAYER_TURN self.finish_dice_roll = False self.state_methods = {GameState.PLAYER_SETUP: self.add_player_info, GameState.SETTLEMENT_SETUP: self.initial_setup, GameState.PLAYER_TURN: self.player_turn, GameState.ROLL_DICE: self.roll_dice} # handles incoming messages / actions from players def handle_network(self, channel, action_name, data): player = self.get_player(channel) if player is not None: # the player who sent this is actually in the game self.state_methods[self.state](player, action_name, data) # add a player into this game def add_player(self, player_channel): self.num_active_players += 1 # now actually add the player self.players.append(ServerPlayer(player_channel)) # following methods are called based on the game state # to add player username and color info # called when in the PLAYER_SETUP state def add_player_info(self, new_player, action_name, data): try: username = data['username'] color = data['color'] except IndexError: pass valid_username = self.validate_username(username) valid_color = self.validate_color(color) if valid_username and valid_color: # new player is ready to be added new_player.username = username new_player.color = color # give new player the game board setup new_player.send({'action': 'game_board', 'layout': self.hex_board.serialize_types()}) # when a player is added to the game, the should first inform the incoming player # of all players already connected. Then all already-connected players should # be informed of the incoming player existing_players = [{'username': player.username, 'color': player.color} for player in self.players if player is not new_player] new_player.send({'action': 'current_players', 'players': existing_players}) # tell other players about this new player for player in self.players: if player is not new_player: player.send({'action': 'new_player', 'username': username, 'color': color}) # tell the user whether their choices of username / color have already # been taken new_player.send({'action': 'check_user_color', 'accept_username': valid_username, 'accept_color': valid_color}) # this might be the last player to have their info accepted # check if it is time to go to the next state and actually start the game if self.game_ready(): self.state = GameState.SETTLEMENT_SETUP # following 2 fields will be used by SETTLEMENT_SETUP's state function self.select_settlement = True self.second_round = False self.cur_player = self.players[0] # tell the first player that they need to select a settlement self.cur_player.send({'action': 'select_settlement'}) # tell everyone else to wait self.broadcast_wait() # handles users' initial settlement and road setup # called when in the SETTLEMENT_SETUP state def initial_setup(self, player, action, data): if player is self.cur_player: if action == 'select_settlement' and self.select_settlement: # user is trying to select a first / second settlement try: settlement_index = data['settlement'] except KeyError: # user sent a faulty message, ignore return if self.hex_board.valid_settlement(settlement_index): # valid settlement selection, update record and notify players # per Catan rules give the player one of each resource # their selected node borders selected_node = self.hex_board.nodes[settlement_index] player.modify_resources(self.resources_around_node(selected_node)) print(player.resources) self.hex_board.settle(settlement_index, player) self.new_settlement(settlement_index, player) # change client state player.send({'action': 'select_road'}) self.select_settlement = False else: # user is apparently unable to select a correct settlement player.send({'action': 'invalid', 'message': 'settlement'}) elif action == 'select_road' and not self.select_settlement: # the user is trying to select a road try: road_index = data['road'] except KeyError: # user sent a faulty message, ignore return if self.hex_board.valid_road(road_index, player): # the player has managed, against all odds, to pick a road correctly self.hex_board.set_road(road_index, player) self.new_road(road_index, player) # if this was the last player in the list and we have already # gone through this process once, move to the next stage of the # game (i.e. actual turns) self.cur_player = self.get_next_player() self.select_settlement = True if player is self.players[-1]: if self.second_round: # CHANGE STATE -- PLAYER_TURN self.state = GameState.ROLL_DICE self.broadcast_roll_dice(self.cur_player.username) else: # go around again picking settlements / roads self.second_round = True self.cur_player.send({'action': 'select_settlement'}) else: self.broadcast_wait() self.cur_player.send({'action': 'select_settlement'}) else: player.send({'action': 'invalid', 'message': 'road'}) # GAME STATE # waiting for the current player to stop the dice from rolling def roll_dice(self, player, action, data): if player is self.cur_player: left = random.randint(0, 6) right = random.randint(0, 6) self.broadcast_dice_result(left, right) def player_turn(self, player, action, data): pass # checks if the game is ready to start, i.e. if the game is full and # all players have their username and color def game_ready(self): if self.is_full(): for player in self.players: if player.username is None or player.color is None: return False # someone hasn't set their user / color return True return False def is_full(self): return self.num_active_players == self.max_num_players # has somebody taken this username? def validate_username(self, username): for player in self.players: if player.username == username: return False return True # has somebody taken this color? def validate_color(self, color): for player in self.players: if player.color == color: return False return True # get player from channel def get_player(self, channel): for player in self.players: if player.channel == channel: return player return None # get the next player in the rotation from the current player # tries to get the next in line, if that fails the array has been stepped out # of, so go back to the beginning def get_next_player(self): try: return self.players[self.players.index(self.cur_player) + 1] except IndexError: return self.players[0] # sends the wait message to all players besides the current player def broadcast_wait(self): for player in self.players: if player is not self.cur_player: player.send({'action': 'wait', 'cur_player': self.cur_player.username}) # announce that the dice should begin rolling animation def broadcast_roll_dice(self, roller): for player in self.players: if player is self.cur_player: player.send({'action': 'roll_dice'}) else: player.send({'action': 'wait_dice', 'roller': roller}) def broadcast_dice_result(self, left, right): for player in self.players: player.send({'action': 'dice_result', 'left': left, 'right': right}) # sends the player's client the player's updated resources to be displayed on their screen def message_update_resources(self, player): player.send({'action': 'update_resources', 'resources': player.resources}) # takes a hextype as an enum and converts it to its proper string form def hextype_to_string(self, enum): conversions = {HexType.FOREST: 'wood', HexType.SHEEP: 'sheep', HexType.WHEAT: 'wheat', HexType.MOUNTAIN: 'ore', HexType.REDDISH_ORANGE: 'reddish-orange', HexType.CACTUS: None} return conversions[enum] # get the resources from the hexes adjacent to the the node and put them into a format # that can be processed by the Player class, i.e. {'resource-name': number of resource} def resources_around_node(self, node): new_resources = {} for hex in node.hexes: resource = self.hextype_to_string(hex.type) if resource: try: new_resources[resource] += 1 except KeyError: # resource not there yet; needs to be created new_resources[resource] = 1 return new_resources # update the clients on a new settlement def new_settlement(self, settlement, owner): for player in self.players: player.send({'action': 'new_settlement', 'settlement': settlement, 'color': owner.color}) # update the clients on a new road def new_road(self, road, owner): for player in self.players: player.send({'action': 'new_road', 'road': road, 'color': owner.color})
def test_hex_board_official(self): hex_board = HexBoard(3) # hex_board.place((0, 0), HexBoard1.RED) # hex_board.place((1, 1), HexBoard1.RED) hex_board.place((2, 2), HexBoard.RED) hex_board.place((0, 1), HexBoard.RED) hex_board.place((1, 0), HexBoard.RED) hex_board.place((0, 2), HexBoard.RED) hex_board.print() print("hex_board.check_win(HexBoardMixed.BLUE_CODE:", hex_board.check_win(HexBoard.BLUE)) print("hex_board.check_win(HexBoardMixed.RED_CODE)", hex_board.check_win(HexBoard.RED)) print("hex_board.is_game_over()", hex_board.is_game_over()) # print("hex_board.obtain_winner_name()", hex_board.obtain_winner_name()) self.assertTrue(True)