def best_uct(self, node, path): if node.unseen is None: node.create_children() if len(node.unseen) != 0: child_strategy = node.unseen.pop(0) child = self.Node(self, child_strategy, game.other_player(node.player), node) node.seen.append(child) return child, False max_uct = float("-inf") next_best_node = None for child in node.seen: if child in path: continue if child.uct >= max_uct: next_best_node = child max_uct = child.uct if next_best_node is None: return node, True return next_best_node, False
def pieces_threatened(game_state, player): other = game.other_player(player) home_b = count_pieces(game_state[player]) pieces = 0 for enemy in game_state[other]: xy = enemy[1], enemy[2] for move in tokens.available_moves(other): if move == "Boom": continue for dist in range(enemy[0]): dist = enemy[0] - dist xy2 = game.dir_to_xy(xy, move, dist) temp_game = game.Game(game_state) if tokens.out_of_board( xy2) or not temp_game.board.is_cell_empty(xy2): continue temp_game.move_token(1, xy, move, dist, other) temp_game.boom(xy2, other) home_a = count_pieces(temp_game.get_game_state()[player]) pieces += home_b - home_a return pieces
def rollout_policy(self, node): game_state = node.data player = node.player # Assume opponent is random if player != self.player: strategy = self.random_valid_move(game_state, player) temp_node = self.Node(self, strategy, game.other_player(player), None) # Stick to the plan else: available = self.available_states(game_state, player) strategy = random.choice(available) temp_node = self.Node(self, strategy, game.other_player(player), None) return temp_node
def min_dist_to_boom(game_state, player): from math import ceil if not (game_state[player] and game_state[game.other_player(player)]): return 0 minimum = float("inf") for piece1 in game_state[player]: x1, y1 = piece1[1], piece1[2] for piece2 in game_state[game.other_player(player)]: x2, y2 = piece2[1], piece2[2] dist = y2 - y1 + x2 - x1 minimum = min(minimum, ceil(dist / piece1[0])) return minimum
def eval_function(agent, curr_state, game_state, player): other = game.other_player(player) b_home_pieces = curr_state[player] b_away_pieces = curr_state[other] a_home_pieces = game_state[player] a_away_pieces = game_state[other] home_num = count_pieces(a_home_pieces) away_num = count_pieces(a_away_pieces) total_num = home_num + away_num if total_num == 0: return 0, 0 home_pieces_diff = count_pieces(b_home_pieces) - home_num away_pieces_diff = count_pieces(b_away_pieces) - away_num # Higher differences have more impact on the game home_pieces_diff = home_pieces_diff * home_pieces_diff away_pieces_diff = away_pieces_diff * away_pieces_diff home_stacks = count_stack_score(a_home_pieces) away_stacks = count_stack_score(a_away_pieces) home_min_dist = min_dist_to_boom(game_state, player) away_min_dist = min_dist_to_boom(game_state, other) home_threatening = pieces_threatened(game_state, player) away_threatning = pieces_threatened(game_state, other) max_damage = pieces_per_boom(game_state, player) max_losses = pieces_per_boom(game_state, other) home_board_score = agent.get_board_score(game_state, player) away_board_score = agent.get_board_score(game_state, other) weights = agent.weights home_features = np.array([ home_num - away_num, home_pieces_diff - away_pieces_diff, home_stacks, home_min_dist, max_damage, home_threatening, home_board_score ]) away_features = np.array([ away_num - home_num, away_pieces_diff - home_pieces_diff, away_stacks, away_min_dist, max_losses, away_threatning, away_board_score ]) home_final = np.dot(home_features, weights) away_final = np.dot(away_features, weights) return home_final, away_final
def action(self): """ This method is called at the beginning of each of your turns to request a choice of action from your program. Based on the current state of the game, your player should select and return an allowed action to play on this turn. The action must be represented based on the spec's instructions for representing actions. """ # TODO: Decide what action to take, and return it self.past_states.append(self.game_state[self.colour]) self.home_tokens = sum([x[0] for x in self.game_state[self.colour]]) self.away_tokens = sum( [x[0] for x in self.game_state[game.other_player(self.colour)]]) simulations = 14 * len(self.game_state[self.colour]) search_depth = 3 action = None if self.opening_book.check_early_game(): action = self.opening_book.next_move() if action: return action if self.away_tokens == 1 and self.home_tokens >= 1: strategy = self.agent.one_enemy_endgame(self.game_state, simulations, search_depth, 1) elif self.away_tokens == 2 and self.home_tokens >= 2: strategy = self.agent.two_enemy_endgame(self.game_state, simulations, search_depth, 1) elif self.away_tokens <= self.trading_prop and self.away_tokens < self.home_tokens: strategy = self.agent.trade_tokens(self.game_state, simulations, search_depth, 1) else: strategy = self.agent.monte_carlo(self.game_state, simulations, search_depth) n, xy, move, distance = strategy if move == "Boom": return "BOOM", xy else: x_a, y_a = xy x_b, y_b = game.dir_to_xy(xy, move, distance) return "MOVE", n, (x_a, y_a), (x_b, y_b)
def end(self, limit): game_state = self.game.get_game_state() self.agent.update_weights(game_state, limit) with open("genetic_programming/score.json") as file: data = json.load(file) if game_state[self.colour]: if not game_state[game.other_player(self.colour)]: data[self.colour] += 1 else: data["draw"] += 1 elif game_state[game.other_player(self.colour)]: if not game_state[self.colour]: data[game.other_player(self.colour)] += 1 else: data["draw"] += 1 else: data["draw"] += 1 with open("genetic_programming/score.json", 'w') as file: json.dump(data, file)
def __init__(self, game_, colour): self.player = colour self.other = game.other_player(colour) self.early_game_turn = 0 self.game = game_ if colour == "black": self.book = black_opening_book() if colour == "white": self.book = white_opening_book() self.boom_book = get_boom_book()
def __init__(self, game_, player, past_states, trade_prop): self.game = game_ self.player = player self.other = game.other_player(player) self.trade_prop = trade_prop self.turn = 0 self.past_states = past_states self.away_recently_moved_to = None self.away_recently_moved_from = None self.root = None self.weights = np.array( [380.17, -361.62, 810.72, -333.62, 356.67, -294.56, -137.97])
def is_bad_boom(self, game_state_b, game_state_a, player): diff_b = self.value_diff(game_state_b, player) diff_a = self.value_diff(game_state_a, player) home_b = features.count_pieces(game_state_b[player]) home_a = features.count_pieces(game_state_a[player]) away_b = features.count_pieces(game_state_a[game.other_player(player)]) if home_a == 0: return True # If less or equal pieces and the difference between pieces increase if home_b < away_b and diff_b >= diff_a: return True # If more pieces, don't accept a boom that will reduce our lead if home_b >= away_b and diff_b > diff_a: return True return False
def value_diff(game_state, player): home_val = 0 away_val = 0 for piece in game_state[player]: if piece[0] == 1: home_val += 1 else: home_val += piece[0] + 1 for piece in game_state[game.other_player(player)]: if piece[0] == 1: away_val += 1 else: away_val += piece[0] + 1 return home_val - away_val
def pieces_per_boom(game_state, player): other = game.other_player(player) damages = [] away_before = count_pieces(game_state[other]) for piece in game_state[player]: temp_game = game.Game(game_state) xy = (piece[1], piece[2]) temp_game.boom(xy, player) temp_game_state = temp_game.get_game_state() away_after = count_pieces(temp_game_state[other]) damage = away_before - away_after damages.append(damage) if len(damages) == 0: return 0 return max(damages) * max(damages)
def count_all(game_state, player): return count_pieces(game_state[player]), count_pieces( game_state[game.other_player(player)])