何をするのか
IchigoJamでライフゲームの世代交代の計算をする。
正方形のグリッドにおいて、各マスは「生」または「死」の状態をとる。
世代交代とは、
- 「生」のマスは、8近傍の「生」のマスの数が2または3なら「生」のまま、そうでないなら「死」になる
- 「死」のマスは、8近傍の「生」のマスの数が3なら「生」になり、そうでないなら「死」のまま
という計算である。
今回は白で「生」を、黒で「死」を表現した。
BASICでやってみた
今回は、「女王蜂」の両側に「ブロック」を配置し、30世代周期でもとに戻るパターンを用意した。
1個だと寂しいので、左右反転して2個並べてみた。
↓「女王蜂」はここを参照した。
シャトル (ライフゲーム) - Wikipedia
まず、配列に初期パターンを格納する。
その後、「配列のデータをVRAMに反映する → VRAMのデータをもとに配列のデータを更新する」を繰り返す。
ソースコード
10 'ライフゲーム
20 LET[0],0,0,0,0,0,0,0,0,0,#4000,0,#5000,0,#2800,#600,#2460
30 LET[16],#600,#2860,0,#5000,0,#4000,0,0,0,0,2,0,#A,0,#614,#60
40 LET[32],#624,#60,#14,0,#A,0,2,0,0,0,0,0,0,0,0,0
50 G=0
60 FOR I=0 TO #2FF
70 POKE#900+I,([I/16]>>(15-I%16))&1
80 NEXT
90 LOCATE0,0:?G
100 POKE#909,#5B:POKE#91F,#5D
110 FOR I=0 TO 47:[I]=0:NEXT
120 FOR Y=2 TO 22:FOR X=1 TO 30
130 P=#900+Y*32+X:C=PEEK(P-33)+PEEK(P-32)+PEEK(P-31)+PEEK(P-1)+PEEK(P+1)+PEEK(P+31)+PEEK(P+32)+PEEK(P+33)
140 IF C=3 OR (PEEK(P) AND C=2) K=Y*2+X/16:[K]=1<<(15-X%16)|[K]
150 POKE#908+Y,#23:NEXT:NEXT
160 WAIT 6
170 G=G+1:IF G>9999 G=0
180 GOTO 60
実行結果
30世代の計算を行うのに、約13分32秒(812秒)かかった。
マシン語でやってみた
BASIC版は頑張っている感はあるものの遅すぎて実用的でないため、
「配列のデータをVRAMに反映する」「VRAMのデータをもとに配列のデータを更新する」それぞれをマシン語に移植してみた。
埋め込んだマシン語のソースコード
@START
R3 = PC + 64 ' 配列の先頭アドレス (コードは#700から)
R2 = R3 + 1
R2 += 255 ' VRAMの先頭アドレス
R0 & R0
IF !0 GOTO @UPDATE
' 描画処理を行う
R12 = R4
R1 = 3
R1 = R1 << 8 ' カウンタ
R1 -= 1
@DRAW_LOOP
R0 = [R3 + 0]W
R4 = 15
R4 &= R1
IF !0 GOTO @DRAW_LOOP_NOARRAYINC
R3 += 2
@DRAW_LOOP_NOARRAYINC
R0 >>= R4
R4 = 1
R0 &= R4
[R2 + 0] = R0
R2 += 1
R1 -= 1
IF CS GOTO @DRAW_LOOP
R4 = R12
RET
@UPDATE
' 更新処理を行う
PUSH {R4, R5, R6, R7}
R0 = 92
R1 = 0
@UPDATE_INIT_LOOP
[R3 + R0]L = R1
R0 -= 4
IF CS GOTO @UPDATE_INIT_LOOP
R6 = R2
R6 -= 33
R4 = 2
@UPDATE_OUTER_LOOP
R5 = 1
@UPDATE_INNER_LOOP
R0 = R4 << 5
R0 = R0 + R5
R0 = R0 + R6
R1 = [R0 + 0]
R7 = [R0 + 1]
R1 = R1 + R7
R7 = [R0 + 2]
R1 = R1 + R7
R0 += 64
R7 = [R0 + 0]
R1 = R1 + R7
R7 = [R0 + 1]
R1 = R1 + R7
R7 = [R0 + 2]
R1 = R1 + R7
R0 -= 32
R7 = [R0 + 0]
R1 = R1 + R7
R7 = [R0 + 2]
R1 = R1 + R7
R1 - 3
IF EQ GOTO @UPDATE_LIVE
R1 - 2
IF NE GOTO @UPDATE_CONTINUE
R7 = [R0 + 1]
R7 & R7
IF 0 GOTO @UPDATE_CONTINUE
@UPDATE_LIVE
R0 = R4 << 1
R1 = R5 >> 4
R0 = R0 + R1
R0 = R0 << 1
R0 = R0 + R3
R1 = 15
R1 &= R5
R7 = 15
R7 = R7 - R1
R1 = 1
R1 <<= R7
R7 = [R0 + 0]W
R7 |= R1
[R0 + 0]W = R7
@UPDATE_CONTINUE
R5 += 1
R5 - 30
IF LS GOTO @UPDATE_INNER_LOOP
R4 += 1
R4 - 22
IF LS GOTO @UPDATE_OUTER_LOOP
POP {R4, R5, R6, R7}
RET
ソースコード
10 'ライフゲーム (マシンゴ ver.)
20 LET[0],0,0,0,0,0,0,0,0,0,#4000,0,#5000,0,#2800,#600,#2460
30 LET[16],#600,#2860,0,#5000,0,#4000,0,0,0,0,2,0,#A,0,#614,#60
40 LET[32],#624,#60,#14,0,#A,0,2,0,0,0,0,0,0,0,0,0
50 POKE#700,63,163,90,28,255,50,0,66,17,209,164,70,3,33,9,2,1,57,24,136,15,36,12,64,0,209,2,51,224,64,1,36,32,64,16,112,1,50,1,57,243,210,100,70,112,71,240,180,92,32,0,33,25,80,4,56,252,210,22,70
60 POKE#73C,33,62,2,36,1,37,96,1,64,25,128,25,1,120,71,120,201,25,135,120,201,25,64,48,7,120,201,25,71,120,201,25,135,120,201,25,32,56,7,120,201,25,135,120,201,25,3,41,4,208,2,41,16,209,71,120,63,66
70 POKE#776,13,208,96,0,41,9,64,24,64,0,192,24,15,33,41,64,15,39,127,26,1,33,185,64,7,136,15,67,7,128,1,53,30,45,211,217,1,52,22,44,207,217,240,188,112,71
80 G=0
90 I=USR(#700,0)
100 LOCATE0,0:?G
110 I=USR(#700,1)
120 WAIT 6
130 G=G+1:IF G>9999 G=0
140 GOTO 90
実行結果
30世代の計算をするのに、約3秒しかかからなかった。
BASIC版の約270倍速いということである…といいたいところだが、ここには`WAIT 6`の時間も含まれる。
これは0.1秒待つということなので、30世代で3秒待つ…すなわち、計算時間はほぼゼロになってしまった。
マシン語つよい。 (BASICがよわい?)
IchigoJamとは
2,000円前後で購入することができ、BASICによるプログラミングが可能なパソコン。
こどもパソコン IchigoJam - はじめてのプログラミングパソコン(1500円)
また、プログラムをWebブラウザ上で実行できるサービスもある。
IchigoJam web by WebAssembly
※マシン語を用いるプログラムは、今のところこのサービスでは動かない
※「IchigoJam」はjig.jpの登録商標