森林火災のシミュレーション 3, countFire()

注目セルとそのムーア近傍と合わせて 9 つのセルに含まれている、発火状態(レベル 5 ~ 8)にあるセルの数をカウントする。
フィールドの外は全部空き地(レベル 0)とする。

上 が lua に読み込んだ現世代行列、下が lua から返されたカウント数。
f:id:ti-nspire:20160110153917j:plain

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

-- 発火レベルの範囲を定義する
local fireRange = {lower = 5, upper = 8}

-- できた行列を確認する。
function on.paint(gc)
   local temp = countFire(matSute, fireRange.lower, fireRange.upper)
   drawMat(temp, 0, 0, 15, 7, gc)
end


-- 注目セルとそのムーア近傍と合計 9 セルに含まれている発火セルの数を数える部分函数(行列, 下限, 上限)
function countFire(mat, boundLo, boundHi)
   
   -- 返すための空行列を作る。
   local matReturn = newMat(#mat, #mat[1])
   
   -- 読み込んだ mat の外周を空き地(レベル 0)で埋める。
   -- まず、読み込んだ mat よりも 2 行・2 列多い空行列を作る。
   local matTemp = newMat(#mat + 2, #mat[1] + 2)
        
   -- 今作った、2 行・2 列多い空行列の 2 行目、2 列目から mat を上書きする。
   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

         -- 注目セルとそのムーア近傍と合計 9 セルを抜き出してリスト化する。
         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