森林火災のシミュレーション 6 of 6

動かしてみる。面白くない。

require "color"
local timerTicking = false
local step = 0.02

-- nspire 側で用意した行列 "mat" を lua 側の変数 mat に読み込む。
local mat = var.recall("mat")

----------------- ルール行列と発火レベル範囲とを定義する -------------------
local matRule = {{0,0,0,0,0,0,0,0,0,color.brown},--レベル 0、空き地、茶
                 {1,2,2,2,2,3,3,3,3,color.green},--レベル 1、樹木、緑
                 {2,3,3,4,4,5,5,5,5,color.yellow},--レベル 2、発火準備、黄
                 {3,4,4,5,5,5,5,5,5,color.yellow},--レベル 3、発火準備、黄
                 {4,5,5,5,5,5,5,5,5,color.yellow},--レベル 4、発火準備、黄
                 {6,6,6,6,6,6,6,6,6,6,color.red},--レベル 5、発火、赤
                 {7,7,7,7,7,7,7,7,7,7,color.red},--レベル 6、発火、赤
                 {8,8,8,8,8,8,8,8,8,8,color.red},--レベル 7、発火、赤
                 {9,9,9,9,9,9,9,9,9,9,color.red},--レベル 8、発火、赤
                 {9,9,9,9,9,9,9,9,9,color.gray}}--レベル 9、木炭、灰
local fireRange = {lower = 5, upper = 8}
----------------------------------------------------------------------------

-- 現世代行列を表示する。
function on.paint(gc)
   drawCell(mat, 5, 5, 4, matRule, false, gc)
   platform.window:invalidate()
end

-- タイマーが tick したら次世代行列を計算してそれを現世代行列に入れ替える。
function on.timer()
   mat = forestFire(mat, matRule)
   platform.window:invalidate()
end

-- enter キーでタイマースタート、ポーズをトグル
function on.enterKey()
   if     timerTicking == false then timer.start(step) timerTicking = true
   elseif timerTicking == true  then timer.stop()      timerTicking = false
   end
   platform.window:invalidate()
end

-- escape キーでリセット
function on.escapeKey()
   reset()
   platform.window:invalidate()
end

-----------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------
--タイマーをとめて初期行列に戻すリセット函数()
function reset() timer.stop() timerTicking=false mat=var.recall("mat") end
--現世代行列を読み込んで次世代行列を出力する(現世代行列,ルール行列)
function forestFire(matCurrent,matRule) local temp=countFire(matCurrent,fireRange.lower,fireRange.upper) local matNew=matNext(matCurrent,temp,matRule) return matNew end
--セルを塗り分ける部分函数(行列,原点座標,1 辺の長さ,ルール行列,数字を表示する/しない,gc)
function drawCell(mat,x0,y0,sideLen,matRule,stringOn,gc) for r=1,#mat do for c=1,#mat[r] do gc:setColorRGB(matRule[mat[r][c]+1][#matRule[mat[r][c]+1]])--[[ルール行列の各行の末尾に指定した色を読み取る。--]]gc:fillRect(x0+(c-1)*sideLen,y0+(r-1)*sideLen,sideLen,sideLen) if stringOn then--[[行列の要素を表示する。--]]gc:setFont("serif","r",7) gc:setColorRGB(color.black) gc:drawString(mat[r][c],x0+(c-1)*sideLen,y0+(r-1)*sideLen,"top") end end end end 
--ルール行列とカウント行列とに従って現世代行列を書き換える部分函数(現世代行列,カウント行列,ルール行列)
function matNext(matNow,matCount,matRule) local matNext=newMat(#matNow,#matNow[1]) for r=1,#matNow do for c=1,#matNow[1] do matNext[r][c]=matRule[matNow[r][c]+1][matCount[r][c]+1] end end return matNext end
--注目セルとそのムーア近傍と合計 9 セルに含まれている発火セルの数を数える部分函数(行列,下限,上限)
function countFire(mat,boundLo,boundHi) local matReturn=newMat(#mat,#mat[1]) local matTemp=newMat(#mat+2,#mat[1]+2) for r=2,#matTemp-1 do for c=2,#matTemp[1]-1 do matTemp[r][c]=mat[r-1][c-1] end end for r=2,#matTemp-1 do for c=2,#matTemp[1]-1 do local matSub=subMat(matTemp,r-1,c-1,r+1,c+1) matSub=mat2list(matSub) local n=countIf(matSub,boundLo,true,boundHi,true) matReturn[r-1][c-1]=n end end return matReturn end
--空行列函数(行数,列数)
function newMat(rowDim,colDim) local mat={} for r=1,rowDim do mat[r]={} for c=1,colDim do mat[r][c]=0 end end return mat end
--行列表示函数(穴なし行列,原点座標,1 辺の長さ,フォントサイズ,gc)
function drawMat(mat,x0,y0,sideLen,fontSize,gc) for r=1,table.maxn(mat) do for c=1,table.maxn(mat[r]) do gc:setFont("sansserif","r",fontSize) gc:setColorRGB(0x000000) gc:drawString(mat[r][c],x0+(c-1)*sideLen,y0+(r-1)*sideLen,"top") end end end
--範囲内の数字の個数を数える(穴なしリスト,下限,含む,上限,含む)
function countIf(list,lowBound,lowIncl,upBound,upIncl) local n=0 for i=1,table.maxn(list) do if lowIncl==false and upIncl==false and lowBound<list[i] and list[i]<upBound then n=n+1--[[下限<?<上限--]]elseif lowIncl==false and upIncl==true and lowBound<list[i] and list[i] <= upBound then n=n+1--[[下限<?<=上限--]]elseif lowIncl==true and upIncl==false and lowBound<=list[i] and list[i]<upBound then n=n+1--[[下限<=?<上限--]]elseif lowIncl==true and upIncl==true and lowBound<=list[i] and list[i]<=upBound then n=n+1--[[下限<=?<=上限--]]end end return n end 
--行列の一部を行列として抜き出す(穴なし行列,左上のどこから右下のどこまでを抜き出す)
function subMat(mat,rowTop,colLeft,rowBottom,colRight) local matReturn={} for r=1,(rowBottom-rowTop+1) do matReturn[r]={} for c=1,(colRight-colLeft+1) do matReturn[r][c]=mat[rowTop+(r-1)][colLeft+(c-1)] end end return matReturn end
--行列をリスト化する(穴なし行列)
function mat2list(mat) local n=1 local listReturn={} for r=1,table.maxn(mat) do for c=1,table.maxn(mat[r]) do listReturn[n]=mat[r][c] n=n+1 end end return listReturn end
 

参考:

pp.167-189