def two_enemy_endgame(self, threshold, max_depth): game_state = self.game_state enemy_stacks = len(game_state[self.other]) for piece in game_state[self.player]: temp_game = game.Game(game_state) temp_game.boom((piece[1], piece[2]), self.player) if not temp_game.get_game_state()[self.player]: strategy, val = self.mp_mix(threshold, max_depth) return strategy if not temp_game.get_game_state()[self.other]: return None, (piece[1], piece[2]), "Boom", None # One stack if enemy_stacks == 1: enemy = game_state[self.other][0] enemy_xy = enemy[1], enemy[2] ally = self.closest_npiece(game_state, 2, self.player, enemy_xy) if ally is None: return self.make_stack(game_state) ally_xy = ally[1], ally[2] enemy_corner_xy = self.get_nearest_corner(ally_xy, enemy_xy) return self.go_there(2, ally, enemy_corner_xy) # Two seperate stacks else: return self.one_enemy_endgame(threshold, max_depth, two_enemy=True)
def __init__(self, colour): """ This method is called once at the beginning of the game to initialise your player. You should use this opportunity to set up your own internal representation of the game state, and any other information about the game state you would like to maintain for the duration of the game. The parameter colour will be a string representing the player your program will play as (White or Black). The value will be one of the strings "white" or "black" correspondingly. """ # TODO: Set up state representation. with open("MPM/initial_game_state.json") as file: data = json.load(file) self.game = game.Game(data) self.game_state = self.game.get_game_state() self.colour = colour self.agent = agent.Agent(self.game, self.game_state, colour) self.max_depth = 2 self.threshold = 0 # opening book change self.opening_book = opening_book.OpenBook(self.game, colour) self.home_tokens = 12 self.away_tokens = 12 self.past_states = [] self.turn = 0
def one_enemy_endgame(self, threshold, max_depth, two_enemy=False): game_state = self.game.get_game_state() # If enemy can draw or we can win for piece in game_state[self.player]: home_b = features.count_pieces(game_state[self.player]) temp_game = game.Game(game_state) temp_game.boom((piece[1], piece[2]), self.player) home_a = features.count_pieces( temp_game.get_game_state()[self.player]) if not temp_game.get_game_state()[self.player] or ( two_enemy and home_b - home_a >= 2): strategy, val = self.mp_mix(threshold, max_depth) return strategy if not temp_game.get_game_state()[self.other]: return None, (piece[1], piece[2]), "Boom", None enemy = game_state[self.other][0] enemy_xy = enemy[1], enemy[2] ally = self.closest_npiece(game_state, 1, self.player, enemy_xy) ally_xy = ally[1], ally[2] # Close enough to boom if abs(enemy_xy[1] - ally_xy[0]) <= 1 and abs(enemy_xy[2] - ally_xy[1]) <= 1: return None, ally_xy, "Boom", None return self.go_there(1, ally, enemy_xy)
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 suicide_move(self, game_, player, xy): curr_state = game_.get_game_state() temp_game = game.Game(curr_state) home_b, away_b = features.count_all(curr_state, player) # Us booming is the same as someone adj booming on their next turn temp_game.boom(xy, player) next_state = temp_game.get_game_state() home_a, away_a = features.count_all(next_state, player) if self.is_bad_boom(home_b, home_a, away_b, away_a): return True return False
def pieces_per_boom(game_state, player): other = game.other_player(player) damages = [] away_before = len(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 = len(temp_game_state[other]) damage = away_before - away_after damages.append(damage) if len(damages) == 0: return 0 return max(damages) * max(damages)
def available_states(self, game_state, player, get_all=False): available = [] all_rational_available = [] all_available = [] home_b, away_b = features.count_all(game_state, player) for piece in game_state[player]: xy = piece[1], piece[2] available_moves = tokens.available_moves(player) for move in available_moves: if move == "Boom": temp_game = game.Game(game_state) if not temp_game.has_surrounding(xy): continue temp_game.boom(xy, player) all_available.append([(None, xy, move, None), temp_game.get_game_state()]) home_a, away_a = features.count_all( temp_game.get_game_state(), player) # If suicide for nothing if away_b == away_a: # Don't continue all_rational_available.append([(None, xy, move, None), temp_game.get_game_state()]) if self.is_bad_boom(home_b, home_a, away_b, away_a): continue available.append([(None, xy, move, None), temp_game.get_game_state()]) else: # Not optimal to move in between unless you have really good strategies if piece[0] == 1: amounts = [1] elif piece[0] == 2: amounts = [1, 2] else: amount = min(piece[0], 8) # Move whole stack or leave one or move one amounts = [1, amount, amount - 1] for n in range(piece[0]): n = piece[0] - n for distance in range(piece[0]): distance = piece[0] - distance temp_game = game.Game(game_state) if temp_game.is_valid_move(xy, move, distance, player): temp_game.move_token(n, xy, move, distance, player) xy2 = game.dir_to_xy(xy, move, distance) all_available.append([ (n, xy, move, distance), temp_game.get_game_state() ]) # Moving into a trap if self.suicide_move(temp_game, player, xy2): continue all_rational_available.append([ (n, xy, move, distance), temp_game.get_game_state() ]) if self.player == player and n not in amounts: continue # We don't like a v pattern (inefficient move) if self.creates_v(temp_game, xy2): continue if temp_game.get_game_state()[ self.player] in self.past_states: continue available.append([(n, xy, move, distance), temp_game.get_game_state()]) if player != self.player or len(available) == 0 or get_all: if len(all_rational_available) == 0: return all_available else: return all_rational_available return available