def find_path(self, for_player, src_x, src_y, dst_x, dst_y): board = self._board dst_node = Node(dst_x, dst_y) opponent = PLAYER_ONE if for_player == PLAYER_TWO else PLAYER_TWO exclude_players = [opponent, PLAYER_NONE] if self._walk_only_by_own_cells else [opponent] reachable = [Node(src_x, src_y)] explored = [] while len(reachable) > 0: node = self.choose_node(reachable, dst_node) if node == dst_node: return build_path(node) reachable.remove(node) explored.append(node) cells = board.get_cell_neighbors(node.x(), node.y(), exclude_players=exclude_players) new_reachable = [n for n in filter(lambda n: n not in explored, to_nodes(cells))] next_cost = node.get_cost() + 1 for adjacent in new_reachable: if adjacent not in reachable: reachable.append(adjacent) if next_cost < adjacent.get_cost(): adjacent.set_previous(node) adjacent.set_cost(next_cost) return []
def _find_path(self, from_node: Node, to_node: Node): def is_free_cell(cell): return self._board.get_cell(cell[0], cell[1]) == PLAYER_NONE def finalize_path(path_to_finalize): beg = from_node.tuple() end = to_node.tuple() beg_p = [beg] if is_free_cell(beg) else [] end_p = [end] if is_free_cell(end) else [] return merge_paths(beg_p, path_to_finalize, end_p) shortest_path = self._astar.find_path(self._for_player, from_node.x(), from_node.y(), to_node.x(), to_node.y()) shortest_path = [p for p in filter(lambda c: is_free_cell(c), shortest_path)] if len(shortest_path) >= SHORTEST_PATH_LENGTH_TO_ANALYZE: for i1, chain1 in self._chains: beg_path, n1 = self._find_path_from_node_to_chain(from_node, chain1) if n1 is not None: for i2, chain2 in self._chains: end_path, n2 = self._find_path_from_node_to_chain(to_node, chain2) if n2 is not None: mid_path = self._find_path_between_chains(i1, i2) if i1 != i2 else [] path = finalize_path(merge_paths(beg_path, mid_path, end_path)) if len(path) < len(shortest_path): shortest_path = path return shortest_path
def choose_node(self, nodes, dst_node: Node): min_cost = INFINITY best_node = None for node in nodes: cost_start_to_node = node.get_cost() cost_node_to_goal = get_distance(node.x(), node.y(), dst_node.x(), dst_node.y()) total_cost = cost_start_to_node + cost_node_to_goal if min_cost > total_cost: min_cost = total_cost best_node = node return best_node
def _find_chains(self): result = [] explored = [] board = self._board w, h = board.get_dimensions() for y in range(h): for x in range(w): current_node = Node(x, y) if current_node not in explored: player = board.get_cell(x, y) if player == self._for_player: chain = [] reachable = [current_node] while len(reachable) > 0: node = reachable[0] reachable.remove(node) explored.append(node) chain.append(node) cells = board.get_cell_neighbors(node.x(), node.y(), [self._opponent, PLAYER_NONE]) new_reachable = [n for n in filter(lambda n: n not in explored, to_nodes(cells))] for adjacent in new_reachable: if adjacent not in reachable: reachable.append(adjacent) if len(chain): result.append(chain) return result
def find_path(self, for_player, src_x, src_y, dst_x, dst_y): def cell_is_not_src_or_dst(cell): node = Node(cell[0], cell[1]) return node != from_node and node != to_node from_node = Node(src_x, src_y) to_node = Node(dst_x, dst_y) self._init_vars(to_node, for_player) self._init_data() shortest_path = self._find_path(from_node, to_node) shortest_path_len = len(shortest_path) if shortest_path_len >= SHORTEST_PATH_LENGTH_TO_ANALYZE: shortest_full_path = self._construct_full_path(from_node, to_node, shortest_path) shortest_full_path_len = len(shortest_full_path) while True: found = False path_without_src_and_dst = [p for p in filter(lambda c: cell_is_not_src_or_dst(c), shortest_path)] new_board = self._board.copy(check_bounds=False) new_board.set_cells(path_without_src_and_dst, self._opponent) self._board = new_board self._init_data() verifiable_path = self._find_path(from_node, to_node) verifiable_path_len = len(verifiable_path) if verifiable_path_len == shortest_path_len: verifiable_full_path = self._construct_full_path(from_node, to_node, verifiable_path) verifiable_full_path_len = len(verifiable_full_path) if verifiable_full_path_len < shortest_full_path_len: shortest_path = verifiable_path shortest_full_path_len = verifiable_full_path_len found = True if not found: break return shortest_path
def build_path(to_node: Node): path = [] while to_node is not None: path.append((to_node.x(), to_node.y())) to_node = to_node.get_previous() return path
def path_to_ids(path): return [Node(p[0], p[1]).id() for p in path]
def cell_is_not_src_or_dst(cell): node = Node(cell[0], cell[1]) return node != from_node and node != to_node
def _construct_full_path(self, src: Node, dst: Node, path): board = self._board.copy(check_bounds=False) board.set_cells(path, self._for_player) walker = WalkerPathfinder(board) return walker.find_path(self._for_player, src.x(), src.y(), dst.x(), dst.y())