def simple_dijkstra(board: HexBoard, source, is_max):

    Q = set()
    V_set = board.get_all_vertices()
    dist = {}
    dist_clone = {}  # I made a clone of dist to retain the information in dist
    prev = {}
    for v in V_set:
        dist[v] = np.inf
        dist_clone[v] = np.inf  # clone
        prev[v] = None
        Q.add(v)
    dist[source] = 0
    dist_clone[source] = dist[source]  # clone

    while len(Q) != 0:
        u = min(dist, key=dist.get)
        Q.remove(u)

        color = board.BLUE if is_max else board.RED

        ## IGNORE THE CODE BELOW, IT DOESN'T WORK PROPERLY AT THE MOMENT
        # begin reverse iteration step
        # this happens when we get to a border of the corresponding color (i.e. we connect the sides)
        # if board.border(color, u):
        #     S = []
        #     path_length = 0
        #     if prev[u] or u == source:
        #         while u:
        #             if not board.is_color(u, color):
        #                 path_length += 1
        #             S.insert(0, u)
        #             u = prev[u]
        #     print(f"S for color {color} IS: {S}")
        #     print(f"Path length when accounting for already marked hexagons: {path_length}")
        #     return path_length, S # You can also optionally return "S" if you also want to store the path
        # # end reverse iteration step

        neighbors = board.get_neighbors(u)

        for v in neighbors:
            if v in Q:  # Only check neighbours that are also in "Q"
                len_u_v = 0 if board.is_color(
                    v,
                    color) else 1  # this isn't working as intended i think...
                alt = dist[u] + len_u_v
                if alt < dist[v]:
                    dist[v] = alt
                    dist_clone[v] = dist[v]
                    prev[v] = u
        # We pop "u" from the distance dict to ensure that the keys match the ones in "Q"
        dist.pop(
            u
        )  # This is also why we need the clone, or else we'll return an empty dict

    return dist_clone, prev
def simple_dijkstra(board: HexBoard, source, is_max):

    Q = set()
    V_set = board.get_all_vertices()
    dist = {}
    dist_clone = {}  # I made a clone of dist to retain the information in dist
    prev = {}
    for v in V_set:
        dist[v] = np.inf
        dist_clone[v] = np.inf  # clone
        prev[v] = None
        Q.add(v)
    dist[source] = 0
    dist_clone[source] = dist[source]  # clone

    while len(Q) != 0:
        u = min(dist, key=dist.get)
        Q.remove(u)

        color = board.BLUE if is_max else board.RED

        neighbors = board.get_neighbors(u)

        for v in neighbors:
            if v in Q:  # Only check neighbours that are also in "Q"
                len_u_v = -1 if board.is_color(
                    v,
                    color) else 1  # this isn't working as intended i think...
                ### BLOCK TO MAKE AI MORE AGGRESSIVE ###
                if board.border(
                        color, v
                ):  # If there is a move that reaches the border in the simulation
                    if board.check_win(color):  # And it results in a win
                        len_u_v = -2  # Make that move more valuable
                ### END OF AGGRO BLOCK ###
                alt = dist[u] + len_u_v
                if alt < dist[v]:
                    dist[v] = alt
                    dist_clone[v] = dist[v]
                    prev[v] = u
        # We pop "u" from the distance dict to ensure that the keys match the ones in "Q"
        dist.pop(
            u
        )  # This is also why we need the clone, or else we'll return an empty dict

    return dist_clone, prev
    assert (board.check_win(winner) == True)
    assert (board.check_win(loser) == False)
    board.print()
endable_board = HexBoard(4)
# sanity check that random play will at some point end the game
while not endable_board.game_over:
    endable_board.place((np.random.randint(0, 4), np.random.randint(0, 4)),
                        HexBoard.RED)
assert (endable_board.game_over == True)
assert (endable_board.check_win(HexBoard.RED) == True)
assert (endable_board.check_win(HexBoard.BLUE) == False)
print("Randomly filled board")
endable_board.print()

neighbor_check = HexBoard(5)
assert (neighbor_check.get_neighbors((0, 0)) == [(1, 0), (0, 1)])
assert (neighbor_check.get_neighbors((0, 1)) == [(1, 1), (1, 0), (0, 2),
                                                 (0, 0)])
assert (neighbor_check.get_neighbors((1, 1)) == [(0, 1), (2, 1), (0, 2),
                                                 (2, 0), (1, 2), (1, 0)])
assert (neighbor_check.get_neighbors((3, 4)) == [(2, 4), (4, 4), (4, 3),
                                                 (3, 3)])
assert (neighbor_check.get_neighbors((4, 3)) == [(3, 3), (3, 4), (4, 4),
                                                 (4, 2)])
assert (neighbor_check.get_neighbors((4, 4)) == [(3, 4), (4, 3)])
neighbor_check_11 = HexBoard(5)
assert (neighbor_check_11.get_neighbors((4, 4)) == [(3, 4), (4, 3)])

neighbor_check_small = HexBoard(2)
assert (neighbor_check_small.get_neighbors((0, 0)) == [(1, 0), (0, 1)])
assert (neighbor_check_small.get_neighbors((1, 0)) == [(0, 0), (0, 1), (1, 1)])