From: toyofuku@... Date: 1998-06-05T20:20:06+09:00 Subject: [ruby-list:8206] mine sweeper 豊福@パパイヤです。 昔のメールを読んでいたら酒本さんのキャラクタ版 マインスイーパというのがあったので動してみたら 面白かったので少し拡張しました。 酒本さん [ruby-list:6920] Re: call for scripts > 漢字、カラー対応の端末でないと遊べませんが、 > マインスイーパのキャラクタ版です。 ... > おきて破りのエスケープシーケンスを使っています。 > > 移動 :h j k l > マーク :m > newゲーム :n > 終了 :q > 開ける : スペース これに加えて 回りを開ける :o (Windows版の左右マウスボタン同時クリックの機能) またマークがすでについているセルで m すると マークが消えるようにしました。 処理を簡単にするために勝手ながらプログラムに 手を入れました。その際気になったことがいくつか あったので教えて下さい。 ・ボードの周囲に sentinel を配置しやすくするため と気軽に二次元ぽく書くために @data[y*@hi+x] を @data[[x,y]] のように配列をキーとしたハッシュに 書きかえたが問題ないか。 ・状態を表現する値を "OPEN" のような文字列から :open のような値に書きかえたが ruby流ではどう 書くのか。 それともう一つ。gnuwin32 では stty raw が効か ないため動かないのですがよい対処方はありませんか。 #!/usr/local/bin/ruby def clr "\e[2J" end def pos(x,y) "\e["+(y+1).to_s+";"+(x*2+1).to_s+"H" end def clrstr(id,s) "\e["+id.to_s+"m"+s+"\e[0m" end class Board def initialize(h,w,m) @num=["・","1","2","3","4","5","6","7","8"] @hi=h; @wi=w; @m=m @alldir = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]] reset end def reset srand() @cx=0; @cy=0; @mc=@m; @total=@hi*@wi @data={} @state={} -1.upto(@hi) {|y| -1.upto(@wi) {|x| xy = [x,y] if (x >= 0 && x < @wi && y >= 0 && y < @hi) @data[xy]=0; @state[xy]=:null; else @data[xy]=-100; @state[xy]=:border; end }} @m.times{ while true j=rand(@hi*@wi-1) y, x = j.divmod(@wi) xy = [x,y] if @data[xy] <= 8 @data[xy]=100 @alldir.each {|dx,dy| @data[[x+dx,y+dy]] += 1 } break end end } print clr , pos(0,0) 0.upto(@hi-1){|y| print pos(0,y),clrstr(46,"・"*@wi)} print pos(@cx,@cy) end def mark xy = [@cx,@cy] if @state[xy] == :mark print pos(@cx,@cy),clrstr(46,"・") @state[xy] = :null @mc += 1 @total += 1 elsif @state[xy] == :null print pos(@cx,@cy),clrstr(43,"★") @state[xy] = :mark @mc -= 1 @total -= 1 else return end move end def open(x=@cx,y=@cy) xy = [x,y] return 0 if @state[xy]!=:null @total -= 1 @state[xy]=:open c = @data[xy] return 1 if c > 8 print pos(x,y),clrstr(43,@num[c]) if c == 0 @alldir.each {|dx,dy| open(x+dx, y+dy) } end move return 0 end def open_neighbor(x=@cx,y=@cy) xy = [x,y] return if @state[xy] != :open sum = 0 @alldir.each {|dx,dy| if @state[[x+dx,y+dy]] == :mark sum += 1 end } if sum == @data[xy] @alldir.each {|dx,dy| open(x+dx, y+dy) } end end def over(e) 0.upto(@hi-1){ |y| print pos(0,y) 0.upto(@wi-1){ |x| xy = [x,y] if (@cx==x) &&( @cy==y) && e==1 then print "@@" else m= @data[xy] > 8 ? "●": @num[@data[xy]] print clrstr((@state[xy] != :mark ? 45: 43),m) end } } if e==1 then print pos(0,@hi),"*** OVER ***" else print pos(0,@hi),"*** YOU WIN !! ***" end end def move print pos(0,@hi),"残り:",@mc,"/",@total," " print pos(@cx,@cy) end def trymove(dx, dy) newx = @cx + dx; newy = @cy + dy if @state[[newx,newy]] != :border @cx = newx; @cy = newy move end end def quit print pos(0,@hi) end def remain @mc+@total end end bd=Board.new(10,10,10) system("stty raw -echo") while(c=getc).chr != "q" case c.chr when "n" # new game bd.reset when "m" # mark bd.mark when "j" bd.trymove(0,1) when "k" bd.trymove(0,-1) when "h" bd.trymove(-1,0) when "l" bd.trymove(1,0) when "o" bd.open_neighbor when " " if bd.open == 1 then bd.over(1) if (c=getc).chr == "q" then break end bd.reset end end if bd.remain==0 then bd.over(0) if (c=getc).chr == "q" then break end bd.reset end end bd.quit system("stty -raw echo") print "\n" --- 豊福@パパイヤ unbound@papaya.juice.or.jp toyofuku@juice.or.jp