左手法のアルゴリズムの可視化 (Python in Processing)
はじめに
迷路を解く有名なアルゴリズムの一つに,左手法(右手法)があります.これは,「左手で常に壁を触り続けて前に進めば,必ずゴールに到達できる」という考えに基づくものです.単純な迷路であればゴールにたどり着けますが,スタート地点やゴール地点を意地悪されたり,迷路が立体的になったりすると,ゴールにたどり着けない場合があります.より有用なアルゴリズムは多数ありますが,理解と実装が簡単で,グリッドを扱う入門に適した題材だと思います.
この記事では,左手法を Processing (Pythonモード) で実装し,動きを可視化します.簡単のためグローバル変数を多用していますが,本当はよくないです.
環境
- Processing 3.5.3
- Python Mode for Processing 3 3056
動画
実装
left_hand_method.pyde
# 解く対象のマップ
# 壁は1, 通路は0
# grid[y][x] でアクセス
grid = [
[1, 1, 1, 1, 1, 1, 1],
[1, 0, 1, 0, 0, 1, 1],
[1, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1]
]
# マス目の表示サイズ
S = 500 / 7
# 上下左右の相対座標 [←,↑,→,↓] の順
dx = [-1, 0, 1, 0]
dy = [0, -1, 0, 1]
# ゴールの座標
goal_x, goal_y = 1, 5
# エージェントの座標と向き
px, py = 1, 1
p_dir = 0
# 定期実行するための変数たち
dt = 15
next_frame = dt * 3
def setup():
frameRate(30)
size(S * 7, S * 7)
textSize(30)
textAlign(CENTER, TOP)
def draw():
background(255)
draw_grid()
draw_agent()
# 定期的に左手法を1回実行
global next_frame
if next_frame < frameCount:
left_hand_method()
next_frame += dt
# 左手法のアルゴリズム
# 左隣に壁がある && 前に壁がある => 右回転
# 左隣に壁がある && 前に壁がない => 前進
# 左隣に壁がない => 左回転して前進
def left_hand_method():
global px, py, p_dir
# ゴール済み判定
if (px, py) == (goal_x, goal_y):
return
# エージェントから見て左側の向きと座標
left_dir = (p_dir + 4 - 1) % 4
lx, ly = px + dx[left_dir], py + dy[left_dir]
# 左に壁があるかどうか
if grid[ly][lx] == 1:
# 前に壁があるかどうか
if grid[py + dy[p_dir]][px + dx[p_dir]] == 1:
p_dir = (p_dir + 1) % 4
else:
px += dx[p_dir]
py += dy[p_dir]
else:
p_dir = left_dir
px, py = lx, ly
# --- 描画用の補助関数 ---
# マップの描画
def draw_grid():
fill(0)
for y in range(7):
for x in range(7):
if grid[y][x] == 1:
rect(x * S, y * S, S, S)
textHeight = textAscent() + textDescent()
text("G", (goal_x + 0.5) * S, (goal_y + 0.5) * S - textHeight / 2)
# エージェントの描画
# 未ゴールは赤, ゴール済みは青
def draw_agent():
if (px, py) == (goal_x, goal_y):
fill(0, 0, 255)
else:
fill(255, 0, 0)
pushMatrix()
translate((px + 0.5) * S, (py + 0.5) * S)
rotate(p_dir * HALF_PI)
triangle(
-S / 4, 0,
S / 4, -S / 8,
S / 4, S / 8
)
popMatrix()
参考
left_hand_method.pyde
# 解く対象のマップ
# 壁は1, 通路は0
# grid[y][x] でアクセス
grid = [
[1, 1, 1, 1, 1, 1, 1],
[1, 0, 1, 0, 0, 1, 1],
[1, 0, 1, 1, 0, 0, 1],
[1, 0, 0, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1]
]
# マス目の表示サイズ
S = 500 / 7
# 上下左右の相対座標 [←,↑,→,↓] の順
dx = [-1, 0, 1, 0]
dy = [0, -1, 0, 1]
# ゴールの座標
goal_x, goal_y = 1, 5
# エージェントの座標と向き
px, py = 1, 1
p_dir = 0
# 定期実行するための変数たち
dt = 15
next_frame = dt * 3
def setup():
frameRate(30)
size(S * 7, S * 7)
textSize(30)
textAlign(CENTER, TOP)
def draw():
background(255)
draw_grid()
draw_agent()
# 定期的に左手法を1回実行
global next_frame
if next_frame < frameCount:
left_hand_method()
next_frame += dt
# 左手法のアルゴリズム
# 左隣に壁がある && 前に壁がある => 右回転
# 左隣に壁がある && 前に壁がない => 前進
# 左隣に壁がない => 左回転して前進
def left_hand_method():
global px, py, p_dir
# ゴール済み判定
if (px, py) == (goal_x, goal_y):
return
# エージェントから見て左側の向きと座標
left_dir = (p_dir + 4 - 1) % 4
lx, ly = px + dx[left_dir], py + dy[left_dir]
# 左に壁があるかどうか
if grid[ly][lx] == 1:
# 前に壁があるかどうか
if grid[py + dy[p_dir]][px + dx[p_dir]] == 1:
p_dir = (p_dir + 1) % 4
else:
px += dx[p_dir]
py += dy[p_dir]
else:
p_dir = left_dir
px, py = lx, ly
# --- 描画用の補助関数 ---
# マップの描画
def draw_grid():
fill(0)
for y in range(7):
for x in range(7):
if grid[y][x] == 1:
rect(x * S, y * S, S, S)
textHeight = textAscent() + textDescent()
text("G", (goal_x + 0.5) * S, (goal_y + 0.5) * S - textHeight / 2)
# エージェントの描画
# 未ゴールは赤, ゴール済みは青
def draw_agent():
if (px, py) == (goal_x, goal_y):
fill(0, 0, 255)
else:
fill(255, 0, 0)
pushMatrix()
translate((px + 0.5) * S, (py + 0.5) * S)
rotate(p_dir * HALF_PI)
triangle(
-S / 4, 0,
S / 4, -S / 8,
S / 4, S / 8
)
popMatrix()
Author And Source
この問題について(左手法のアルゴリズムの可視化 (Python in Processing)), 我々は、より多くの情報をここで見つけました https://qiita.com/zenito9970/items/bf43617e38751f508f7d著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .