Pythonアニメーションを使用して、迷路から抜け出す方法を見つけるための深さ優先アルゴリズムを示す方法を教える10分

@この記事は公開番号から来ています:csdn2299、公開番号プログラマー学校に注意を払うように
深さ優先アルゴリズム(DFSアルゴリズム)とは何ですか?

開始ノードとターゲットノード間のパスを見つけるためのアルゴリズムは、迷路を脱出するためのパスを検索するためによく使用されます。主な考え方は、入り口から始めて、周囲のノードの可能な座標が順番に検索されますが、同じノードを繰り返し通過することはなく、障害物ノードを通過することはできません。ノードに移動して行く方法がないことがわかった場合は、前のノードにフォールバックして別のパスを選択します。出口が見つかるか、開始点に戻る方法がなくなるまで、ゲームは終了です。もちろん、深さ優先アルゴリズムは、有効なパスが見つかる限り検索を停止します。つまり、進む方法がある限り、深さ優先アルゴリズムは前のステップにフォールバックしません。

それでもプログラミングの世界で混乱している場合は、Python学習ボタンqun:784758214に参加して、前任者がどのように学習したかを確認できます。交換体験!私は上級のpython開発エンジニアで、基本的なpythonスクリプトからWeb開発、クローラー、django、データマイニングなど、ゼロベースから実際の戦闘情報を予測するまでを担当しています。Pythonのすべての小さな友達に!注意が必要ないくつかの学習方法と小さな詳細を共有し、クリックしてPython学習者の集まりに参加してください

次の図は、DFSアルゴリズムを使用して検索されたパスです。ここに画像の説明を挿入
要約:

開始点から開始して、次のステップを通過できるノードにクエリを実行し、これらの可能なノードをスタックにプッシュします。これにより、既に通過したノードは再試行しません。クエリが完了したら、スタックからノードを削除し、ノードの周囲に機能しているノードがあるかどうかをクエリします。可能なノードがない場合は、スタックからノードを取得し続けます。現在のノードが終点になるか、スタックにノードがなくなるまで、上記の操作を繰り返します。

データを定義します。

開始ノードとターゲットノード
ストレージノードスタック
補助機能の定義

次のノードの関数を取得します:
終点かどうか判別する後続関数:test_goal
まず、スタックのデータ構造を定義しましょうスタックは後入れ先出しのデータ構造です。

幅優先検索は後でキューを使用し、A *アルゴリズムは優先キューを使用するため、以降の使用のために抽象基本クラスを定義しました。dequeは、組み込み型のリスト操作に似た両端キューですが、ヘッドとテールの挿入および削除操作の時間の複雑さはどちらもO(1)です。

# utils.py
from abc import abstractmethod, ABC
from collections import deque
class Base(ABC):
  def __init__(self):
    self._container = deque()
  @abstractmethod
  def push(self, value):
    """push item"""
  @abstractmethod
  def pop(self):
    """pop item"""
  def __len__(self):
    return len(self._container)
  def __repr__(self):
    return f'{type(self).__name__}({list(self._container)})'
class Stack(Base):
  def push(self, value):
    self._container.append(value)
  def pop(self):
    return self._container.pop()

次に、dfs関数を定義しましょう。このうち、initialは初期ノード、sはスタック、markedは通過ノードを記録するために使用されます。後続関数は次の可能なノードを検索するために使用され、test_goal関数はノードがターゲットノードであるかどうかを判別するために使用されます。childrenは可能なノードのリストであり、これらのノードをトラバースし、スタックに移動していないノードをプッシュして、レコードを作成します。

# find_path.py
from utils import Stack
def dfs(initial, _next = successor, _test = test_goal):
  s: Stack = Stack()
  marked = {initial}
  s.push(initial)
  while s:
    parent: state = s.pop()
    if _test(parent):
      return parent
    children = _next(parent)
    for child in children:
      if child not in marked:
        marked.add(child)
        s.push(child)

次に、DFSアルゴリズムを使用して迷路を検索し、検索された迷路を視覚的に示します。

まず、列挙を使用してパスの色を示します。EMPTYは通常のノード、BLOCKEDはバリアノード、STARTは迷路の入り口、ENDは迷路の出口、PATHは検索パスです。

from enum import IntEnum
class Cell(IntEnum):
  EMPTY = 255
  BLOCKED = 0
  START = 100
  END = 200
  PATH = 150

次に、迷路を定義しましょう。まず、Namedtupleを使用して、迷路の各ノードの座標を定義します。

class MazeLocation(NamedTuple):
  row: int
  col: int

まず、ノード間の関係の決定を容易にするために、Mazeクラスで内部クラス_Nodeを定義して、ノードとノードの親ノードの状態を記録します。

class _Node:
  def __init__(self, state, parent):
    self.state = state
    self.parent = parent

次に、初期化して入口と出口の座標を決定し、np.random.choice関数を使用してランダムに迷路を生成し、入口と出口にマークを付けます。

def __init__(self, rows: int = 10, cols: int = 10,
       sparse: float = 0.2, seed: int = 365,
       start: MazeLocation = MazeLocation(0, 0),
       end: MazeLocation = MazeLocation(9, 9), *,
       grid: Optional[np.array] = None) -> None:
  np.random.seed(seed)
  self._start: MazeLocation = start
  self._end: MazeLocation = end
  self._grid: np.array = np.random.choice([Cell.BLOCKED, Cell.EMPTY],
                        (rows, cols), p=[sparse, 1 - sparse])
  self._grid[start] = Cell.START
  self._grid[end] = Cell.END

2つ目は、ノード座標がターゲットノードを基準にしている限り、test_goalメソッドです。

def _test_goal(self, m1: MazeLocation) -> bool:
  return m1 == self._end

次に、後続メソッドがあり、上、下、左、右の方向のノードが障害物ではなく、境界内にある限り、それらが考慮され、リストに追加されます。

List[MazeLocation]:
  location: List[MazeLocation] = []
  row, col = self._grid.shape
  if m1.row + 1 < row and self._grid[m1.row + 1, m1.col] != Cell.BLOCKED:
    location.append(MazeLocation(m1.row + 1, m1.col))
  if m1.row - 1 >= 0 and self._grid[m1.row - 1, m1.col] != Cell.BLOCKED:
    location.append(MazeLocation(m1.row - 1, m1.col))
  if m1.col + 1 < col and self._grid[m1.row, m1.col + 1] != Cell.BLOCKED:
    location.append(MazeLocation(m1.row, m1.col + 1))
  if m1.col - 1 >= 0 and self._grid[m1.row, m1.col - 1] != Cell.BLOCKED:
    location.append(MazeLocation(m1.row, m1.col - 1))
  return location

表示パス、一時停止は画像を表示する間隔、プロットは描画フラグです。ターゲットノードから開始して、各ノードの親ノードを最初のノードに到達するまでトラバースし、パスマップを描画します。

None:
  if pause <= 0:
    raise ValueError('pause must be more than 0')
  path: Maze._Node = self._search()
  if path is None:
    print('没有找到路径')
    return
  path = path.parent
  while path.parent is not None:
    self._grid[path.state] = Cell.PATH
    if plot:
      self._draw(pause)
    path = path.parent
  print('Path Done')

DFSアルゴリズムを使用するために、迷路クラスを継承するDepthFirstSearchクラスを定義します。DepthFirstSearchクラスは、基本クラスの_searchメソッドを書き換えます。これは、前に定義したdfs関数定義とほぼ同じです。

class DepthFirstSearch(Maze):
  def _search(self):
    stack: Stack = Stack()
    initial: DepthFirstSearch._Node = self._Node(self._start, None)
    marked: Set[MazeLocation] = {initial.state}
    stack.push(initial)
    while stack:
      parent: DepthFirstSearch._Node = stack.pop()
      state: MazeLocation = parent.state
      if self._test_goal(state):
        return parent
      children: List[MazeLocation] = self._success(state)
      for child in children:
        if child not in marked:
          marked.add(child)
          stack.push(self._Node(child, parent))
class DepthFirstSearch(Maze):
  def _search(self):
    stack: Stack = Stack()
    initial: DepthFirstSearch._Node = self._Node(self._start, None)
    marked: Set[MazeLocation] = {initial.state}
    stack.push(initial)
    while stack:
      parent: DepthFirstSearch._Node = stack.pop()
      state: MazeLocation = parent.state
      if self._test_goal(state):
        return parent
      children: List[MazeLocation] = self._success(state)
      for child in children:
        if child not in marked:
          marked.add(child)
          stack.push(self._Node(child, parent))

読んでいただきありがとうございます
。大学でpythonを勉強することに決めたとき、私はコンピューターの基礎がよくなかったことがわかりました。私は学問の資格を持っていませんでした。これは
何もすることはできません。埋め合わせるしかできないので、コーディング以外で自分の反撃を始めました。道は、Pythonのコア知識を学び続け、コンピューターの基礎の詳細な研究を整理し、平凡になりたくない場合は、コーディングに参加して成長してください!
実は、ここには技術だけでなく、それ以外のものもあり、例えば「絹糸」というよりも、どうやってプログラマーとして絶妙な存在になるのか、プログラマー自体が高貴な存在ですね。[参加するにはクリックしてください]自分らしくなりたい、高貴な人になりたい、是非!

公開された34のオリジナル記事 いいね12 訪問者20,000以上

おすすめ

転載: blog.csdn.net/chengxun03/article/details/105476985
おすすめ