高校生の頃買った、奥村晴彦先生の「C言語による最新アルゴリズム辞典」で知ったライフゲーム。当時は C を覚えたばかりで、グラフィカルなソフトなんてほぼほぼ書けませんでした。 最新アルゴリズム辞典ではグラフィックを使わず端末上の文字で各セルを表現するものでしたが、どうせなら綺麗な見た目でやってみたいと思ってなつかしの HSP でちまちま書いてみていました。 そのキャプチャ動画を↓に載せています。

[Lifegame – YouTube]1

マウスを押下した場所に R ペントミノを配置することができるので、安定期に入ったセルをかき混ぜて遊ぶことができます。 タイムスタンプを見たら10年以上前ですね、こわい。

lifegame-1.hsp (Gist)

/*

		HSPによるライフゲームサンプル

		参考文献:
			『C言語による最新アルゴリズム辞典』奥村晴彦著/技術評論社
			『人工生命の世界』服部桂/オーム社
*/
#define ScreenX 160
#define ScreenY 120
#define ImageBuffer 0
#define Speed 0

	//仮想イメージバッファ
	dim vram,ScreenX,ScreenY
	//次世代イメージバッファ
	dim nram,ScreenX,ScreenY
	x=0
	y=0
	gn=0
	i=0

//	初期媒体ペントミノの定義
	nram(ScreenX/2,ScreenY/2)		= 1
	nram(ScreenX/2,ScreenY/2-1)		= 1
	nram(ScreenX/2,ScreenY/2+1)		= 1
	nram(ScreenX/2-1,ScreenY/2)		= 1
	nram(ScreenX/2+1,ScreenY/2-1)	= 1

screen ImageBuffer,ScreenX,ScreenY
	cls 0
	repeat
		repeat
			repeat
				vram(x,y) = nram(x,y)
				x++
				if( x >= ScreenX-1 ) : break
			loop
			y++
			if( y >= ScreenY-1 ) : break
			x=1
		loop
	redraw 0
			color 255,255,255
			boxf
			color 0,0,0
			x=1
			y=1
			repeat
				repeat
					i=0

					if( nram(x,y) != 0 ) :{
						pset x,y
					}
					
					if( vram(x-1,y-1) != 0) : i++
					if( vram(x  ,y-1) != 0) : i++
					if( vram(x+1,y-1) != 0) : i++
					if( vram(x-1,y  ) != 0) : i++
					if( vram(x+1,y  ) != 0) : i++
					if( vram(x-1,y+1) != 0) : i++
					if( vram(x  ,y+1) != 0) : i++
					if( vram(x-1,y+1) != 0) : i++
					if( i = 0 ) : nram(x,y) = 0
					if( i = 2 ) : nram(x,y) = vram(x,y)
					if( i = 3 ) : nram(x,y) = 1
					if( i > 3 ) : nram(x,y) = 0

					x++
					if( x >= ScreenX-1 ) : break
				loop
				y++
				if( y >= ScreenY-1 ) : break
				x=1
			await
			loop
		redraw 1
		gn++
		title "Generation : "+gn+""
		await Speed
	loop

	stop

lifegame-2.hsp (Gist)

/*
	LIFEGAME SAMPLE for HSP
	VERSION 1.12

	[REFERENCE]
	左クリ	ペントミノ投下
	ENTER	初期位置(中心)にペントミノ投下
	ESC		細胞を全消去
	SPACE	一時停止
	↑		倍率を上げる
	↓		倍率を下げる
	TAB		グリッド表示切替

*/
//行数・文字数
N=128
M=192
//倍率設定
x=2
//グリッド有無
gd=0
//グリッド横分割数
gdx=24
//グリッド縦分割数
gdy=16
//ウェイト
w=10
//背景画像有効
img=1
//自動投下モード
auto=1
//投下タイミング(世代数)
ag=100

*start
	if(img):{
		buffer 2
		picload "back.jpg"
	}
	i=0
	j=0
	gosub *clr
	gosub *put
screen 0,M*x,N*x
	title "LIFEGAME - RUN"
	repeat
*main
		g++
//		title ""+g+""
		redraw 0
		//背景描写
		if(img):{
			pos 0,0
			gzoom M*x,N*x,2,0,0,M,N,1
		}else: color 0,0,0 : boxf
		//グリッド描写
		if(gd):{
			color 63,47,47
			repeat gdx
				line M/gdx*x*cnt,0,M/gdx*x*cnt,N*x
			loop
			repeat gdy
				line 0,N/gdy*x*cnt,M*x,N/gdy*x*cnt
			loop
		}
		//描写系統
		for i,1,N,1
			for j,1,M,1
				if( a(i,j)!=0):{
					color 255-(j+i),63+j,127+i
					//倍率を上げたら、ドットを強調する。
					pset j*x,i*x
					if(x>2):{
						pset j*x,i*x-1
						pset j*x+1,i*x
						pset j*x-1,i*x
						pset j*x,i*x+1
					}
					if(x>4):{
						pset j*x-1,i*x-1
						pset j*x+1,i*x-1
						pset j*x-1,i*x+1
						pset j*x+1,i*x+1
					}
					b(i-1,j-1)++ :	b(i-1,j  )++	:b(i-1,j+1)++
					b(i  ,j-1)++ :					:b(i  ,j+1)++
					b(i+1,j-1)++ :	b(i+1,j  )++	:b(i+1,j+1)++
				}
			next
		next
		//ムーア近傍をチェック
		for i,0,N+1,1
			for j,0,M+1,1
				if(b(i,j)!=2) : a(i,j)=(b(i,j)==3)
				b(i,j)=0;
			next
		next
		redraw 1
		stick key,256
			if key&128	: gosub *clr
			if key&16	: gosub *stp
			if key&32	: gosub *put
			if key&2	: if x<8 : x++ : screen 0,M*x,N*x : goto *main
			if key&8	: if x>1 : x-- : screen 0,M*x,N*x : goto *main
			if key&1024	: if(gd) : gd=0 : else : gd=1
			if key&256	: gosub *click
		await w
		//自動投下
		if(auto) : if(cnt>ag) : if(cnt\ag=0) : gosub *put
	loop
	stop

//一時停止画面
*stp
	title "LIFEGAME - STOP"
	font "Impact",12,16 : color 127,255,192 : pos 0,0
	mes " [ LIFEGAME ] "
	mes "  SIZE : "+M*x+"px, "+N*x+"px ( "+x+"x )"
	mes "  GENERATION : "+g
	c=0
	for i,1,N,1
		for j,1,M,1
			if( a(i,j)!=0):c++
		next
	next
	mes "  CELLS : "+c
	repeat
		stick key,256
			if key&128	: gosub *clr
			if key&16	: 	title "LIFEGAME - RUN" : break
			if key&32	: gosub *put
			if key&2	: if x<8 : x++ : goto *main
			if key&8	: if x>1 : x-- : goto *main
			if key&1024	: if(gd) : gd=0 : else : gd=1
			if key&256	: gosub *click
		wait 10
	loop
	return

//細胞全消去
*clr
	dim a,N+2,M+2
	dim b,N+2,M+2
	g=0
	return

//初期ペントミノを定義
*put
	a(N/2,M/2)		=1
	a(N/2-1,M/2)	=1
	a(N/2+1,M/2)	=1
	a(N/2,M/2-1)	=1
	a(N/2-1,M/2+1)	=1
	return

//クリックした位置にペントミノ投下
*click
	mx=mousey/x
	my=mousex/x
	//タスクバークリックは無効
	if((mx<=0)||(mx>=N)||(my<=0)||(my>=M)) : return
	a(mx,my)		=1
	a(mx-1,my)		=1
	a(mx+1,my)		=1
	a(mx,my-1)		=1
	a(mx-1,my+1)	=1
	return
/* EOF */

HSP の動かせる環境がないので動確はしていませんが、元になった(はずの)コードを貼りつけておきます。 (ところで、HSP をやっている人って今いるのかな?)


最近に Ruby で書いてみたものも掲載します。

lifegame.rb (Gist)

#!/usr/bin/ruby

w = 80
h = 24

print "\e[5>h"

a = h.times.map{ w.times.map{ false } }

ww = w / 2
hh = h / 2
a[hh][ww]   = true
a[hh-1][ww] = true
a[hh+1][ww] = true
a[hh][ww-1] = true
a[hh-1][ww+1] = true

ww = w - 1
hh = h - 1
g = 1

STDOUT.sync = true

loop do

  print "\e[2J"
  print "\e[1;1H"
  ss = ""
  a.each.with_index(1) do |b, y|
    s = ""
    b.each do |c|
      s += (c ? "*" : " ")
    end
    ss += "#{s}\n"
  end
  puts "#{ss}gen=#{g}"
  sleep 0.1

  aa = h.times.map{ w.times.map{ false } }

  (0..ww).each do |x|
    (0..hh).each do |y|
      arives = 0
      arives += 1 if (x>0&&y>0) && a[y-1][x-1]
      arives += 1 if (y>0) && a[y-1][x]
      arives += 1 if (x<ww&&y>0) && a[y-1][x+1]
      arives += 1 if (x>0) && a[y][x-1]
      arives += 1 if (x<ww) && a[y][x+1]
      arives += 1 if (x>0&&y<hh) && a[y+1][x-1]
      arives += 1 if (y<hh) && a[y+1][x]
      arives += 1 if (x<ww&&y<hh) && a[y+1][x+1]
      aa[y][x] = a[y][x] ? (arives == 2 || arives == 3) : (arives == 3)
    end
  end
  a = aa
  g += 1
end

print "\e[5>l"

手元の環境(PuTTY経由)では、カーソルの表示・非表示のエスケープシーケンスが上手く動いてませんね。