巷ではRubyで「あみだくじ」を書くのが流行っているのですね。僕も便乗します。但し、無制限一本勝負で^ ^; Cursesを使ってみました。
[フレーム]require "curses"
class Amida
include Curses
def initialize(opt={})
opt = opt_check(opt)
n = opt[:member]
@members = ('A'..'Z').take(n)
@margin = opt[:margin]
@height = opt[:length]
@width = n + @margin*(n-1)
@ladders = set_ladders(n)
@wins = set_win(n, (opt[:win]))
end
def draw
draw_with_curses do |bx, by|
draw_headline(bx, by, 0.1)
draw_vlines(bx, by, 0.05)
draw_win(bx, by, 0.2)
draw_ladders(bx, by, 0.05)
end
end
private
def opt_check(opt)
m = opt[:member] || 5
init_screen
h = { member: [26,5],
margin: [cols/m,3],
length: [lines-5,5],
win: [m,1] }
h.each do |key, (max, defo)|
val = opt[key]
raise "#{key} value `#{val}` is out of range(max: #{max})." if val && val > max
opt.update({key => (val || defo)})
end
opt
end
def set_ladders(n)
ladders = Array.new(@height) { Array.new(n-1, false) }
is_true_pair = ->l{ l.each_cons(2).any? { |pair| pair.all? } }
ladders.map! do |line|
while line.none? || is_true_pair[line]
line = line.map { |lad| rand <= 0.6 }
end
line
end
end
def set_win(n, wins)
[*0...n].shuffle.pop(wins)
end
def draw_with_curses(bx=nil, by=nil)
init_screen
start_color
init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK)
init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK)
init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK)
yield (bx || cols/2-@width/2), (by || lines/2-@height/2)
setpos(0,0)
getch
ensure
close_screen
end
def draw_headline(x, y, sp)
@members.each do |m|
sleep(sp)
setpos(y, x)
attron(color_pair(COLOR_GREEN)|A_BOLD) {
addstr(m.to_s)
}
refresh
x += @margin+1
end
end
def draw_vlines(x, y, sp)
@members.each do
pos_y = y + 1
@height.times do |i|
sleep(sp)
setpos(pos_y+i, x)
addch('|')
refresh
end
x += @margin+1
end
end
def draw_ladders(x, y, sp)
pos_y = y + 1
@ladders.each_with_index do |line, i|
pos_x = x + 1
line.each do |lad|
sleep(sp)
setpos(pos_y+i, pos_x)
addstr('-'*@margin) if lad
refresh
pos_x += @margin + 1
end
end
end
def draw_win(x, y, sp)
pos_y = y + @height + 1
@wins.each_with_index do |win, i|
sleep(sp)
pos_x = x + win * (@margin+1)
setpos(pos_y, pos_x)
attron(color_pair COLOR_RED) {
addstr("#{i+1}")
}
refresh
end
end
end
args = ARGV.map(&:to_i)
args = Array.new(3).map { args.shift }
opt = Hash[ [:member, :win, :length].zip(args) ]
am = Amida.new(opt)
am.draw