Skip to content
This repository
Fetching contributors…

Cannot retrieve contributors at this time

file 175 lines (173 sloc) 3.995 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
#! /usr/bin/ruby -Ke

class Board
  def clr
    print "\e[2J"
  end
  def pos(x,y)
    printf "\e[%d;%dH", y+1, x*2+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 "残り:",@mc,"/",@total," "
    pos(x,y)
  end
  private :clr, :pos, :colorstr, :put
  CHR=["・","1","2","3","4","5","6","7","8","★","●","@@"]
  COL=[46,43,45] # default,opened,over
  def initialize(h,w,m)
    # ゲーム盤の生成(h:縦,w:横,m:爆弾の数)
    @hi=h; @wi=w; @m=m
    reset
  end
  def reset
    # ゲーム盤を(再)初期化する
    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
    # 現在のカーソル位置にマークをつける
    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)
    # 現在のカーソル位置をオープンにする
    # 爆弾があればゲームオーバー
    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)
    # (x,y)の位置の爆弾の数(0 or 1)を返す
    if x < 0 then 0
    elsif x >= @wi then 0
    elsif y < 0 then 0
    elsif y >= @hi then 0
    else
      @data[y*@wi+x]
    end
  end
  def count(x,y)
    # (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)
    # ゲームの終了
    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?
    # ゲームの終了チェック
    # 終了処理も呼び出す
    remain = (@mc+@total == 0)
    if @over || remain
      over(remain)
      true
    else
      false
    end
  end
  def quit
    # ゲームの中断(または終了)
    # 盤面を全て見せる
    @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
    # カーソルを下に
    if @cy < @hi-1 then @cy=@cy+1; pos(@cx, @cy) end
  end
  def up
    # カーソルを上に
    if @cy > 0 then @cy=@cy-1; pos(@cx, @cy) end
  end
  def left
    # カーソルを左に
    if @cx > 0 then @cx=@cx-1; pos(@cx, @cy) end
  end
  def right
    # カーソルを右に
    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"
Something went wrong with that request. Please try again.