2009年8月7日金曜日

壁のばし方で迷路を作ってみた

maze.rb
#!/usr/bin/env ruby
# -*- encoding: utf-8 -*-

require 'rubygems'
require 'win32console'
require 'term/ansicolor'

include Win32::Console::ANSI
include Term::ANSIColor

class Maze
PATHWAY = 1
WALL = 2

attr_accessor :width, :height

def initialize(width, height)
@width = width * 2 + 1
@height = height * 2 + 1
@map = [ PATHWAY ] * @width * @height
@console = Win32::Console.new(STD_OUTPUT_HANDLE)

prologue
dig
epilogue
end

def prologue
@console.Cls
print on_white
dig_edge
end

def epilogue
print reset
@console.Cursor(0, 1)
print ' '
@console.Cursor(@width - 1, @height - 2)
print ' '
@console.Cursor(0, @height + 1)
end

def dig
loop do
w0, w1 = select_next
break unless w0
set_wall(*w0)
set_wall(*w1)
loop do
w0, w1 = candidates(*w1)
break unless w0
set_wall(*w0)
set_wall(*w1)
sleep 0
end
end
end

def select_next
r = walls
loop do
i = rand(r.size)
x, y = r[i]
r.delete_at(i)
z = candidates(x, y)
return z if z
break if r.empty?
end
end

def candidates(x, y)
c = []
f0(c, x + 1, y, x + 2, y)
f0(c, x - 1, y, x - 2, y)
f0(c, x, y + 1, x, y + 2)
f0(c, x, y - 1, x, y - 2)
c[rand(c.size)] unless c.empty?
end

def f0(z, x, y, x1, x2)
if PATHWAY == self[x1, x2]
z << [ [x, y], [x1, x2] ]
end
end

def walls
r = []
0.step(@height - 1, 2) do |y|
0.step(@width - 1, 2) do |x|
r << [x, y] if WALL == self[x, y]
end
end
r
end

def dig_edge
x = @width - 1
@height.times do |y|
set_wall(0, y)
set_wall(x, y)
end

y = @height - 1
@width.times do |x|
set_wall(x, 0)
set_wall(x, y)
end
end

def set_wall(x, y)
@map[x + y * @width] = WALL
@console.Cursor(x, y)
print ' '
end

def [](x, y)
return nil if x < 0 || @width <= x
return nil if y < 0 || @height <= y
@map[x + y * @width]
end
end

m = Maze.new(39, 30)

0 件のコメント:

コメントを投稿