game of life 9 of 9
ライフ・ゲームの初代行列をフリーハンドで設定する。
local n = 1 -- 世代番号の初期値 local stringPen = "PEN UP" local stringEraser = "ERASER UP" local posX, posY = 0, 0 local posC, posR = 1, 1 local penDown = false local eraserDown = false local rdim, cdim = 25,25 -- 行列のサイズを決める。 local sideLen = 8 -- セルの一辺の長さを決める。 local screenW, screenH = sideLen * cdim, sideLen * rdim -- 画面サイズを決める。 -- 空行列を作る local mat_now, mat_void = {}, {} for r = 1, rdim do mat_now[r], mat_void[r] = {}, {} for c = 1, cdim do mat_now[r][c], mat_void[r][c] = 0, 0 end end -- 現世代行列を描画する。 function on.paint(gc) gc:drawString(n, 250, 80, "top") -- 世代数を表示する。 if penDown then mat_now[posR][posC] = 1 -- 行列に 1 を代入 elseif eraserDown then mat_now[posR][posC] = 0 -- 行列に 0 を代入 end --[[ -- あとで再現できるよう、できた行列を nspire 側に保存しておく var.store("mat", mat_now) --]] -- 行列を描画する。 for r = 1, rdim do for c = 1, cdim do if mat_now[r][c] == 1 then gc:setColorRGB(0,0,0) gc:fillRect((c - 1) * sideLen, (r - 1) * sideLen, sideLen, sideLen) end gc:setColorRGB(198,113,113) gc:setFont("serif", "r", 7) --[[ -- 確認のため行列の要素を表示する gc:drawString(mat_now[r][c], (c - 1) * sideLen, (r - 1) * sideLen, "top") --]] end end gc:drawRect((posC -1) * sideLen, (posR - 1) * sideLen, sideLen, sideLen) -- カーソルの位置に目印の枠を出す gc:setFont("serif", "r", 7) gc:setColorRGB(0,0,0) gc:drawString(stringPen, 230, 0) -- ペンの状態を表示する gc:drawString(stringEraser, 230, 15) -- 消しゴムの状態を表示する gc:drawString("x = "..posX, 230, 30) -- x 座標を表示する gc:drawString("y = "..posY, 275, 30) -- y 座標を表示する gc:drawString("Col = "..posC, 230, 45) -- 列番号を表示する gc:drawString("Row = "..posR, 275, 45) -- 行番号を表示する end function on.timer() -- タイマーが動いたら n = n + 1 -- 世代番号を 1 進める。 mat_now = game_of_life(mat_now) -- 現世代行列を game_of_life 函数に読み込んで次世代行列を計算する。 platform.window:invalidate() end function on.enterKey() -- enter キーでタイマーを開始する。 timer.start(0.01) end function on.escapeKey() -- esc キーでタイマーを停止する。 timer.stop() platform.window:invalidate() end function on.mouseDown() -- 左クリックでペンを下ろす stringPen = "PEN DOWN" penDown = true platform.window:invalidate() end function on.mouseUp() stringPen = "PEN UP" penDown = false platform.window:invalidate() end function on.rightMouseDown() --右クリックで消しゴムを下ろす eraserDown = true stringEraser = "ERASER DOWN" platform.window:invalidate() end function on.rightMouseUp() eraserDown = false stringEraser = "ERASER UP" platform.window:invalidate() end function on.mouseMove(x, y) posX, posY = x, y posC = math.floor(posX/(screenW/cdim)) + 1 -- x 座標を列番号にマッピングする。 posC = math.max(1, math.min(posC, cdim)) -- 列数をはみ出さないようにする。 posR = math.floor(posY/(screenH/rdim)) + 1 -- y 座標を行番号にマッピングする。 posR = math.max(1, math.min(posR, rdim)) -- 行数をはみ出さないようにする。 platform.window:invalidate() end -- 現世代行列から次世代行列を求める部分プログラム function game_of_life(mat_now) local mat_moore = mat_void -- ルール表を定義する。 local mat_rule = {{0,0,0,1,0,0,0,0,0}, {0,0,1,1,0,0,0,0,0}} -- ムーア近傍の和の行列を作る。 for r = 1, rdim do for c = 1, cdim do -- トーラス接続にする。 local above, below, left, right if r == 1 then above = rdim else above = r - 1 end if r == rdim then below = 1 else below = r + 1 end if c == 1 then left = cdim else left = c - 1 end if c == cdim then right = 1 else right = c + 1 end -- ムーア近傍の和を計算する。 mat_moore[r][c] = mat_now[above][left] + mat_now[above][c] + mat_now[above][right] + mat_now[r][left] + mat_now[r][right] + mat_now[below][left] + mat_now[below][c] + mat_now[below][right] end end local mat_next = mat_now -- 次世代行列を作る。 for r = 1, rdim do for c = 1, cdim do mat_next[r][c] = mat_rule[mat_now[r][c] + 1][mat_moore[r][c] + 1] end end -- 次世代行列を返す。 return mat_next end
つぎはぎ、つぎはぎしているので無駄が多い。