コンソールでライフゲーム(Ruby)

Ruby の Gem でコンソールをウィンドウのように使える 'curses' というのがあります。これを使ってみたくて、ライフゲームを書いてみました。Linux Mint 18.2, Ruby 2.3.3 で確認しています。(追記:Window 8.1, Ruby 2.2.2 [i386-mingw32] でも確認しました。)
 

 
Gem のインストールは $ gem install curses で OK です。


Gem 'curses' の使い方は下のリンク先でほぼ充分でした。

 

lifegame_console.rb

require 'curses'

class LifeGame
  class Field
    def initialize(width, height)
      @width, @height = width, height
      @window = Curses::Window.new(height, width, 0, 0)
      @window.timeout = 0    #キー入力をノンブロッキングにする
    end
    
    def generate(n)
      @field = Array.new(@height + 2) {Array.new(@width + 2, 0)}
      n.times {@field[rand(@height) + 1][rand(@width) + 1] = 1}
    end
    
    def show
      @window.clear
      @height.times do |h|
        @width.times do |w|
          if @field[h + 1][w + 1] == 1
            @window.attrset(Curses.color_pair(1))
            @window.attron(Curses::A_BOLD)
            @window.setpos(h, w)
            @window.addstr("*")
          end
        end
      end
      @window.refresh
    end
    
    def next
      tmp = Array.new(@height + 2) {Array.new(@width + 2, 0)}
      @height.times do |h|
        @width.times do |w|
          n = @field[h + 1][w] + @field[h + 1][w + 2] +
                @field[h][w + 1] + @field[h][w] + @field[h][w + 2] +
                @field[h + 2][w + 1] + @field[h + 2][w] + @field[h + 2][w + 2]
          if @field[h + 1][w + 1].zero?
            tmp[h + 1][w + 1] = 1 if n == 3
          else
            tmp[h + 1][w + 1] = 1 if n == 2 or n == 3
          end
        end
      end
      @field = tmp
    end
    
    def key_in
      key = @window.getch
      return false if key == " "
      if key == "e"
        Curses.close_screen
        exit
      end
      true
    end
  end
  
  def initialize(width, height)
    Curses.init_screen
    Curses.cbreak
    Curses.noecho
    Curses.start_color
    Curses.init_pair(1, Curses::COLOR_GREEN, Curses::COLOR_BLACK)
    Curses.curs_set(0)    #カーソルを表示しない
    @f = Field.new(width, height)
  end
  
  def main
    loop do
      @f.generate(180)
      while @f.key_in
        @f.show
        @f.next
        sleep(0.3)
      end
    end
  end
end

LifeGame.new(60, 20).main

スペースキーであたらしいライフゲームを始めます。終了は [e] または [Ctrl] + [C] で行って下さい。

以前に表示を GTK+ で行うライフゲームを書いています。