방향 정보가 있는 미로가 있을 때, 미로를 탈출하시오.
# 방향 정보
NONE, RIGHT, LEFT, DOWN, UP = 0, 1, 2, 4, 8
# 예
5 = 1 + 4 = RIGHT + DOWN ( 오른쪽 아래쪽에 길이 있음 )
7 = 1 + 2 + 4 = RIGHT + LEFT + DOWN
# 미로 (입력)
4 5 7 3 6
12 8 12 5 10
9 3 10 12 4
4 5 6 9 14
9 10 9 3 11
# 탈출 (출력)
4 0 1 1 4
4 0 8 4 2
1 1 8 4 0
0 0 0 1 4
0 0 0 0 1
8개의 풀이가 있습니다.
Ruby
def maze_runner(size = 5)
maze = size.times.map { gets.split.map {|n| [1,2,4,8].select {|e| n.to_i & e > 0} } }
start, goals, range = [0, 0], [[size-1, size], [size, size-1]], (0...size)
compass = ->r,c { maze[r][c].map {|k| {1 => [r,c+1], 2 => [r,c-1],
4 => [r+1,c], 8 => [r-1,c]}.assoc(k) } }
ways = ->path { compass[*path.keys.last].reject {|_,passed| path[passed] }.
map {|dir,pt| path.merge(path.keys.last => dir, pt => 0) } }
move = ->path { goals.index(path.keys.last) ? path : path.any? ? ways[path].flat_map(&move) : {} }
exit = move[{start => 0}].pop
puts (exit ? range.map {|r| range.map {|c| exit[[r,c]] || 0}.join(" ") } : "no exit")
end
Test
maze1 = " 4 5 7 3 6\n" +
"12 8 12 5 10\n" +
" 9 3 10 12 4\n" +
" 4 5 6 9 14\n" +
" 9 10 9 3 10\n"
$stdin = StringIO.new(maze1)
expect { maze_runner }.to output("no exit\n").to_stdout
maze2 = " 4 5 7 3 6\n" +
"12 8 12 5 10\n" +
" 9 3 10 12 4\n" +
" 4 5 6 9 14\n" +
" 9 10 9 3 11\n"
$stdin = StringIO.new(maze2)
expect { maze_runner }.to output( "4 0 1 1 4\n" +
"4 0 8 4 2\n" +
"1 1 8 4 0\n" +
"0 0 0 1 4\n" +
"0 0 0 0 1\n").to_stdout
def maze_escape():
dr = ((0,1), (0,-1), (1,0), (-1,0))
stc = [_solver(0, 0)]
route = [(0,0)]
while stc:
try:
dx, dy, x, y = *dr[next(stc[-1])], *route[-1]
if (x+dx, y+dy) in route: continue
if not(0<= x+dx <len(board) and 0<= y+dy <len(board[0])): break
stc.append(_solver(x+dx, y+dy))
route.append((x+dx, y+dy))
except:
stc.pop()
route.pop()
for i in range(len(board)):
for j in range(len(board[i])):
if (i,j) not in route: board[i][j] = 0
print(str(board[i])[1:-1].replace(',', ''))
def _solver(x, y):
tmp = bin(board[x][y])[2:][::-1]
for i,j in enumerate(tmp):
if j == '1':
board[x][y] = 2**i
yield i
board[x][y] = 0
test = '''\
4 5 7 3 6
12 8 12 5 10
9 3 10 12 4
4 5 6 9 14
9 10 9 3 11'''
board = [[*map(int, i.split())] for i in test.splitlines()]
maze_escape()
package bamin_pretest;
import java.util.Scanner;
import java.util.Arrays;
public class main {
public static void main(String[] args) {
int x_size = 5, y_size = 5;
Scanner scanner = new Scanner(System.in);
int maze[] = new int[x_size*y_size];
for(int i = 0; i<x_size*y_size; i++)
maze[i] = scanner.nextInt();
int sol[] = new int[x_size*y_size];
Arrays.fill(sol, 0);
int position = 0;
if (check(maze,sol,position,0)) {
for(int i = 0; i<sol.length;i++) {
if(i%5==0 && i!=0) System.out.println();
System.out.print(" " + String.valueOf(sol[i]));
}
}
else System.out.println("isn't solution");
}
public static boolean check(int[] maze, int[] sol, int position, int from) {
if(position == maze.length-1) {sol[position] = 1; return true;}
int temp = maze[position] - from;
if((temp&1) != 0) {
if(check(maze,sol,position+1,2)) {
sol[position] = 1;
return true;
}
else return false;
}
if((temp&2) != 0) {
if(check(maze,sol,position-1,1)) {
sol[position] = 2;
return true;
}
else return false;
}
if((temp&4) != 0) {
if(check(maze,sol,position+5,8)) {
sol[position] = 4;
return true;
}
else return false;
}
if((temp&8) != 0) {
if(check(maze,sol,position-5,4)) {
sol[position] = 8;
return true;
}
else return false;
}
return false;
}
}
입력란에 x_size와 y_size를 따로 받지 않기에 임의적으로 5라는 값을 직접 넣어놨습니다.
Haskell
크기가 s인 미로에서 상하좌우 이동은 일차원 배열 int maze[s*s] 에서 index가 1, -1, s, -s만큼 변하는 것으로 생각할 수 있습니다.
import Data.List
import Data.List.Split
import Control.Monad
import Control.Monad.Loops
s = 5
doors = fmap ([1,-1,s,-s]!!) . findIndices odd . take 4 . iterate (`div` 2)
solution maze = reverse $ head $ iterateUntilM ((>s*s-1) . head) advance [0]
where advance = filter (notElem <$> head <*> tail) . (\(x:xs) -> (:x:xs) . (+x) <$> doors (maze !! x))
direction path = maybe 0 (2^) . (flip lookup dic >=> flip elemIndex [1,-1,s,-s]) <$> [0..s*s-1]
where dic = flip zip =<< zipWith (-) =<< tail $ path
main = fmap read . words <$> getContents >>= putStrLn . unlines . fmap unwords . chunksOf 5 . fmap show . direction . solution
$ cat input | runhaskell solution
4 0 1 1 4
4 0 8 4 2
1 1 8 4 0
0 0 0 1 4
0 0 0 0 1
약간 더 읽기 편한 버전입니다.
import Data.List
import Data.List.Split
import Control.Monad
import Control.Monad.Loops
type Location = Int
type Direction = Int
type Maze = [Direction]
type Path = [Location]
delta s = [1, -1, s, -s]
solution :: Int -> Maze -> [Path]
solution s maze = reverse <$> iterateUntilM ((> s*s-1) . head) advance [0]
where
advance :: Path -> [Path]
advance p = fmap (:p) $ filter (`notElem` p) $ branch $ head p
branch :: Location -> [Location]
branch l = (+ l) <$> (fmap ((delta s)!!) . bits $ maze !! l)
bits :: Direction -> [Int]
bits = findIndices odd . take 4 . iterate (`div` 2)
display :: Int -> Path -> String
display s path = unlines . fmap unwords . chunksOf s . fmap show $ dir <$> [0..s*s-1]
where
diff :: Location -> Maybe Int
diff = flip lookup $ flip zip =<< zipWith (-) =<< tail $ path
dir :: Location -> Int
dir = maybe 0 (2^) . (diff >=> flip elemIndex (delta s))
parse :: String -> Maze
parse = fmap read . words
main = parse <$> getContents >>= mapM_ (putStrLn . display 5) . solution 5
Store Comonad와 Tree를 사용하여 만들어보았습니다.
시작점에서부터의 경로를 트리로 만들고 DFS로 미로 밖의 leaf를 찾습니다. lazy 언어이기 때문에 트리를 한꺼번에 계산하지는 않습니다.
결과적인 알고리즘은 위의 코드와 크게 다르지 않을 것 같습니다.
{-# LANGUAGE ScopedTypeVariables, ParallelListComp, DeriveFunctor, TypeSynonymInstances, FlexibleInstances #-}
import Data.List
import Data.List.Split
import Control.Monad
import Control.Monad.Loops
import Control.Comonad.Store
import Data.Fix
import Data.Bits
import Data.Ix
import Data.Maybe
import Data.Set (Set)
import qualified Data.Set as Set
import qualified Data.Map as Map
import Debug.Trace
type Loc = Int
type Dir = Int
type Maze = Store Loc Dir
type Path = [Loc]
type Seed = (Maze, Set Loc)
data TreeF a = NodeF Maze [a] deriving Functor
type Tree = Fix TreeF
escaped :: Int -> Maze -> Bool
escaped s = not . inRange (0, s*s-1) . pos
coalgebra :: Int -> Seed -> TreeF Seed
coalgebra s (maze, visited) = NodeF maze branches
where
branches = if escaped s maze then [] else
[ (seek newloc maze, Set.insert newloc visited)
| (delta, bit) <- zip [1, -1, s, -s]
$ testBit (extract maze) <$> [0..3]
, bit == True
, let newloc = (pos maze) + delta
, newloc `Set.notMember` visited
]
type Algebra f a = f a -> a
algebra :: Int -> Algebra TreeF (Loc, Maybe [(Loc, Dir)])
algebra s (NodeF maze []) = (pos maze, path)
where
path
= if escaped s maze
then Just []
else Nothing
algebra s (NodeF maze paths) = (pos maze, path)
where
path
= fmap (\(loc, Just p) -> (pos maze, toDir (pos maze - loc)) : p)
$ find (isJust . snd)
$ paths
toDir = fromJust . flip elemIndex [0, 1, -1, s, -s]
solution s maze = snd $ hylo (algebra s) (coalgebra s) (maze, Set.empty)
render :: Int -> Maybe [(Loc, Dir)] -> String
render s (Just path)
= unlines . fmap unwords . chunksOf s
$ [ maybe "0" show $ Map.lookup i pathMap
| i <- [0..s*s-1]
]
where
pathMap = Map.fromList path
parse :: String -> Maze
parse str = store (map!!) 0
where map = fmap read $ words str
main = parse <$> getContents >>= putStrLn . render 5 . solution 5
package test;
import java.util.Stack;
public class java1 {
static int NONE = 0;
static int RIGHT = 1;
static int LEFT = 2;
static int DOWN = 4;
static int UP = 8;
public static void main(String args[]){
int maze[][] = {{4,5,7,3,6}
,{12,8,12,5,10}
,{9,3,10,12,4}
,{4,5,6,9,14}
,{9,10,9,3,11}};
int loc[] = {0,0};
Stack<Integer> route = new Stack<Integer>();
findRoute(maze,loc,route);
}
/*정답 여부 판별*/
public static boolean isFinished(int loc[]){
boolean result = false;
if(loc[0] < 0 || loc[0] > 4 || loc[1] < 0 || loc[1] > 4)
result = true;
return result;
}
/*현재위치에서 이동방향에 따라 다음 위치 계산*/
public static int[] nextLoc(int loc[], int move){
int[] result = new int[2];
result[0] = loc[0];
result[1] = loc[1];
if(move == UP){
result[0] = loc[0] - 1;
}
if(move == DOWN){
result[0] = loc[0] + 1;
}
if(move == LEFT){
result[1] = loc[1] - 1;
}
if(move == RIGHT){
result[1] = loc[1] + 1;
}
return result;
}
/* 정답 출력 */
public static void printRoute(Stack<Integer> route){
int[][] result = {{0,0,0,0,0}
,{0,0,0,0,0}
,{0,0,0,0,0}
,{0,0,0,0,0}
,{0,0,0,0,0}};
int[] loc = {0,0};
int move = 0;
for(int i = 0; i < route.size(); i++){
move = route.get(i);
result[loc[0]][loc[1]] = move;
loc = nextLoc(loc, move);
}
for(int i = 0;i<5;i++){
for(int j=0;j<5;j++){
System.out.print(result[i][j] + " ");
}
System.out.println();
}
}
/*경로 계산*/
public static void findRoute(int maze[][],int loc[],Stack<Integer> route){
if(isFinished(loc)){
printRoute(route);
return;
}
int way = maze[loc[0]][loc[1]];
int beforeMove = NONE;
if(route.size() != 0){
beforeMove = route.get(route.size()-1);
}
/* 이동 가능한 경로에 대해 재귀 호출(이전 위치 제외) */
if((way & DOWN) != 0 && beforeMove != UP){
route.push(DOWN);
findRoute(maze,nextLoc(loc,DOWN),route);
}
if((way & RIGHT) != 0 && beforeMove != LEFT){
route.push(RIGHT);
findRoute(maze,nextLoc(loc,RIGHT),route);
}
if((way & UP) != 0 && beforeMove != DOWN){
route.push(UP);
findRoute(maze,nextLoc(loc,UP),route);
}
if((way & LEFT) != 0 && beforeMove != RIGHT){
route.push(LEFT);
findRoute(maze,nextLoc(loc,LEFT),route);
}
return;
}
}
inputMaze = '''
4 5 7 3 6
12 8 12 5 10
9 3 10 12 4
4 5 6 9 14
9 10 9 3 11
'''
maze = list()
for line in inputMaze.split('\n'):
if line.strip() == '': continue
toks = [int(tok) for tok in line.strip().split(' ') if tok != '']
maze.append(toks)
for i in range(0,len(maze)):
for j in range(i,len(maze[i])):
tmp = maze[i][j]
maze[i][j] = maze[j][i]
maze[j][i] = tmp
def getInfo(secondPropositionInfo):
directionCandidate = list()
if (secondPropositionInfo >> 0) % 2 == 1: directionCandidate.append(2 ** 0)
if (secondPropositionInfo >> 1) % 2 == 1: directionCandidate.append(2 ** 1)
if (secondPropositionInfo >> 2) % 2 == 1: directionCandidate.append(2 ** 2)
if (secondPropositionInfo >> 3) % 2 == 1: directionCandidate.append(2 ** 3)
if (secondPropositionInfo >> 4) % 2 == 1: directionCandidate.append(2 ** 4)
return directionCandidate
outputMaze = [ [ 0 for i in range(0,len(maze[0]))] for i in range(0,len(maze)) ]
def goMaze(x,y,x_1,y_1,before):
outputMaze[x_1][y_1] = before
if x>4 or y >4: return True
for direction in getInfo(maze[x][y]):
if direction == 1 :
nextX= x + 1
nextY= y
if nextX == x_1 and nextY == y_1: continue
if goMaze(nextX,nextY,x,y,1): return True
if direction == 2 :
nextX= x - 1
nextY= y
if nextX == x_1 and nextY == y_1: continue
if goMaze(nextX,nextY,x,y,2): return True
if direction == 4 :
nextX= x
nextY= y + 1
if nextX == x_1 and nextY == y_1: continue
if goMaze(nextX,nextY,x,y,4): return True
if direction == 8 :
nextX= x
nextY= y - 1
if nextX == x_1 and nextY == y_1: continue
if goMaze(nextX,nextY,x,y,8): return True
outputMaze[nextX][nextY] = direction
return False
for i in range(0,len(outputMaze)):
for j in range(i,len(outputMaze[i])):
tmp = outputMaze[i][j]
outputMaze[i][j] = outputMaze[j][i]
outputMaze[j][i] = tmp
outputMaze
import numpy as np
# custum module. Usage:
# A(1,1) + A(2,2) => A(3,3)
# A(x,y) < A(X,Y) => 0<=x<X and 0<=y<Y
from exttuple import ArrayIndex2D as A
# 7 = 1 + 2 + 4 => [(0, 1), (0, -1), (1, 0)]
def dir(d):
info = {1:(0, 1), 2:(0, -1), 4:(1, 0), 8:(-1, 0)}
return [info[k] for k in info if int(d) & k]
# (0, 1) => 1, (0, -1) => 2, ...
def rdir(d):
info = {1:(0, 1), 2:(0, -1), 4:(1, 0), 8:(-1, 0)}
rinfo = {v:k for k, v in info.items()}
return rinfo[d]
# Q, V = queue[(pos, path[])], visited[pos]. 큐에 탈출경로를 같이 저장한다.
def escape_path(arr, X, Y):
Q, V = [(A(0, 0), [])], set()
while Q:
cur, path = Q.pop(0)
for d in dir(arr[cur]):
next = cur + d
if next == (X-1, Y): #탈출
return print_path(path + [(cur, rdir(d))], X, Y)
elif next < (X, Y) and next not in V:
V.add(next)
Q.append((next, path + [(cur, rdir(d))]))
# 탈출경로를 배열에 표시한다.
def print_path(path, X, Y):
res = np.zeros((X, Y), dtype=np.int32)
for pos, d in path:
res[pos] = d
return res
inp_str = ''' 4 5 7 3 6
12 8 12 5 10
9 3 10 12 4
4 5 6 9 14
9 10 9 3 11'''
X, Y = 5, 5
res = escape_path(np.array(inp_str.split()).reshape((X, Y)), X, Y)
print(res)
import numpy as np
from numpy.random import shuffle as sh
class MakeMaze:
def __init__(self, h, w, random_start_on=False, random_end_on=False):
self.h, self.w = 2 * h + 1, 2 * w + 1
self.maze = np.zeros((self.h, self.w))
self.random_start_on = random_start_on
self.set_maze_array()
self.make_maze()
self.maze_list = self.convert_maze_to_list()
self.print_maze()
def set_maze_array(self):
for i in range(self.h):
if i % 2 == 0:
for j in range(self.w):
if j % 2 == 1:
self.maze[i, j] = 1
else:
for j in range(self.w):
if j % 2 == 0:
self.maze[i, j] = 2
else:
self.maze[i, j] = 4
self.maze[1, 0] = 4
if self.random_start_on:
starting_point = (2*np.random.randint(self.h//2)+1, 2*np.random.randint(self.w//2)+1)
else:
starting_point = (-2, -2)
self.maze[starting_point] = 3
def move(self, maze_01, current_point):
h, w = maze_01.shape
x, y = current_point
maze_101 = np.ones((h + 2, w + 2))
maze_101[1:-1, 1:-1] = maze_01
movable_points = []
for i, j in [(-1, 0), (0, -1), (1, 0), (0, 1)]:
if maze_101[x + 1 + i, y + 1 + j] == 0:
movable_points.append((x + i, y + j))
if len(movable_points) == 0:
return maze_01, None
next_point = movable_points[np.random.choice(range(len(movable_points)))]
next_maze = maze_101[1:-1, 1:-1]
next_maze[next_point] = 1
return next_maze, next_point
def make_maze(self):
h, w = self.h // 2, self.w // 2
maze_01 = np.zeros((h, w))
maze_01[0, 0] = 1
path_list = [(0, 0)]
while len(path_list):
current_point = path_list[-1]
maze_01, next_point = self.move(maze_01, current_point)
if next_point is None:
path_list.pop()
continue
break_wall = np.array(current_point) + np.array(next_point) + 1
self.maze[break_wall[0], break_wall[1]] = 4
path_list.append(next_point)
def convert_maze_to_list(self):
maze_list = []
convert_dic = {0: ' + ', 1: '---', 2: ' | ', 3: ' o ', 4: ' ', 5: ' '}
for i in range(self.h):
maze_list_t = []
for j in range(self.w):
maze_list_t.append(convert_dic[self.maze[i, j]])
maze_list.append(maze_list_t)
return maze_list
def print_maze(self):
with open("maze.txt", 'w') as f:
for maze_row in self.maze_list:
for x in maze_row:
f.write(x)
f.write('\n')
for maze_row in self.maze_list:
for x in maze_row:
print(x, end='')
print('')
class EscapeMaze:
def __init__(self, path):
self.path = path
self.h, self.w = 0, 0
self.current_point = []
self.checkpoint = []
self.end_point = []
self.dir = None
self.maze_info, self.maze = self.read_maze()
success = False
while not success:
success = self.move()
self.draw_path()
def read_maze(self):
with open(self.path, 'r') as f:
maze = f.read()
wall_dic = {'+': 0, '-': 1, '|': 2, 'o': 3, ' ': 4}
lines = maze.split('\n')
lines.remove("")
self.h = len(lines)
self.w = len(lines[0].split())
state = np.zeros((self.h, self.w))
for i in range(self.h):
for j in range(self.w):
state[i, j] = wall_dic[lines[i][3*j + 1]]
if i == 0 or i == self.h-1 or j == 0 or j == self.w-1:
if state[i, j] == 4:
state[i, j] = 5
state_info = state.copy()
for i in range(self.h):
for j in range(self.w):
if state[i, j] == 3:
self.current_point.append((i, j))
state[i, j] = 4
elif state[i, j] == 5:
self.end_point.append((i, j))
state[i, j] = 4
elif state[i, j] != 4:
state[i, j] = 0
state_d = state.copy()
for i in range(1, self.h - 1):
for j in range(1, self.w - 1):
if state[i, j] == 4:
state_d[i, j] = 0
if state[i, j - 1] == 4:
state_d[i, j] += 1
if state[i, j + 1] == 4:
state_d[i, j] += 2
if state[i-1, j] == 4:
state_d[i, j] += 4
if state[i + 1, j] == 4:
state_d[i, j] += 8
state_d[self.end_point[0]] = -1
return state_info, state_d
def move(self):
# print(self.maze)
current = self.current_point[-1]
if self.maze[current[0], current[1]] == -1:
return True
dir_dic = {1: [(0, -1)], 2: [(0, 1)], 3: [(0, -1), (0, 1)], 4: [(-1, 0)], 5: [(0, -1), (-1, 0)],
6: [(0, 1), (-1, 0)], 7: [(0, -1), (0, 1), (-1, 0)], 8: [(1, 0)], 9: [(0, -1), (1, 0)],
10: [(0, 1), (1, 0)], 11: [(0, -1), (0, 1), (1, 0)], 12: [(-1, 0), (1, 0)],
13: [(0, -1), (-1, 0), (1, 0)], 14: [(0, 1), (-1, 0), (1, 0)],
15: [(0, -1), (0, 1), (-1, 0), (1, 0)]}
dir_dic_2 = {(0, -1): 1, (0, 1): 2, (-1, 0): 4, (1, 0): 8}
if len(dir_dic[self.maze[current[0], current[1]]]) >= 1:
self.checkpoint.append(current)
next_points = []
for move1 in map(np.array, [(0, 1), (0, -1), (-1, 0), (1, 0)]):
next_point = np.array(current) + move1
if self.maze[next_point[0], next_point[1]] != 0:
mut = False
for cp in self.current_point:
if cp[0] == next_point[0] and cp[1] == next_point[1]:
mut = True
if not mut:
next_points.append((next_point, next_point - np.array(current)))
if len(next_points) == 0:
index = self.current_point.index(self.checkpoint[-1])
for point in self.current_point[index:]:
self.maze[point] = 0
self.current_point = self.current_point[:index]
self.checkpoint.pop()
self.dir = None
return False
sh(next_points)
direction = next_points[-1][1]
next_point = next_points[-1][0]
self.maze[current] -= dir_dic_2[direction[0], direction[1]]
self.current_point.append((next_point[0], next_point[1]))
return False
def draw_path(self):
print("start")
for i in range(len(self.current_point)):
if i % 2 == 0:
print(np.array(self.current_point[i])//2 + 1, end='->')
print("exit")
for point in self.current_point[1:-1]:
self.maze_info[point] = 6
maze_list = []
convert_dic = {0: ' + ', 1: '---', 2: ' | ', 3: ' s ', 4: ' ', 5: ' e ', 6: ' * '}
for i in range(self.h):
maze_list_t = []
for j in range(self.w):
maze_list_t.append(convert_dic[self.maze_info[i, j]])
maze_list.append(maze_list_t)
for maze_row in maze_list:
for x in maze_row:
print(x, end='')
print('')
if __name__ == "__main__":
# hr, wr = map(int, input("높이, 폭의 크기를 입력해주세요. (띄어쓰기로 구분) : ").split())
hr, wr = 15, 15
make_maze = MakeMaze(hr, wr, random_start_on=True)
a = EscapeMaze('maze.txt')
+ --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- +
| | | |
+ --- + --- + --- + --- + + --- + + --- + --- + + + + + + --- +
| | | | | | | | |
+ + + + + --- + + --- + --- + + + + --- + --- + --- + +
| | o | | | | | | | |
+ + --- + --- + --- + + --- + --- + + --- + + + + + + +
| | | | | | | | | | |
+ + + --- + + + --- + + + + + + + + + --- +
| | | | | | | | | | | |
+ + --- + --- + --- + --- + + + + + --- + + + + --- + +
| | | | | | | | | |
+ + + --- + --- + --- + --- + + + + + --- + --- + --- + + +
| | | | | | | | |
+ + + --- + --- + --- + --- + --- + + + + + --- + --- + --- + +
| | | | | | |
+ + --- + --- + --- + --- + + + --- + + --- + + --- + + + +
| | | | | | | | | | |
+ + + + + --- + + + + --- + --- + --- + --- + + + --- +
| | | | | | | | |
+ + + --- + + + + + --- + --- + --- + --- + + + --- + +
| | | | | | | | |
+ + --- + + --- + + + --- + --- + + --- + --- + --- + + + --- +
| | | | | | | | |
+ --- + --- + + + --- + --- + + + + + + --- + --- + --- + +
| | | | | | | | |
+ + --- + + + --- + + --- + --- + --- + --- + --- + + + + +
| | | | | | | | |
+ + + + --- + + --- + + --- + --- + + + --- + + --- + +
| | | | | |
+ --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- +
start
[3 3]->[2 3]->[2 4]->[3 4]->[3 5]->[4 5]->[5 5]->[5 6]->[6 6]->[6 5]->[6 4]->[6 3]->[6 2]->[7 2]->[8 2]->[8 3]->[8 4]->[8 5]->[8 6]->[9 6]->[10 6]->[10 5]->[11 5]->[12 5]->[12 4]->[13 4]->[14 4]->[14 5]->[15 5]->[15 6]->[15 7]->[14 7]->[14 8]->[14 9]->[14 10]->[15 10]->[15 11]->[14 11]->[14 12]->[13 12]->[13 11]->[12 11]->[12 10]->[13 10]->[13 9]->[12 9]->[11 9]->[11 8]->[11 7]->[10 7]->[9 7]->[8 7]->[8 8]->[7 8]->[6 8]->[5 8]->[4 8]->[3 8]->[3 7]->[3 6]->[2 6]->[2 5]->[1 5]->[1 4]->[1 3]->[1 2]->[1 1]->exit
+ --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- +
e * * * * * * * * * | | | |
+ --- + --- + --- + --- + * + --- + + --- + --- + + + + + + --- +
| | * * * | * * * | | | | | |
+ + + * + * + --- + * + --- + --- + + + + --- + --- + --- + +
| | s | * * * | * * * * * | | | | | |
+ + --- + --- + --- + * + --- + --- + * + --- + + + + + + +
| | | * | * | | | | | | |
+ + + --- + + * + --- + + * + + + + + + + --- +
| | | * * * | | * | | | | | | |
+ + --- + --- + --- + --- + * + + * + + --- + + + + --- + +
| | * * * * * * * * * | | * | | | | | |
+ + * + --- + --- + --- + --- + + * + + + --- + --- + --- + + +
| | * | | * | | | | |
+ + * + --- + --- + --- + --- + --- + * + + + + --- + --- + --- + +
| | * * * * * * * * * | * * * | | | |
+ + --- + --- + --- + --- + * + * + --- + + --- + + --- + + + +
| | | | * | * | | | | | |
+ + + + + --- + * + * + + --- + --- + --- + --- + + + --- +
| | | | * * * | * | | | |
+ + + --- + + * + + * + --- + --- + --- + --- + + + --- + +
| | | | * | | * * * * * | | |
+ + --- + + --- + * + + --- + --- + * + --- + --- + --- + + + --- +
| | * * * | | | * | * * * | | |
+ --- + --- + + * + --- + --- + + + * + * + * + --- + --- + --- + +
| | | * | | * * * | * * * | | |
+ + --- + + * + --- + + --- + --- + --- + --- + --- + * + + + +
| | | * * * | | * * * * * * * | * * * | | |
+ + + + --- + * + --- + * + --- + --- + * + * + --- + + --- + +
| | | * * * * * | * * * | |
+ --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- + --- +