ちなみに

火曜日の空は僕を押しつぶした。

今更、ライフゲーム

ハチロク世代の話題にあがったと聞いたのでワンテンポ遅れて、どう書く?.orgのお題をやってみた。

life_game.rb

#! /usr/bin/env ruby

class LifeGame
  VERSION = "0.0.3"
  DEFAULT_BOARD = [
    [0, 1, 0, 0, 0, 0, 1, 1, 1, 0,],
    [0, 0, 0, 0, 1, 0, 0, 1, 1, 0,],
    [0, 0, 0, 1, 0, 0, 1, 0, 1, 0,],
    [1, 0, 1, 1, 0, 0, 1, 0, 0, 0,],
    [0, 1, 0, 0, 0, 0, 0, 0, 1, 0,],
    [1, 0, 0, 0, 1, 0, 1, 1, 0, 1,],
    [0, 1, 0, 0, 0, 0, 1, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 1,],
    [1, 0, 0, 0, 0, 0, 1, 0, 0, 1,],
    [0, 0, 0, 0, 1, 1, 0, 0, 1, 0,],
  ]
  CACHE_MEMORY = 100
  ALIVE        = " - "
  DEAD         = "   "

  def initialize(board = nil)
    @board       = board || DEFAULT_BOARD
    @board_size  = @board.size
    @cache_board = Array.new CACHE_MEMORY
    @time        = 0
    @realtime    = 0

    @cls = `clear`
  end

  def create_world
    list =
      "i) increment time\n" +
      "d) decrement time\n" +
      "q) quit program\n"

    auto_mode  = false
    auto_count = 0
    sleep_time = 0.1

    loop do
      print @cls
      print_world
      puts "time : #{@time} (real : #{@realtime})"
      puts list

      unless auto_mode
        print "> "
        case gets.chomp
        when "i" 
          increment_time
        when "d" 
          decrement_time
        when "q"
          exit
        when "a"
          auto_mode = true
          print "how? > "
          auto_count = gets.chomp.to_i
        when "s"
          puts "#{sleep_time}"
          print "sleep time = "
          sleep_time = gets.chomp.to_f
        end
      else
        increment_time
        sleep sleep_time
        if (auto_count -= 1) <= 0
          auto_mode = false
        end
      end
    end
  end

  def increment_time
    @time += 1
    @realtime = @time
    push_cache @board
    do_life
  end

  def decrement_time
    if @time > 0 && @realtime - @time < CACHE_MEMORY
      @time -= 1
      @board = pop_cache
    else
      print_error "time cannot be returned any more."
    end
  end

  def print_world
    @board.each do |y|
      row = ""
      y.each do |p|
        if p == 0
          row += DEAD
        else
          row += ALIVE
        end
      end
      puts row
    end
  end

  private
  @cache_count

  def print_error(message)
    puts @cls, "erro : #{message}"
    puts "press any key to continue"
    gets
  end

  def push_cache(board)
    @cache_count = @cache_count ? @cache_count + 1 : 0
    if @cache_count > CACHE_MEMORY - 1
      @cache_count = 0
    end
    @cache_board[@cache_count] = board
  end

  def pop_cache
    board = @cache_board[@cache_count]
    if @cache_count == 0
      @cache_count = CACHE_MEMORY - 1
    else
      @cache_count -= 1
    end
    board
  end

  def _i(val)
    val = 0 if val >= @board_size
    val
  end

  def life_or_die(now, sum)
    if sum == 2
      now
    elsif sum == 3
      1
    else
      0
    end
  end

  def do_life
    next_board = []
    @board_size.times do |y|
      row = Array.new(@board_size)
      @board_size.times do |x|
        tmp = (-1..1).map {|i|
            (-1..1).map {|j| @board[_i(y+i)][_i(x+j)] }
        }.flatten
        now = @board[y][x]
        sum = tmp.inject {|r, i| r + i } - now
        row[x] = life_or_die now, sum
      end
      next_board << row
    end
    @board = next_board
  end
end

if $0 == __FILE__
  board = [
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,],
    [1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,],
    [1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
  ]
  LifeGame.new(board).create_world
end

なんのひねりもございません。
初期配置をダイハードにしてるのでしばらく眺めて楽しんでください。

投稿する勇気はない。

(追記)

一部書き直し。
ダイハードを削除して、シンメトリーに発達するパターンを。