def run_tests(): # Test board evaluation function. game = Latrunculi(8) minimax = Minimax(game) state = game.start_state() state.board[0][:2] = -2 # Simulate black losing 2 pieces. eval_w = minimax.evaluate_board(state, 1) state.player = not state.player # Simulate black having the turn. eval_b = minimax.evaluate_board(state, 1) assertion.assert_equal(4, eval_w, "latrunculi evaluate board positive") assertion.assert_equal(-14, eval_b, "latrunculi evaluate board negative") # ================================= game = Connect_Four(7) minimax = Minimax_CF(game) state = game.start_state() state.board[3:6, 1] = -1 state.board[4:6, 2] = 1 eval_w = minimax.evaluate_board(state, 0) state.player = not state.player # Simulate black having the turn. eval_b = minimax.evaluate_board(state, 0) assertion.assert_equal(3, eval_w, "connect four evaluate board positive") assertion.assert_equal(-3, eval_b, "connect four evaluate board negative")
def run_tests(): # Test Action ID. action1 = Action((1, 2), (3, 4)) action2 = Action((0, 0), (3, 4)) assertion.assert_equal(1234, action1.numeric(), "action numeric id 1234") assertion.assert_equal(34, action2.numeric(), "action numeric id 34") # ================================= game = Latrunculi(8) state = game.start_state() dictionary = dict() dictionary[state.stringify()] = "wow" assertion.assert_equal("wow", dictionary[state.stringify()], "state hashing") # ================================= # Test self-play performance evaluation. game = Connect_Four(6) as_white = evaluate_against_ai(game, get_ai_algorithm("Random", game), get_ai_algorithm("Random", game), True, 5, Config, None) as_black = evaluate_against_ai(game, get_ai_algorithm("Random", game), get_ai_algorithm("Random", game), False, 5, Config, None) print(as_white) print(as_black)
def run_tests(): # Test terminal state cases. # Test white wins. game = Othello(6) state = game.start_state() state.board[:4][:] = 1 state.board[4:][:] = -1 game_over = game.terminal_test(state) utility_w = game.utility(state, True) utility_b = game.utility(state, False) assertion.assert_true(game_over, "Terminal test - white wins") assertion.assert_equal(1, utility_w, "Utility - white wins") assertion.assert_equal(-1, utility_b, "Utility - black loses") # ================================= # Test black wins. state = game.start_state() state.board[:2][:] = 1 state.board[2:][:] = -1 game_over = game.terminal_test(state) utility_w = game.utility(state, True) utility_b = game.utility(state, False) assertion.assert_true(game_over, "Terminal test - black wins") assertion.assert_equal(1, utility_b, "Utility - black wins") assertion.assert_equal(-1, utility_w, "Utility - white loses") # ================================= # Test white wins by eliminating all black pieces. state = game.start_state() state.board[2, 2:4] = 1 state.board[3, 2:4] = 1 game_over = game.terminal_test(state) utility_w = game.utility(state, True) utility_b = game.utility(state, False) assertion.assert_true(game_over, "Terminal test2 - black wins") assertion.assert_equal(1, utility_w, "Utility2 - white wins") assertion.assert_equal(-1, utility_b, "Utility2 - black loses") # ================================= # Test tie. state = game.start_state() state.board[:3][:] = 1 state.board[3:][:] = -1 game_over = game.terminal_test(state) utility_w = game.utility(state, True) utility_b = game.utility(state, False) assertion.assert_true(game_over, "Terminal test - tie") assertion.assert_equal(0, utility_w, "Utility - black draws") assertion.assert_equal(0, utility_b, "Utility - white draws") # ================================= # Test pass move. state = game.start_state() state.board[3, 2:4] = 0 actions_w = game.actions(state) result = game.result(state, actions_w[0]) actions_b = game.actions(result) result = game.result(result, actions_b[0]) game_over = game.terminal_test(state) assertion.assert_equal([Action((2, 1), None)], actions_w, "Actions - one move") assertion.assert_equal([None], actions_b, "Actions - no moves black") assertion.assert_equal([None], game.actions(result), "Actions - no moves white") assertion.assert_true(result.player, "Actions - pass switches turn")
def run_tests(): # Test initial board setup. # Test correct board size. test_size = 8 game = Latrunculi(test_size) state = game.start_state() assertion.assert_equal(test_size, state.board.shape[1], "correct board width") assertion.assert_equal(test_size, state.board.shape[0], "correct board height") # ================================= # "Chess" distribution. # Test number of white and black pieces are equal, and is the correct amount. num_white = (state.board == 1).sum() num_black = (state.board == -1).sum() assertion.assert_equal(16, num_black, "number of black pieces chess formation") assertion.assert_equal(16, num_white, "number of white pieces chess formation") # ================================= # Test piece list is correct. pieces_board = [] it = np.nditer(state.board, flags=["multi_index"]) while not it.finished: y, x = it.multi_index if it[0] == 1 or it[0] == -1: pieces_board.append((y, x)) it.iternext() assertion.assert_all_equal(pieces_board, state.pieces, "correct pieces in piece list") # Random distribution. # Test number of white and black pieces are equal, and is the correct amount. game = Latrunculi(8, 432) state = game.start_state() num_white = (state.board == 1).sum() num_black = (state.board == -1).sum() assertion.assert_equal(16, num_black, "number of black pieces random") assertion.assert_equal(16, num_white, "number of white pieces random") # ================================= # Test initial player turn is white. assertion.assert_true(game.player(state), "initial player turn") # ================================= # Test terminal state methods. # Test terminal_test. game = Latrunculi(8) state = game.start_state() state.board[-3:][:] = 0 # Set white's pieces, except 1, to empty squares. state.board[-1][0] = 1 assertion.assert_true(game.terminal_test(state), "terminal state true") # ================================= # Test utility function. assertion.assert_equal(-1, game.utility(state, True), "utility white") assertion.assert_equal(1, game.utility(state, False), "utility black") # ================================= # Test available actions for "Chess" formation. game = Latrunculi(5) state = game.start_state() legal_moves = [ Action((3, 0), (2, 0)), Action((3, 1), (2, 1)), Action((3, 2), (2, 2)), Action((3, 3), (2, 3)), Action((3, 4), (2, 4)), Action((4, 0), (2, 0)), Action((4, 1), (2, 1)), Action((4, 2), (2, 2)), Action((4, 3), (2, 3)), Action((4, 4), (2, 4)) ] assertion.assert_all_equal(legal_moves, game.actions(state), "legal moves white") # ================================= # Test available actions for "random" board. game = Latrunculi(6, 5) state = game.start_state() state.player = not state.player legal_moves = [ Action((0, 1), (1, 1)), Action((0, 2), (1, 2)), Action((1, 0), (2, 0)), Action((1, 0), (1, 1)), Action((1, 4), (2, 4)), Action((1, 4), (1, 3)), Action((1, 4), (0, 4)), Action((1, 5), (2, 5)), Action((1, 5), (1, 3)), Action((2, 1), (1, 1)), Action((2, 1), (2, 0)), Action((2, 1), (2, 2)), Action((5, 0), (4, 0)), Action((5, 2), (4, 2)), Action((5, 2), (5, 3)), Action((5, 4), (4, 4)), Action((5, 4), (5, 3)), Action((5, 4), (5, 5)) ] assertion.assert_all_equal(legal_moves, game.actions(state), "legal random moves white") # ================================= # Test result of action. # Test simple move. game = Latrunculi(5) state = game.start_state() result = game.result(state, Action((3, 0), (2, 0))) old_piece = state.board[3][0] old_vacant = state.board[2][0] new_vacant = result.board[3][0] new_piece = result.board[2][0] assertion.assert_true(old_piece == new_piece, "regular move piece moved") assertion.assert_true(old_vacant == new_vacant, "regular move piece absent") # ================================= # Test jump. result = game.result(state, Action((4, 1), (2, 1))) old_piece = state.board[4][1] old_vacant = state.board[2][1] new_vacant = result.board[4][1] new_piece = result.board[2][1] assertion.assert_true(old_piece == new_piece, "jump move piece moved") assertion.assert_true(old_vacant == new_vacant, "jump move piece absent") # ================================= # Test double jump. game = Latrunculi(6, 489) state = game.start_state() result = game.result(state, Action((4, 1), (4, 5))) old_piece = state.board[4][1] old_vacant = state.board[4][5] new_vacant = result.board[4][1] new_piece = result.board[4][5] assertion.assert_true(old_piece == new_piece, "double jump move piece moved") assertion.assert_true(old_vacant == new_vacant, "double jump move piece absent") # ================================= # Test move causing piece to be captured. game = Latrunculi(5, 42) state = game.start_state() result_cb = game.result(state, Action((4, 3), (3, 3))) state.player = not state.player result_cw = game.result(state, Action((1, 0), (2, 0))) assertion.assert_equal(2, result_cw.board[2][1], "capture white piece") assertion.assert_equal(-2, result_cb.board[2][3], "capture black piece") # ================================= # Test captured piece not being able to move. actions = game.actions(result_cw) cant_move = True for action in actions: cant_move = action.source != (2, 1) and cant_move assertion.assert_true(cant_move, "captured piece can't move") # ================================= # Test move causing captured piece to be freed. result_cw.player = not result_cw.player result_cb.player = not result_cb.player # Move both pieces that are capturing another. result1 = game.result(result_cw, Action((2, 0), (1, 0))) result2 = game.result(result_cw, Action((2, 2), (3, 2))) result3 = game.result(result_cb, Action((1, 3), (0, 3))) result4 = game.result(result_cb, Action((3, 3), (4, 3))) assertion.assert_equal(1, result1.board[2][1], "move west frees captured piece") assertion.assert_equal(1, result2.board[2][1], "move east frees captured piece") assertion.assert_equal(-1, result3.board[2][3], "move north frees captured piece") assertion.assert_equal(-1, result4.board[2][3], "move south frees captured piece") # ================================= # Test capture causing captured piece to be freed. game = Latrunculi(5, 302) state = game.start_state() result1 = game.result(state, Action((3, 4), (3, 3))) # Capture black piece. result2 = game.result(result1, Action((1, 3), (2, 3))) # Free that piece. assertion.assert_equal(-2, result1.board[3][2], "captured black piece for freeing") assertion.assert_equal(-1, result2.board[3][2], "free piece by capture") # ================================= # Test potential capture causing move not being possible. game = Latrunculi(8, 31) state = game.start_state() state.player = not state.player actions = game.actions(state) cant_move = True for action in actions: cant_move = action.dest != (3, 2) and cant_move assertion.assert_true(cant_move, "suicide can't move") # ================================= # Test suicide move, a move that would normally result in capture, # but instead captures one of the two enemy pieces. # Test south game = Latrunculi(8, 42) state = game.start_state() state.player = not state.player exists = Action((6, 1), (7, 1)) in game.actions(state) assertion.assert_true(exists, "regular suicide move south") # ================================= # Test south again game = Latrunculi(8, 107) state = game.start_state() state.player = not state.player exists = Action((3, 2), (4, 2)) in game.actions(state) assertion.assert_true(exists, "regular suicide move south 2") # ================================= # Test south again again game = Latrunculi(8, 75) state = game.start_state() exists = Action((0, 2), (1, 2)) in game.actions(state) assertion.assert_true(exists, "regular suicide move south 3") # ================================= # Test west game = Latrunculi(8, 96) state = game.start_state() exists = Action((3, 3), (3, 2)) in game.actions(state) assertion.assert_true(exists, "regular suicide move west") # ================================= # Test west again game = Latrunculi(8, 118) state = game.start_state() exists = Action((3, 7), (3, 6)) in game.actions(state) assertion.assert_true(exists, "regular suicide move west 2") # ================================= # Test east game = Latrunculi(8, 102) state = game.start_state() exists = Action((2, 1), (2, 2)) in game.actions(state) assertion.assert_true(exists, "regular suicide move east") # ================================= # Test east again game = Latrunculi(8, 77) state = game.start_state() exists = Action((1, 1), (1, 2)) in game.actions(state) assertion.assert_true(exists, "regular suicide move east 2") # ================================= # Test north game = Latrunculi(8, 118) state = game.start_state() exists = Action((6, 3), (5, 3)) in game.actions(state) assertion.assert_true(exists, "regular suicide move north") # ================================= # Test north again game = Latrunculi(8, 70) state = game.start_state() exists = Action((6, 3), (5, 3)) in game.actions(state) assertion.assert_true(exists, "regular suicide move north 2") # ================================= # Test potential capture causign move not being possible. game = Latrunculi(8, 69) state = game.start_state() state.player = not state.player exists = Action((1, 2), (3, 2)) in game.actions(state) assertion.assert_true(exists, "jump suicide move") # ================================= # Test chump jain being broken, by potential capture. new_state = game.result(state, Action((1, 2), (3, 2)))
def run_tests(): # Test possible initial actions. test_size = 6 game = Connect_Four(test_size) state = game.start_state() expected_actions = [ Action(None, (test_size - 1, 0)), Action(None, (test_size - 1, 1)), Action(None, (test_size - 1, 2)), Action(None, (test_size - 1, 3)), Action(None, (test_size - 1, 4)), Action(None, (test_size - 1, 5)) ] assertion.assert_all_equal(expected_actions, game.actions(state), "correct actions") # ================================= # Test possible mid-game actions. result = game.result(state, Action(None, (test_size - 1, 0))) result = game.result(result, Action(None, (test_size - 1, 2))) result = game.result(result, Action(None, (test_size - 2, 0))) expected_actions = [ Action(None, (test_size - 3, 0)), Action(None, (test_size - 1, 1)), Action(None, (test_size - 2, 2)), Action(None, (test_size - 1, 3)), Action(None, (test_size - 1, 4)), Action(None, (test_size - 1, 5)) ] assertion.assert_all_equal(expected_actions, game.actions(result), "correct actions moved") # ================================= # Test terminal state vertical. result.player = not result.player result = game.result(result, Action(None, (test_size - 3, 0))) result.player = not result.player result = game.result(result, Action(None, (test_size - 4, 0))) assertion.assert_true(game.terminal_test(result), "terminal test vertical") # ================================= # Test utility function. utility_w = game.utility(result, True) utility_b = game.utility(result, False) assertion.assert_equal(1, utility_w, "utility white") assertion.assert_equal(-1, utility_b, "utility black") # ================================= # Test policy normalization. logits = np.array([ -0.42, 0.23, -0.33, 0.23, -0.11, 0.19, -0.42, 0.23, -0.33, 0.23, -0.11, 0.19, -0.42, 0.23, -0.33, 0.23, -0.11, 0.19, -0.42, 0.23, -0.33, 0.23, -0.11, 0.19, -0.42, 0.23, -0.33, 0.23, -0.11, 0.19, -0.42, 0.23, -0.33, 0.23, -0.11, 0.19, ]) state = game.start_state() mapping = game.map_actions(game.actions(state), logits)
def run_tests(): # Test single input shape. game = Othello(6) network = NeuralNetwork(game) state = game.start_state() shape = network.shape_input(game.structure_data(state)) assertion.assert_equal((1, 2, 6, 6), shape.shape, "Single input shape") # ================================= # Test multiple inputs shape. state1 = game.start_state() state2 = game.result(state1, game.actions(state1)[0]) state3 = game.result(state1, game.actions(state1)[1]) in1 = game.structure_data(state1) in2 = game.structure_data(state2) in3 = game.structure_data(state3) shape = network.shape_input(array([in1, in2, in3])) assertion.assert_equal((3, 2, 6, 6), shape.shape, "Multiple inputs shape") # ================================= # Test output shape of single input. policy, value = network.evaluate(in1) assertion.assert_equal((1, 36), policy.shape, "One input - policy shape") assertion.assert_equal((1, 1), value.shape, "One input - value shape") # ================================= # Test output shape of multiple inputs. policies, values = network.evaluate(array([in1, in2, in3])) print(values) assertion.assert_equal((3, 36), policies.shape, "Multiple inputs - policy shape") assertion.assert_equal((3, 1), values.shape, "Multiple inputs - value shape") assertion.assert_equal(policies[0][0], policy[0][0], "Multiple and single policy equal") assertion.assert_equal(value[0][0], value[0][0], "Multiple and single value equal")
def run_tests(): # Test softmax sampling. game = Othello(8) mcts = MCTS(game) state = game.start_state() actions = game.actions(state) root = Node(state, None) probs = [0.08, 0.09, 0.5, 0.4] visits = [6, 6, 98, 90] root.children = {a: Node(game.result(state, a), a, p, root) for (a, p) in zip(actions, probs)} for i, n in enumerate(root.children.values()): n.visits = visits[i] n.value = visits nodes = [n for n in root.children.values()] sampling = softmax_sample(nodes, [n.visits for n in nodes], 1.7) print(f"Softmax sampling: {sampling}") # ================================= # Test selection. # Test first selection. probabilities = [0.2, 0.4, 0.1, 0.6] child_nodes = {action: Node(game.result(state, action), action, prob, root) for action, prob in zip(actions, probabilities)} root.children = child_nodes node = mcts.select(root) assertion.assert_equal(child_nodes[actions[0]], node, "first selection") # ================================= # Test prior selection. root.visits = 3 for child in child_nodes.values(): child.value = 2 child.visits = 3 node = mcts.select(root) assertion.assert_equal(child_nodes[actions[3]], node, "prior selection") # ================================= # Test exploration of less visited node. root.visits = 3 for child in child_nodes: child.value = 4 child.visits = 3 child_nodes[3].value = 3 child_nodes[3].visits = 2 node = mcts.select(root) assertion.assert_equal(child_nodes[3], node, "exploration selection") # ================================= # Test expansion. # Test correct number of children. root = Node(state, None) mcts.expand(root, actions) assertion.assert_equal(16, len(root.children), "expansion correct num of children") # ================================= # Test correct parent parent_is_root = True for child in root.children: parent_is_root = child.parent == root and parent_is_root assertion.assert_true(parent_is_root, "expansion correct parent")