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)])