예제 #1
0
파일: basic.py 프로젝트: vodchella/pyhex
    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 []
예제 #2
0
    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
예제 #3
0
    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
예제 #4
0
 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
예제 #5
0
    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
예제 #6
0
파일: basic.py 프로젝트: vodchella/pyhex
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
예제 #7
0
파일: paths.py 프로젝트: vodchella/pyhex
 def path_to_ids(path):
     return [Node(p[0], p[1]).id() for p in path]
예제 #8
0
 def cell_is_not_src_or_dst(cell):
     node = Node(cell[0], cell[1])
     return node != from_node and node != to_node
예제 #9
0
 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())