DEFINITIONS
This source file includes following functions.
1 #! /usr/bin/ruby -Ke
2
3 class Board
4 def clr
5 print "\e[2J"
6 end
7 def pos(x,y)
8 printf "\e[%d;%dH", y+1, x*2+1
9 end
10 def colorstr(id,s)
11 printf "\e[%dm%s\e[0m", id, s
12 end
13 def put(x, y, col, str)
14 pos(x,y); colorstr(43,str)
15 pos(0,@hi); print "残り:",@mc,"/",@total," "
16 pos(x,y)
17 end
18 private :clr, :pos, :colorstr, :put
19 CHR=["・","1","2","3","4","5","6","7","8","★","●","@@"]
20 COL=[46,43,45] # default,opened,over
21 def initialize(h,w,m)
22 # ゲーム盤の生成(h:縦,w:横,m:爆弾の数)
23 @hi=h; @wi=w; @m=m
24 reset
25 end
26 def reset
27 # ゲーム盤を(再)初期化する
28 srand()
29 @cx=0; @cy=0; @mc=@m
30 @over=false
31 @data=Array.new(@hi*@wi)
32 @state=Array.new(@hi*@wi)
33 @total=@hi*@wi
34 @total.times {|i| @data[i]=0}
35 @m.times do
36 loop do
37 j=rand(@total-1)
38 if @data[j] == 0 then
39 @data[j]=1
40 break
41 end
42 end
43 end
44 clr; pos(0,0)
45 @hi.times{|y| pos(0,y); colorstr(COL[0],CHR[0]*@wi)}
46 pos(@cx,@cy)
47 end
48 def mark
49 # 現在のカーソル位置にマークをつける
50 if @state[@wi*@cy+@cx] != nil then return end
51 @state[@wi*@cy+@cx] = "MARK"
52 @mc=@mc-1;
53 @total=@total-1;
54 put(@cx, @cy, COL[1], CHR[9])
55 end
56 def open(x=@cx,y=@cy)
57 # 現在のカーソル位置をオープンにする
58 # 爆弾があればゲームオーバー
59 if @state[@wi*y+x] =="OPEN" then return 0 end
60 if @state[@wi*y+x] == nil then @total=@total-1 end
61 if @state[@wi*y+x] =="MARK" then @mc=@mc+1 end
62 @state[@wi*y+x]="OPEN"
63 if fetch(x,y) == 1 then @over = 1; return end
64 c = count(x,y)
65 put(x, y, COL[1], CHR[c])
66 return 0 if c != 0
67 if x > 0 && y > 0 then open(x-1,y-1) end
68 if y > 0 then open(x, y-1) end
69 if x < @wi-1 && y > 0 then open(x+1,y-1) end
70 if x > 0 then open(x-1,y) end
71 if x < @wi-1 then open(x+1,y) end
72 if x > 0 && y < @hi-1 then open(x-1,y+1) end
73 if y < @hi -1 then open(x,y+1) end
74 if x < @wi-1 && y < @hi-1 then open(x+1,y+1) end
75 pos(@cx,@cy)
76 end
77 def fetch(x,y)
78 # (x,y)の位置の爆弾の数(0 or 1)を返す
79 if x < 0 then 0
80 elsif x >= @wi then 0
81 elsif y < 0 then 0
82 elsif y >= @hi then 0
83 else
84 @data[y*@wi+x]
85 end
86 end
87 def count(x,y)
88 # (x,y)に隣接する爆弾の数を返す
89 fetch(x-1,y-1)+fetch(x,y-1)+fetch(x+1,y-1)+
90 fetch(x-1,y) + fetch(x+1,y)+
91 fetch(x-1,y+1)+fetch(x,y+1)+fetch(x+1,y+1)
92 end
93 def over(win)
94 # ゲームの終了
95 quit
96 unless win
97 pos(@cx,@cy); print CHR[11]
98 end
99 pos(0,@hi)
100 if win then print "*** YOU WIN !! ***"
101 else print "*** GAME OVER ***"
102 end
103 end
104 def over?
105 # ゲームの終了チェック
106 # 終了処理も呼び出す
107 remain = (@mc+@total == 0)
108 if @over || remain
109 over(remain)
110 true
111 else
112 false
113 end
114 end
115 def quit
116 # ゲームの中断(または終了)
117 # 盤面を全て見せる
118 @hi.times do|y|
119 pos(0,y)
120 @wi.times do|x|
121 colorstr(if @state[y*@wi+x] == "MARK" then COL[1] else COL[2] end,
122 if fetch(x,y)==1 then CHR[10] else CHR[count(x,y)] end)
123 end
124 end
125 end
126 def down
127 # カーソルを下に
128 if @cy < @hi-1 then @cy=@cy+1; pos(@cx, @cy) end
129 end
130 def up
131 # カーソルを上に
132 if @cy > 0 then @cy=@cy-1; pos(@cx, @cy) end
133 end
134 def left
135 # カーソルを左に
136 if @cx > 0 then @cx=@cx-1; pos(@cx, @cy) end
137 end
138 def right
139 # カーソルを右に
140 if @cx < @wi-1 then @cx=@cx+1; pos(@cx, @cy) end
141 end
142 end
143
144 bd=Board.new(10,10,10)
145 system("stty raw -echo")
146 begin
147 loop do
148 case STDIN.getc
149 when ?n # new game
150 bd.reset
151 when ?m # mark
152 bd.mark
153 when ?j
154 bd.down
155 when ?k
156 bd.up
157 when ?h
158 bd.left
159 when ?l
160 bd.right
161 when ?\s
162 bd.open
163 when ?q,?\C-c # quit game
164 bd.quit
165 break
166 end
167 if bd.over?
168 if STDIN.getc == ?q then break end
169 bd.reset
170 end
171 end
172 ensure
173 system("stty -raw echo")
174 end
175 print "\n"