[ruby-talk:00935] Re: Curios About "ruby"?
From:
matz@... (Yukihiro Matsumoto)
Date:
1999-11-25 14:27:50 UTC
List:
ruby-talk #935
Hi,
In message "[ruby-talk:00933] Re: Curios About "ruby"?"
on 99/11/25, Clemens Hintze <c.hintze@gmx.net> writes:
|matz, you have said that the example programs of your book would be
|available via FTP, when the book is in the store.
|
|I assume, it is already. Do you plan to put them anywhere to
|ruby-lang.org? :-)))
Oh, well. I forgot. Here's one; I put the rest after I translated
comments in the scripts.
- simple mine sweeper.
Keys
hjkl: cursor move (vi move)
m: put mark at the cursor
space: open at the cursor
q: quit
--
#! /usr/bin/ruby
class Board
def clr
print "\e[2J"
end
def pos(x,y)
printf "\e[%d;%dH", y+1, x+1
end
def colorstr(id,s)
printf "\e[%dm%s\e[0m", id, s
end
def put(x, y, col, str)
pos(x,y); colorstr(43,str)
pos(0,@hi); print "Left:",@mc,"/",@total," "
pos(x,y)
end
private :clr, :pos, :colorstr, :put
CHR=[" ","1","2","3","4","5","6","7","8","X","*","@"]
COL=[46,43,45] # default,opened,over
def initialize(h,w,m)
# board generation(h:hight,w:width,m:number of mines)
@hi=h; @wi=w; @m=m
reset
end
def reset
# (re)initialize game board
srand()
@cx=0; @cy=0; @mc=@m
@over=false
@data=Array.new(@hi*@wi)
@state=Array.new(@hi*@wi)
@total=@hi*@wi
@total.times {|i| @data[i]=0}
@m.times do
loop do
j=rand(@total-1)
if @data[j] == 0 then
@data[j]=1
break
end
end
end
clr; pos(0,0)
@hi.times{|y| pos(0,y); colorstr(COL[0],CHR[0]*@wi)}
pos(@cx,@cy)
end
def mark
# put mark at current cursor position
if @state[@wi*@cy+@cx] != nil then return end
@state[@wi*@cy+@cx] = "MARK"
@mc=@mc-1;
@total=@total-1;
put(@cx, @cy, COL[1], CHR[9])
end
def open(x=@cx,y=@cy)
# open at current cursor position.
# gameover if there's mine at the cursor
if @state[@wi*y+x] =="OPEN" then return 0 end
if @state[@wi*y+x] == nil then @total=@total-1 end
if @state[@wi*y+x] =="MARK" then @mc=@mc+1 end
@state[@wi*y+x]="OPEN"
if fetch(x,y) == 1 then @over = 1; return end
c = count(x,y)
put(x, y, COL[1], CHR[c])
return 0 if c != 0
if x > 0 && y > 0 then open(x-1,y-1) end
if y > 0 then open(x, y-1) end
if x < @wi-1 && y > 0 then open(x+1,y-1) end
if x > 0 then open(x-1,y) end
if x < @wi-1 then open(x+1,y) end
if x > 0 && y < @hi-1 then open(x-1,y+1) end
if y < @hi -1 then open(x,y+1) end
if x < @wi-1 && y < @hi-1 then open(x+1,y+1) end
pos(@cx,@cy)
end
def fetch(x,y)
# number of mines (0 or 1) at the position(x,y).
if x < 0 then 0
elsif x >= @wi then 0
elsif y < 0 then 0
elsif y >= @hi then 0
else
@data[x*@wi+y]
end
end
def count(x,y)
# number of mines at neighboring sections around (x,y).
fetch(x-1,y-1)+fetch(x,y-1)+fetch(x+1,y-1)+
fetch(x-1,y) + fetch(x+1,y)+
fetch(x-1,y+1)+fetch(x,y+1)+fetch(x+1,y+1)
end
def over(win)
# gameover
quit
unless win
pos(@cx,@cy); print CHR[11]
end
pos(0,@hi)
if win then print "YOU WIN!!"
else print "GAME OVER"
end
end
def over?
# gameover check.
remain = (@mc+@total == 0)
if @over || remain
over(remain)
true
else
false
end
end
def quit
# quit the game. open the board.
@hi.times do|y|
pos(0,y)
@wi.times do|x|
colorstr(if @state[y*@wi+x] == "MARK" then COL[1] else COL[2] end,
if fetch(x,y)==1 then CHR[10] else CHR[count(x,y)] end)
end
end
end
def down
# move down the cursor.
if @cy < @hi-1 then @cy=@cy+1; pos(@cx, @cy) end
end
def up
# move up the cursor.
if @cy > 0 then @cy=@cy-1; pos(@cx, @cy) end
end
def left
# move left the cursor.
if @cx > 0 then @cx=@cx-1; pos(@cx, @cy) end
end
def right
# move right the cursor.
if @cx < @wi-1 then @cx=@cx+1; pos(@cx, @cy) end
end
end
bd=Board.new(10,10,10)
system("stty raw -echo")
begin
loop do
case STDIN.getc
when ?n # new game
bd.reset
when ?m # mark
bd.mark
when ?j
bd.down
when ?k
bd.up
when ?h
bd.left
when ?l
bd.right
when ?\s
bd.open
when ?q,?\C-c # quit game
bd.quit
break
end
if bd.over?
if STDIN.getc == ?q then break end
bd.reset
end
end
ensure
system("stty -raw echo")
end
print "\n"