前橋です。サイン本コンテスト(?)に応募します。

tk によるライフゲームです。
有名なので知っていると思いますが、碁盤の目上に配置された生命体が、一定
のルールにしたがって生成/消滅を繰り返していく様を見て楽しむというもの
です。ルールは、
・ある生命体の周囲 8つのマス目のうち 2つあるいは 3つに生命体が存在すれ
  ば生き残るがそれ以外では過疎あるいは過密で死んでしまう
・空いている場所の周りにちょうど 3つの生命体がいれば、そこに新しい生命
  体が生まれる
です。

使い方は起動すればわかるでしょう。マウスで盤面をクリックすることにより
配置/除去ができます。

# サーチエンジンでライフゲームを調べたら、Java アプレットのライフゲー
# ムが山のようにでてきた。。。

----------------------------------------------------------------------
#! /usr/local/bin/ruby

# Game of Life

require "tk"

class LifeGame
  def initialize(width=80, height=23)
    @width = width
    @height = height
    default = [-width-1, -width, -width+1, -1, 1, width-1, width, width+1]
    @neighbors = []
    @neighbors.fill(default, 0, width*height)
    (0..width*height-1).each {|i|
      x = i % width
      y = i / width
      if x == 0
	@neighbors[i] = [-width, -width+1, 1, width, width+1]
      elsif x == @width-1
	@neighbors[i] = [-width-1, -width, -1, width-1, width]
      end
      if y == 0
	@neighbors[i] = @neighbors[i].clone
	@neighbors[i].delete_if {|v| v < -1}
      elsif y == @height-1
	@neighbors[i] = @neighbors[i].clone
	@neighbors[i].delete_if {|v| v > 1}
      end
    }
    @grid = {}
    center = height / 2 * width + width / 2
    @grid[center] = true
    @grid[center+1] = true
    @grid[center+width] = true
    @grid[center+width-1] = true
    @grid[center+width+width] = true
  end

  def nextgen
    n = {}
    @grid.each_key {|i|
      n[i] += 0
      @neighbors[i].each {|pos| n[i+pos] += 1}
    }
    n.each {|i, n|
      @grid[i] = if (n == 3 || @grid[i] && n == 2) then true else nil end
    }
  end

  def run
    loop {
      display
      nextgen
      break unless gets
    }
  end

  def display
    s = ' ' * (@width * @height)
    @grid.each_key {|i| s[i,1]='*'}
    print s, "\n"
  end
end

class TkLifeGame < LifeGame
  include Tk
  def initialize(width=80, height=80, rectsize=6)
    super(width, height)
    @rectsize = rectsize
    @goflag = false

    @canvas = TkCanvas.new(nil,
			   'width'=>width * rectsize,
			   'height'=>height * rectsize,
			   'borderwidth'=>1,
			   'relief'=>'sunken')
    @nextbutton = TkButton.new(nil,
			       'text'=>'next',
			       'command'=>proc {nextgen; display})
    @gobutton = TkButton.new(nil,
			     'text'=>'go',
			     'command'=>proc {
			       @goflag = !@goflag
			       if @goflag
				 @gobutton.text 'stop'
				 go
			       else
				 @gobutton.text 'go'
			       end
			     })
    @quitbutton = TkButton.new(nil,
			       'text'=>'quit',
			       'command'=>proc {exit})
    @canvas.pack
    @nextbutton.pack('side'=>'left')
    @gobutton.pack('side'=>'left')
    @quitbutton.pack('side'=>'right')

    @prevgrid = {}
    @rectangles = {}
    @canvas.bind '1', proc {|x, y|
      i = x / @rectsize + y / @rectsize * @width
      if @grid[i]
	@grid[i] = nil
      else
	@grid[i] = true
      end
      display
      update
    }, '%x %y'
  end

  def go
    nextgen
    display
    update
    if @goflag
      after 0, proc {go}
    end
  end

  def run
    display
    mainloop
  end

  def display
    @grid.each_key {|i|
      if @prevgrid[i]
	@prevgrid[i] = nil
      else
	setrect(i)
      end
    }
    @prevgrid.each_key {|i|
      resetrect(i)
    }
    @prevgrid = @grid.dup
  end

  def setrect(i)
    x = i % @width
    y = i / @width
    @rectangles[i] = TkcRectangle.new(@canvas,
				      x * @rectsize,
				      y * @rectsize,
				      x * @rectsize + @rectsize - 2,
				      y * @rectsize + @rectsize - 2,
				      'fill'=>'black')
  end

  def resetrect(i)
    @rectangles[i].destroy
    @rectangles[i] = nil
  end

end

#g = LifeGame.new
g = TkLifeGame.new
g.run