Juwan Park :: 자동 미로 생성 예제

자동 미로 생성 예제

★프로그래밍/Ruby :: 2015. 9. 20. 15:50

루비로 구현해 본 자동 미로 생성 예제입니다.

구현된 알고리즘은 깊이 우선 탐색법(DFS; Depth First Search)을 이용한 알고리즘입니다.
지정된 랜덤 방향으로 계속해서 뚫어 나가다가 더 이상 뚫을 수 없게 되면 뒤로 돌아가면서 뚫을 수 있는 곳이 발견되면 다시 뚫어 나가는 구조입니다. 깊이 우선 방식이므로 재귀호출을 이용합니다.

이 방법으로 미로를 만들게 되면 항상 다음과 같은 특징을 갖게 됩니다.
- 미로판 전체에 미로가 생성됨.
- 미로판 어느 곳이든 이동이 가능함.
- 특정 위치에서 특정 위치로 이동하는 문제에 대하여 단 하나의 해만 존재함.

다음은 DFS 자동 미로 예제 코드입니다.

# 자동 미로 생성 예제 (DFS)
class Maze
  # 설정할 값
  CHR_WALL    = "■"
  CHR_EMPTY   = "  "
  CHR_SOLVE   = "○"
  MAZE_WIDTH  = 18        # 미로의 가로 칸 수
  MAZE_HEIGHT = 10        # 미로의 세로 칸 수
  VIEW_SOLUTION = true    # false로 설정하면 해를 표시하지 않음
  
  # 미로 초기설정
  def initialize
    @maze_order = [1, 2, 4, 8]    # 미로 순서 (1하, 2좌, 3우, 4상)
    # 미로판 배열 정의
    @maze_way = Array.new(MAZE_HEIGHT) { Array.new(MAZE_WIDTH, 0) }
    @maze_sway = Array.new(MAZE_HEIGHT) { Array.new(MAZE_WIDTH, false) }
    @maze_solved = false          # 도착지까지 가면 true
  end
  
  # 미로 생성하기 (재귀호출)
  def road_make(y, x)
    @maze_sway[y][x] = true if !@maze_solved && VIEW_SOLUTION
    @maze_solved = true if x == MAZE_WIDTH - 1 && y == MAZE_HEIGHT - 1
    @maze_order.shuffle!    # 미로 뚫는 순서 섞기
    oo = 0                  # 미로 순서 배열 참조용 변수
    while oo <= 3           # 뚫을 방향이 없을 때까지 반복
      xx = x                # 뚫을 x좌표 지정 변수
      yy = y                # 뚫을 y좌표 지정 변수
      noway = true          # 뚫을 수 없음을 지정할 진리변수
      
      case @maze_order[oo]    # 방향에 따른 분기
      when 1
        # 아래(1): 맨 아래가 아닐 경우만 유효
        if y < MAZE_HEIGHT - 1
          yy += 1
          noway = false
        end
      when 2
        # 왼쪽(2): 맨 왼쪽이 아닐 경우만 유효
        if x > 0
          xx -= 1
          noway = false
        end
      when 4
        # 오른쪽(4): 맨 오른쪽이 아닐 경우만 유효
        if x < MAZE_WIDTH - 1
          xx += 1
          noway = false
        end
      when 8
        # 위(8): 맨 위가 아닐 경우만 유효
        if y > 0
          yy -= 1
          noway = false
        end
      end
      
      if !noway && @maze_way[yy][xx] == 0
        # 방향이 유효하고 뚫을 목적지가 비어 있어야 처리
        @maze_way[y][x] += @maze_order[oo]            # 지정 방향으로 뚫기
        @maze_way[yy][xx] += (8 / @maze_order[oo])    # 목적지는 반대로
        road_make(yy, xx)    # 목적지 좌표로 재귀호출
      else
        oo += 1    # 뚫지 못하면 방향 차례를 넘김
      end
    end
    @maze_sway[y][x] = false if !@maze_solved
  end
  
  # 생성된 미로 출력
  def maze_print
    pchar = ""    # 출력용 문자열
    
    # 세로 칸 수만큼 반복
    for i in 0..(MAZE_HEIGHT - 1)
      # 가로 칸 수만큼 반복
      for j in 0..(MAZE_WIDTH - 1)
        # 위쪽(8)이 뚫려 있는가의 여부 검사
        pchar = CHR_WALL
        if @maze_way[i][j] >= 8
          if @maze_sway[i-1][j] && @maze_sway[i][j]
            # 뚫려 있음 + 해
            pchar += CHR_SOLVE
          else
            # 뚫려 있음 + 해 아님
            pchar += CHR_EMPTY
          end
        else
          # 뚫려 있지 않음
          pchar += CHR_WALL
        end
        pchar = "출발" if i == 0 && j == 0
        print pchar
      end
      print CHR_WALL + "\n"    # 맨 우측벽 출력
      
      for j in 0..(MAZE_WIDTH - 1)
        if @maze_way[i][j] % 4 >= 2
          # 왼쪽(2)이 뚫려 있는가의 여부 검사
          if @maze_sway[i][j-1] && @maze_sway[i][j]
            # 뚫려 있음 + 해
            pchar = CHR_SOLVE
          else
            # 뚫려 있음 + 해 아님
            pchar = CHR_EMPTY
          end
        else
          # 뚫려 있지 않음
          pchar = CHR_WALL
        end
        # 해 검사
        @maze_sway[i][j] ? pchar += CHR_SOLVE : pchar += CHR_EMPTY
        print pchar
      end
      print CHR_WALL + "\n"    # 맨 우측벽 출력
    end
    
    # 맨 아래쪽 벽을 출력
    print CHR_WALL * (MAZE_WIDTH * 2 - 1) + "도착"
    puts
  end
  
  # 미로 생성 시작
  def maze_start
    road_make(0, 0)
    maze_print
  end
end

# 미로 시작
mz=Maze.new
mz.maze_start

아래는 이 코드를 실행한 스크린샷입니다.

유용하게 활용하시기 바랍니다.

Today    Yday    Tot
Juwan Park
Juwan Park's blog is powered by Daum and .
Contemporary Blue for .
Designed by Juwan Park. Creative Commons License
▲ TOP