def test_get_legal_moves_empty(self): self.board_state = BoardState() self.board_state.north_board_score = 0 self.board_state.south_board_score = 0 self.board_state.north_board_state = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0 } self.board_state.south_board_state = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0 } legal_moves = get_legal_moves(self.board_state, 0) self.assertEquals(len(legal_moves), 0)
def make_move(is_first_move, is_second_move): global calls global board_side calls = 0 log.write("Making a move \n") log.write("=== Board State === \n") log.write(str(board_state) + "\n") log.write("=================== \n") possible_moves = get_legal_moves(board_state, board_side, is_second_move) log.write("=== Legal Moves ===\n") log.write(str(possible_moves)) log.write("===========\n") curr_highest_val = 0 best_move = possible_moves[0] pool = Pool(processes=7) res = [] for move in possible_moves: next_state = board_state.get_next_state(move, board_side) if board_state.do_we_play_again(move, board_side, is_first_move): res.append((pool.apply_async(min_max, (next_state, False, False, 1, board_side, True, float("-inf"), float("inf"))), move)) elif move != SWAP_MOVE: res.append((pool.apply_async(min_max, (next_state, False, is_first_move, 1, board_side, False, float("-inf"), float("inf"))), move)) else: res.append((pool.apply_async(min_max, (next_state, False, False, 1, not board_side, False, float("-inf"), float("inf"))), move)) for result in res: val = result[0].get() move = result[1] if val > curr_highest_val: curr_highest_val = val best_move = move choice = best_move if choice == -1: move = "SWAP\n" board_side = not board_side else: move = "MOVE;" + str(choice) + "\n" log.write(move) sys.stdout.write(move) sys.stdout.flush()
def get_min_value(board_state, board_side, depth, is_second_move): global calls calls += 1 curr_lowest_val = 0 possible_moves = get_legal_moves(board_state, board_side, is_second_move) if len(possible_moves) == 0: stones_opp_side = board_state.total_stones_on_side(not board_side) board_state_copy = board_state.copy() board_state_copy._increase_score_for_side(not board_side, stones_opp_side) if board_state_copy.get_score_for_side(board_side) > board_state_copy.get_score_for_side(not board_side): return float("-inf") elif board_state_copy.get_score_for_side(board_side) < board_state_copy.get_score_for_side(not board_side): return float("inf") else: return 0 for move in possible_moves: next_state = board_state.get_next_state(move, board_side) if depth > DEPTH_LIMIT: val = get_heuristic_val(next_state, not board_side) else: if board_state.do_we_play_again(move, board_side, is_first_move=False): val = get_min_value(next_state, board_side, depth + 1, is_second_move) elif move != SWAP_MOVE: val = get_max_value(next_state, not board_side, depth + 1) else: val = get_max_value(next_state, board_side, depth + 1) if val < curr_lowest_val: curr_lowest_val = val return curr_lowest_val
def test_get_legal_moves_start(self): self.board_state = BoardState() legal_moves = get_legal_moves(self.board_state, 0) moves_map = {} for move in legal_moves: # Should not have duplicates in legal moves list self.assertFalse(move in moves_map) moves_map[move] = True expected_moves_map = { 1: True, 2: True, 3: True, 4: True, 5: True, 6: True, 7: True } for expected_move in expected_moves_map.keys(): moves_map.pop(expected_move) # legal_moves should have the exact same items as expected_moves_map self.assertEquals(len(moves_map), 0)
def get_next_state(self, hole_choice, player_board_side): next_state = self.copy() if hole_choice == SWAP_MOVE: return next_state if hole_choice in get_legal_moves(self, player_board_side, is_second_move=False): side_state = next_state.get_board_state_for_side(player_board_side) remaining_seeds = side_state[hole_choice] # Empty the selected hole side_state[hole_choice] = 0 # Picked any hole but the last one before the scoring well if hole_choice < 7: next_hole = Hole(hole_choice + 1, player_board_side) else: # We chose the /final/ hole on the players side. # Next hole is past the scoring well, so we switch sides and # decrement the remaining seeds (1 goes to scoring well) next_hole = Hole(1, not player_board_side) remaining_seeds -= 1 next_state._increase_score_for_side(player_board_side) while remaining_seeds > 0: # Get state for the correct side next_hole_board_state = next_state.get_board_state_for_side( next_hole.board_side) # Increment the number of seeds in the next hole remaining_seeds -= 1 if remaining_seeds == 0 and next_hole.board_side == player_board_side: opp_next_hole_board_state = next_state.get_board_state_for_side( not next_hole.board_side) opp_hole_number = 7 - next_hole.number + 1 captured_stones = opp_next_hole_board_state[ opp_hole_number] next_state._increase_score_for_side( player_board_side, 1 + captured_stones) opp_next_hole_board_state[opp_hole_number] = 0 else: next_hole_board_state[next_hole.number] += 1 # Now calculate the next hole previous_hole = next_hole if remaining_seeds != 0: next_hole_number = previous_hole.number + 1 next_hole_side = previous_hole.board_side # Check if need to change sides if next_hole_number > 7: next_hole_number = 1 next_hole_side = not next_hole_side # If we left the players side if previous_hole.board_side == player_board_side: next_state._increase_score_for_side( player_board_side) remaining_seeds -= 1 next_hole = Hole(next_hole_number, next_hole_side) else: log.write("Action is not a legal move: " + str(hole_choice) + "\n") sys.stderr.write("CHECK LOGS! EXITING") sys.exit(0) return next_state