def test_get_opcode_count(self): self.assertIsNone(tracer.get_opcode_count()) with tracer.limited_opcodes(100): self.assertTrue(0 < tracer.get_opcode_count() < 100) self.assertIsNone(tracer.get_opcode_count())
def get_next_move(board, token): board_columns_used = get_board_columns_used(board) available_moves = game.available_moves(board) preferred_locations = [3, 2, 4, 1, 5, 0, 6] preferred_locations = [x for x in preferred_locations if x in available_moves] priority_locations = get_columns_with_space(board, token, preferred_locations) opcode_limit = get_opcode_limit() losing_locations = set() skip_moves = set() # if state is None: # state = {'opening_trap': False} moves_played = get_moves_played(board) other_token = 'X' if token == 'O' else 'O' for move in available_moves: board[move][board_columns_used[move]] = token if check_winner(board, move, board_columns_used[move]): print('MOVE: winning move') return move board[move][board_columns_used[move]] = '.' for move in available_moves: board[move][board_columns_used[move]] = other_token if check_winner(board, move, board_columns_used[move]): print('MOVE: blocking enemy win') return move board[move][board_columns_used[move]] = '.' for move in available_moves: if board_columns_used[move] > 4: continue board[move][board_columns_used[move]] = token board[move][board_columns_used[move] + 1] = other_token if check_winner(board, move, board_columns_used[move] + 1): losing_locations.add(move) board[move][board_columns_used[move]] = '.' board[move][board_columns_used[move] + 1] = '.' # Opening book if moves_played == 1: if board[3][0] == other_token: losing_locations.add(3) if moves_played == 2: if board[3][1] == other_token: # state['opening_trap'] = True return 2 if board[2][0] == other_token: return 2 if board[4][0] == other_token : return 4 if moves_played == 4: if board[3][1] == other_token and board[1][0] == '.' and board[4][0] == '.': return 4 # Take the move if you see a open-ended 3 way opportunity for move in available_moves: if move in losing_locations: continue if move_makes_3_horizontal_with_spaces(board, move, board_columns_used[move], token): print('MOVE: 3-way opportunity') return move # Block 2 adjacent tokens for the enemy for move in available_moves: if move_makes_3_horizontal_with_spaces(board, move, board_columns_used[move], other_token): print('MOVE: block 3-way opportunity') return move for move in available_moves: if move in losing_locations or board_columns_used[move] > 4: continue board[move][board_columns_used[move]] = token board[move][board_columns_used[move] + 1] = token if check_winner(board, move, board_columns_used[move] + 1, ignore_vertical=True): skip_moves.add(move) board[move][board_columns_used[move]] = '.' board[move][board_columns_used[move] + 1] = '.' print(get_opcode_count()) # Look for forced wins for move in skip_moves: if move in losing_locations or board_columns_used[move] > 2: continue board[move][board_columns_used[move]] = token board[move][board_columns_used[move] + 1] = other_token board[move][board_columns_used[move] + 2] = token if check_winner(board, move, board_columns_used[move] + 2): print('MOVE: Force WIN') return move board[move][board_columns_used[move] + 2] = '.' board[move][board_columns_used[move] + 1] = '.' board[move][board_columns_used[move]] = '.' # # Look for a sure win: # for move in available_moves: # print(f'sure {move}') # if move in losing_locations or board_columns_used[move] > 2: # continue # copy_board = [x[:] for x in board] # copy_board_columns_used = board_columns_used[:] # copy_board[move][copy_board_columns_used[move]] = token # # copy_board[move][copy_board_columns_used[move] + 1] = token # # # if not check_winner(copy_board, move, board_columns_used[move] + 1): # # continue # # # copy_board[move][copy_board_columns_used[move] + 1] = '.' # copy_board_columns_used[move] += 1 # # result = results_in_a_winner(copy_board, copy_board_columns_used, token, other_token) # print(f'sure result: {result}') # # if result == token: # print('MOVE: Sure WIN') # return move # elif result == other_token: # losing_locations.add(move) # Look for opening opportunities for move in preferred_locations: move_score = {} if move in skip_moves or move in losing_locations or board_columns_used[move] == 0: continue score = move_opens_opportunities(board, move, board_columns_used[move], token) if score > 0: move_score[move] = score if move_score: sorted_score = sorted(move_score.items(), key=itemgetter(1)) print('MOVE: making opportunities') return sorted_score[0][0] # Look for blocking opening opportunities for move in available_moves: move_score = {} if move in losing_locations: continue score = move_opens_opportunities(board, move, board_columns_used[move], other_token) if score > 0: move_score[move] = score if move_score: sorted_score = sorted(move_score.items(), key=itemgetter(1)) print('MOVE: blocking enemy opportunities') return sorted_score[0][0] sorted_friendly_neighbours_score = None friendly_neighbours_score = {} for move in preferred_locations: if move in skip_moves or move in losing_locations or board_columns_used[move] == 0 or board_columns_used[move] == 0: continue friendly_neighbours = get_friendly_neighbours(board, move, board_columns_used[move], token) if friendly_neighbours > 1: friendly_neighbours_score[move] = friendly_neighbours if friendly_neighbours_score: sorted_friendly_neighbours_score = sorted(friendly_neighbours_score.items(), key=itemgetter(1)) if sorted_friendly_neighbours_score[0][1] >= 3: print('MOVE: good friendlies') return sorted_friendly_neighbours_score[0][0] for move in preferred_locations: if move in skip_moves or move in losing_locations or board_columns_used[move] == 0 or board_columns_used[move] > 3: continue if not can_make_4_horizontal(board, move, board_columns_used[move], token): continue if move > 0: if board[move - 1][board_columns_used[move]] == token: print('MOVE: pair left') return move if move < 6: if board[move + 1][board_columns_used[move]] == token: print('MOVE: pair right') return move if sorted_friendly_neighbours_score: print('MOVE: weak neighbours') return sorted_friendly_neighbours_score[0][0] print(get_opcode_count()) for move in priority_locations: if move not in available_moves or move in losing_locations or move in skip_moves: continue return move for move in preferred_locations: if move not in available_moves or move in losing_locations or move in skip_moves: continue return move for move in priority_locations: if move not in available_moves or move in losing_locations: continue return move for move in preferred_locations: if move not in available_moves or move in losing_locations: continue return move return random.choice(available_moves)
def get_next_move(board, token): board_columns_used = get_board_columns_used(board) available_moves = game.available_moves(board) preferred_locations = [3, 2, 4, 1, 5, 0, 6] preferred_locations = [ x for x in preferred_locations if x in available_moves ] priority_locations = get_columns_with_space(board, token, preferred_locations) opcode_limit = get_opcode_limit() losing_locations = set() # if state is None: # state = {'opening_trap': False} moves_played = get_moves_played(board) other_token = 'X' if token == 'O' else 'O' for move in available_moves: board[move][board_columns_used[move]] = token if check_winner(board, move, board_columns_used[move]): return move board[move][board_columns_used[move]] = '.' for move in available_moves: board[move][board_columns_used[move]] = other_token if check_winner(board, move, board_columns_used[move]): return move board[move][board_columns_used[move]] = '.' for move in available_moves: if board_columns_used[move] > 4: continue board[move][board_columns_used[move]] = token board[move][board_columns_used[move] + 1] = other_token if check_winner(board, move, board_columns_used[move] + 1): losing_locations.add(move) board[move][board_columns_used[move]] = '.' board[move][board_columns_used[move] + 1] = '.' # Opening book if moves_played == 1: if board[3][0] == other_token: losing_locations.add(3) if moves_played == 2: if board[3][1] == other_token: # state['opening_trap'] = True return 2 if board[2][0] == other_token: return 2 if board[4][0] == other_token: return 4 if moves_played == 4: if board[3][1] == other_token and board[1][0] == '.' and board[4][ 0] == '.': return 4 skip_moves = set() for move in available_moves: if board_columns_used[move] > 4: continue board[move][board_columns_used[move]] = token board[move][board_columns_used[move] + 1] = token if check_winner(board, move, board_columns_used[move] + 1, ignore_vertical=True): skip_moves.add(move) board[move][board_columns_used[move]] = '.' board[move][board_columns_used[move] + 1] = '.' print(get_opcode_count()) for move in preferred_locations: if move in skip_moves or move in losing_locations or board_columns_used[ move] == 0 or board_columns_used[move] > 3: continue if move > 0: if board[move - 1][board_columns_used[move]] == token: return move if move < 6: if board[move + 1][board_columns_used[move]] == token: return move print(get_opcode_count()) for move in priority_locations: if move not in available_moves or move in losing_locations or move in skip_moves: continue return move for move in preferred_locations: if move not in available_moves or move in losing_locations or move in skip_moves: continue return move for move in priority_locations: if move not in available_moves or move in losing_locations: continue return move for move in preferred_locations: if move not in available_moves or move in losing_locations: continue return move return random.choice(available_moves)
def get_next_move(board, token): board_columns_used = get_board_columns_used(board) available_moves = game.available_moves(board) preferred_locations = [3, 2, 4, 1, 5, 0, 6] preferred_locations = [ x for x in preferred_locations if x in available_moves ] priority_locations = get_columns_with_space(board, token, preferred_locations) opcode_limit = get_opcode_limit() losing_locations = set() skip_moves = set() # if state is None: # state = {'opening_trap': False} moves_played = get_moves_played(board) other_token = 'X' if token == 'O' else 'O' for move in available_moves: board[move][board_columns_used[move]] = token if check_winner(board, move, board_columns_used[move]): return move board[move][board_columns_used[move]] = '.' for move in available_moves: board[move][board_columns_used[move]] = other_token if check_winner(board, move, board_columns_used[move]): return move board[move][board_columns_used[move]] = '.' for move in available_moves: if board_columns_used[move] > 4: continue board[move][board_columns_used[move]] = token board[move][board_columns_used[move] + 1] = other_token if check_winner(board, move, board_columns_used[move] + 1): losing_locations.add(move) board[move][board_columns_used[move]] = '.' board[move][board_columns_used[move] + 1] = '.' # Opening book if moves_played == 1: if board[3][0] == other_token: losing_locations.add(3) if moves_played == 2: if board[3][1] == other_token: # state['opening_trap'] = True return 2 if board[2][0] == other_token: return 2 if board[4][0] == other_token: return 4 if moves_played == 4: if board[3][1] == other_token and board[1][0] == '.' and board[4][ 0] == '.': return 4 # Take the move if you see a open-ended 3 way opportunity for move in available_moves: if move_makes_3_horizontal_with_spaces(board, move, board_columns_used[move], token): return move # Block 2 adjacent tokens for the enemy for move in available_moves: if move_makes_3_horizontal_with_spaces(board, move, board_columns_used[move], other_token): return move for move in available_moves: if board_columns_used[move] > 4: continue board[move][board_columns_used[move]] = token board[move][board_columns_used[move] + 1] = token if check_winner(board, move, board_columns_used[move] + 1, ignore_vertical=True): skip_moves.add(move) board[move][board_columns_used[move]] = '.' board[move][board_columns_used[move] + 1] = '.' print(get_opcode_count()) for move in preferred_locations: if move in skip_moves or move in losing_locations or board_columns_used[ move] == 0 or board_columns_used[move] > 3: continue if not can_make_4_horizontal(board, move, board_columns_used[move], token): continue if move > 0: if board[move - 1][board_columns_used[move]] == token: return move if move < 6: if board[move + 1][board_columns_used[move]] == token: return move for move in preferred_locations: move_score = {} if move in skip_moves or move in losing_locations or board_columns_used[ move] == 0 or board_columns_used[move]: continue friendly_neighbours = get_friendly_neighbours(board, move, board_columns_used[move], token) if friendly_neighbours > 1: move_score[move] = friendly_neighbours if move_score: sorted_score = sorted(move_score.items(), key=itemgetter(1)) return sorted_score[0][0] print(get_opcode_count()) for move in priority_locations: if move not in available_moves or move in losing_locations or move in skip_moves: continue return move for move in preferred_locations: if move not in available_moves or move in losing_locations or move in skip_moves: continue return move for move in priority_locations: if move not in available_moves or move in losing_locations: continue return move for move in preferred_locations: if move not in available_moves or move in losing_locations: continue return move return random.choice(available_moves)
def get_next_move(board, token): test_board = test_make_board_from_string() print(f'Before check_winner:{get_opcode_count()}') game.check_winner(test_board) print(f'After check_winner:{get_opcode_count()}') board_columns_used = get_board_columns_used(board) print(f'Before available moves:{get_opcode_count()}') all_available_moves = game.available_moves(board) print(f'After available moves:{get_opcode_count()}') preferred_locations = [3, 2, 4, 1, 5, 0, 6] print(f'Before preferred locations:{get_opcode_count()}') priority_locations = get_columns_with_space(board, token, preferred_locations) print(f'After preferred locations:{get_opcode_count()}') losing_locations = set() # if state is None: # state = {'opening_trap': False} print(f'Before board walk: {get_opcode_count()}') board[3][board_columns_used[3]] = token board[3][board_columns_used[3]] = '.' print(f'After board walk: {get_opcode_count()}') new_board = game.new_board() new_board[0][0] = 'X' new_board[1][1] = 'X' new_board[2][2] = 'X' new_board[3][3] = 'X' print(f'Before game.check_winner:{get_opcode_count()}') game.check_winner(new_board) print(f'After game.check_winner:{get_opcode_count()}') print(f'Before check_winner:{get_opcode_count()}') check_winner(board, 3, 3) print(f'After check_winner:{get_opcode_count()}') rO = re.compile(r'OOOO|O.{6}O.{6}O.{6}O|O.{7}O.{7}O.{7}O|O.{8}O.{8}O.{8}O') rX = re.compile(r'XXXX|X.{6}X.{6}X.{6}X|X.{7}X.{7}X.{7}X|X.{8}X.{8}X.{8}X') board_string = make_string_from_board(board) print(f'Before check_winner_regex:{get_opcode_count()}') board_string = board_string[:2 * 7 + 2] + 'X' + board_string[2 * 7 + 2:] check_winner_regex(board_string, 'X', r=rX) print(f'After check_winner_regex:{get_opcode_count()}') moves_played = get_moves_played(board) # best_value = float('-inf') # best_move = random.choice(available_moves) other_token = 'X' if token == 'O' else 'O' for move in all_available_moves: board[move][board_columns_used[move]] = token if check_winner(board, move, board_columns_used[move]): return move board[move][board_columns_used[move]] = '.' print(get_opcode_count()) for move in all_available_moves: board[move][board_columns_used[move]] = other_token if check_winner(board, move, board_columns_used[move]): return move board[move][board_columns_used[move]] = '.' print(get_opcode_count()) available_moves = set(all_available_moves) for move in all_available_moves: if board_columns_used[move] > 4: continue board[move][board_columns_used[move]] = token board[move][board_columns_used[move] + 1] = other_token if check_winner(board, move, board_columns_used[move] + 1): losing_locations.add(move) board[move][board_columns_used[move]] = '.' board[move][board_columns_used[move] + 1] = '.' print(get_opcode_count()) skip_moves = set() for move in all_available_moves: if board_columns_used[move] > 4: continue board[move][board_columns_used[move]] = token board[move][board_columns_used[move] + 1] = token if check_winner(board, move, board_columns_used[move] + 1, ignore_vertical=True): skip_moves.add(move) board[move][board_columns_used[move]] = '.' board[move][board_columns_used[move] + 1] = '.' # for move in all_available_moves: # board[move][board_columns_used[move]] = token # if move_makes_opportunity(board, move, board_columns_used[move], token): # return move print(get_opcode_count()) if moves_played == 1: # Don't go on top of the previous player losing_locations.add(find_enemy_location(board, other_token)) if moves_played == 2: if board[3][1] == other_token: return 2 if moves_played == 4: if board[3][1] == other_token and board[1][0] == '.' and board[4][0] == '.': return 4 priority_locations = [x for x in priority_locations if x not in skip_moves] for move in priority_locations: if move in losing_locations: continue return move for move in preferred_locations: if move in losing_locations: continue return move return random.choice(all_available_moves)
def get_next_move(board, token, state): board_columns_used = get_board_columns_used(board) available_moves = game.available_moves(board) preferred_locations = [3, 2, 4, 1, 5, 0, 6] priority_locations = get_columns_with_space(board, token, preferred_locations) losing_locations = set() if state is None: state = {'opening_trap': False} moves_played = get_moves_played(board) other_token = 'X' if token == 'O' else 'O' for move in available_moves: board[move][board_columns_used[move]] = token if check_winner(board, move, board_columns_used[move]): return move, state board[move][board_columns_used[move]] = '.' for move in available_moves: board[move][board_columns_used[move]] = other_token if check_winner(board, move, board_columns_used[move]): return move, state board[move][board_columns_used[move]] = '.' for move in available_moves: if board_columns_used[move] > 4: continue board[move][board_columns_used[move]] = token board[move][board_columns_used[move] + 1] = other_token if check_winner(board, move, board_columns_used[move] + 1): losing_locations.add(move) board[move][board_columns_used[move]] = '.' board[move][board_columns_used[move] + 1] = '.' skip_moves = set() for move in available_moves: if board_columns_used[move] > 4: continue board[move][board_columns_used[move]] = token board[move][board_columns_used[move] + 1] = token if check_winner(board, move, board_columns_used[move] + 1, ignore_vertical=True): skip_moves.add(move) board[move][board_columns_used[move]] = '.' board[move][board_columns_used[move] + 1] = '.' print(get_opcode_count()) if moves_played == 1: # Don't go on top of the previous player losing_locations.add(find_enemy_location(board, other_token)) if moves_played == 2: if board[3][1] == other_token: state['opening_trap'] = True return 2, state if moves_played == 4: if state['opening_trap']: if board[1][0] == '.' and board[4][0] == '.': return 4, state for move in priority_locations: if move not in available_moves or move in losing_locations or move in skip_moves: continue return move, state for move in preferred_locations: if move not in available_moves or move in losing_locations or move in skip_moves: continue return move, state for move in priority_locations: if move not in available_moves or move in losing_locations: continue return move, state for move in preferred_locations: if move not in available_moves or move in losing_locations: continue return move, state return random.choice(available_moves), state