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