ライフゲーム

Rubyライフゲームを作ってみた.

起動後,10x10みたいな感じでフィールドの大きさを入力.
あとはEnterを押すと世代が一つずつ進んでいく.

また,座標の指定をすれば,その座標の生死を切り替えられる.

以下にソースコードを示す.

lifegame.rb

#!/usr/bin/env ruby
require "lifegamefield.rb"
require "lifegameview.rb"

print "[幅x高さ]を入力してください: "
widthheight=gets.split(/x/)
width=widthheight[0].to_i
height=widthheight[1].to_i

lgf = LifeGame::Field.new(width,height)
view = LifeGame::ConsoleView.new(lgf)

g=0
loop do
	print "=== generation #{g+1} ===\n"
	view.visualize
	cmd=""
	loop do
		print "状態を変更する場合はその座標をカンマ区切りで入力[x,y]:"
		break if (cmd=gets) == "\n"
		# 座標指定があれば
		if cmd =~ /(\d+),(\d+)/
			x=$1.to_i
			y=$2.to_i
			if lgf.isalive?(x,y)
				lgf.kill(x,y)
			else
				lgf.create(x,y)
			end
		end
		view.visualize
	end
	break if cmd=="exit"
	lgf.update
	g+=1
end

lifegamefield.rb

module LifeGame
class Field
	attr_reader :width,:height
	def initialize(width,height)
		@width=width
		@height=height
		init
	end
	
	def init
		@field=[]
		@height.times do |h|
			line=[]
			@width.times do |w|
				line.push(false)
			end
			@field.push(line)
		end
	end

	def isalive?(x,y)
		return false if x >= @width
		return false if y >= @height
		return @field[y][x]
	end

	def create(x,y)
		return false if x >= @width
		return false if y >= @height
		@field[y][x]=true
	end

	def kill(x,y)
		return false if x >= @width
		return false if y >= @height
		@field[y][x]=false
	end
	
	def update
		# life game のメインルーチン
		newfield=@field.map{|x| x.clone}
		@height.times do |h|
			@width.times do |w|
				count=getlivecount(h,w)
				if @field[h][w]
					# 8近傍のうち生きているのが2つか3つでないなら死ぬ
					newfield[h][w]=false if count != 2 and count != 3
				else
					# 8近傍のうち生きているのが3つだったら生きる
					newfield[h][w]=true if count == 3
				end
			end
		end
		@field=newfield
	end

	def getlivecount(h,w)
		count=0
		(-1..1).each do |dy|
			(-1..1).each do |dx|
				next if dy==0 and dx==0
				count += 1 if @field[h-dy] != nil and @field[h-dy][w-dx]
			end
		end
		return count
	end
end

end

lifegameview.rb

module LifeGame
	class ConsoleView
		def initialize(field)
			@field=field
		end

		def visualize
			@field.height.times do |h|
				@field.width.times do |w|
					state=@field.isalive?(w,h)
					print "" if state
					print "" unless state
				end
				print "\n"
			end
		end
	end
end

ついでにWebアプリにもしてみたいけど,めんどくさいので今日はここまで.