【TIC-80】架空のゲーム機のゲームをFantasyConsoleに移植する（その２）

えーと、つづきを書きたかったのですが、段階としては戻ります。
今回の課題はこちら

##フィールドデータをスプライトエディタで作成したい

```field.lua
field={
 {0,0,0,0,0,0,0,0},
 {0,0,0,0,0,6,6,0},
 {0,0,0,0,2,4,6,0},
 {0,1,1,1,3,5,6,0},
 {0,1,0,1,3,5,7,0},
 {0,1,1,1,1,7,7,0},
 {0,0,0,0,0,7,7,0},
 {0,0,0,0,0,0,0,0}
}
```
はい、こういうデータですね。
数値はエリア番号とします。

以前の記事（[【TIC-80】エリア番号を振った配列（テーブル）から境界線付きのマップデータを作成](https://qiita.com/uokagi/items/4f3c003bcbcd1b2eeb3a)）で使ったデータはエクセルで作ったのですが、それでも面倒でした。
「TIC-80」には使いやすいスプライトエディタがあるので、色番号をそのままテーブルに変換できればいい。

「TIC-80」ではスプライトの表示は以下の命令でできます。
spr(idx,x,y)  -- idx:スプライトのインデックス、x,y:描画座標

とてもシンプル。もちろんさらにパラメータを足せば、色んな表示ができます。
こんな感じで使えるようにしたい。

でもどうすればいいんだろう？　peek4 （アドレス指定して4bitデータを読み込む）を使えばいいのかな？
「TIC-80」のWiki（https://github.com/nesbox/TIC-80/wiki/peek4 ）を見に行くと
スプライトシートのx,y のデータを読み取る sget(x,y) という例が！
ありがたく使わせてもらいます。

```spr2tbl.lua
function spr2tbl(idx,w,h,x_offset,y_offset)
 local w,h=w or 8,h or 8
 local ox,oy=x_offset or 0,y_offset or 0
 local SADDR=0x4000
 function sget(x,y)  -- from TIC-80 wiki
  local addr=SADDR+(x//8+y//8*16)*32
  return peek4(addr*2+x%8+y%8*8)
 end
 local sprX,sprY=idx%16*8,idx//16*8
 local tbl={}
 for i=1,h do
  tbl[i]={}
  for j=1,w do
   tbl[i][j]=sget((sprX+ox+j-1)%256,sprY+oy+i-1)
  end
 end	 
 return tbl
end

function tbl2str(t)
 local str="{\n"
 for i,v in ipairs(t) do
  str=str.." {"..table.concat(v,",").."},\n"
 end
 str=str:sub(1,#str-2).."\n}"
 return str
end
```

ふふふ、関数化ってやつを思い出しましたよ。（以前の記事では関数化すらしていなかった）
関数ってあれでしょ、ホストプログラムが用意したものを使えればいいんでしょ、って感じで自分で作るという意識がなかったです。
本当にレベルが低くて申し訳ないです。

あとついでに確認用に文字列にするのも関数に。
おそらく再帰を使えば、多次元のものもできるとは思いますが、よく分からないし、今回は上記のもので作ったものの確認なのでとりあえずはこれで。

![tbldata.gif](https://qiita-image-store.s3.amazonaws.com/0/284455/94c34e8f-cbfb-8a84-2564-a45862a2b867.gif)

でこんな感じでデータを作って

```test.lua
function test()
 sprid=112
 t=spr2tbl(sprid)
 s=tbl2str(t) 
end

test()

function TIC()
 cls(8)
 print(s,1,1,0,true,2)
 print(s,0,0,15,true,2)
 spr(sprid,204,100,-1,4)
end
```
こんな感じのテストを書いて‥

![test2.gif](https://qiita-image-store.s3.amazonaws.com/0/284455/11f9cd42-6305-b1fb-4ea2-b163fe9e4620.gif)

おー大丈夫かな？

###エリア数が16を超えた場合の番号振り直し

ではさっそく「国盗りす」のLEVEL1（ステージ１）のデータを作成。
![LEVEL1.gif](https://qiita-image-store.s3.amazonaws.com/0/284455/d221191a-a058-feb6-2001-a4fd64e4d937.gif)

はい、こんな感じ。
しかし、このデータには問題があります。
エリア数が海を合わせて16を超えます。
本来別エリアでないといけないエリアも同じとみなされてしまいます。

ただ「国盗りす」では同じエリアが離れて配置されることはないようなので
離れていればすべて別エリアとしてカウントし直すこととします。

でいつものように調べたのですが、例のごとく、これ！と合致する情報は
みつからず（2値画像データの島の数え上げ？辺りは結構近かったと思います）、
仕方ないので、ぷよぷよのつながっているぷよをカウントする、という
方法を参考に作ってみました。

```renumt.lua
function renumt(tbl) 

 local function chain (row,col,n,tbl,newtbl)
  local num = tbl[row][col]
  newtbl[row][col]=(num==0)and 0 or n
  tbl[row][col] = -1
  if (row>1 and tbl[row-1][col]==num) then chain(row-1, col,n,tbl,newtbl)  end
  if (row<#tbl and tbl[row+1][col]==num) then chain(row+1,col,n,tbl,newtbl) end
  if (col>1 and tbl[row][col-1]==num) then chain(row, col-1,n,tbl,newtbl) end
  if (col<#tbl[1] and tbl[row][col+1]==num) then chain(row,col+1,n, tbl,newtbl) end
  return
 end

 local area={}
  for i=1,#tbl do
   area[i]={}
   for j=1,#tbl[i] do
    area[i][j]=0
   end
  end	
  n=0
  for i=1,#t do
   for j=1,#t[i] do
    if tbl[i][j]>=0 then
     chain(i,j,n,tbl,area)
     n=n+1
    end
   end
  end
  return area
end
```

この関数を作るだけで数時間かかりました。
しかも微妙に違う問題を中途半端に参考にしたせいでひどく
回りくどい書き方になっているように思います。

どういうワードで検索すれば目的の情報に行き当たるか、
こういう書き方をすればもっとすっきりするよ、など
アドバイスがありましたらよろしくお願いいたします。

とりあえず、以前のマップデータ作成のスクリプトを関数化し、
エリア番号確認用の描画関数を追加。

```tbl2map.lua
function tbl2map(t,dosync,tileID,x_offset,y_offset)
 local tid=tileID or 0
 local ox=x_offset or 0
 local oy=x_offset or 0 
 for i=2,#t do
  for j=2,#t[i] do
   local dSea=(t[i][j]==0)and 0 or 4
   local dLeft=(t[i][j]==t[i][j-1])and 0 or 1
   local dUp=(t[i][j]==t[i-1][j])and 0 or 2
   mset(j+ox,i+oy,tid+dSea+dLeft+dUp)
  end
 end
 if dosync then sync(4,0,true) end
end

function drawtbl(t,cellsize,ox,oy,color)
 local csize=cellsize or 8
 local c=color or 15
 local ox,oy=ox or 2,oy or 2
 for row,col in ipairs(t) do
  for coln,v in ipairs(col) do
   print(v,coln*csize+ox,row*csize+oy,c,false,1,true)
  end
 end
end
```

##結果確認とまとめ

今回使わなかった部分のデータはクリアして

![test6.gif](https://qiita-image-store.s3.amazonaws.com/0/284455/95277051-75ee-fb33-c94a-c6fd108bebdf.gif)

テストをしてみます。

![test7.gif](https://qiita-image-store.s3.amazonaws.com/0/284455/838f242f-93a6-19fc-3f7f-6be76ad30ec7.gif)

無事、8種類のタイルと別エリアを別の色で表現したスプライトデータから
境界線付きマップデータと、エリア番号を振り直したフィールドデータを作成できました。

‥ふと思ったのですが、この手の地図は4色あれば塗り分けられるみたいですね。
ということは番号を振り直した（振り直す前でも）データは、一つのセルにつき4種類、
すなわち2bitで表現できるということ。
フィールドデータはかなり圧縮できそうです。
こんなことを考えたのは「国盗りす」のパッケージ（もちろん捏造なんですが）に
16KB との記述が。
[国盗りすアクキー](https://store.hakabanogarou.jp/shopdetail/000000001226/) （2個購入済）

「音源：ドとレとシの音が出ない」
とあって最初は笑っていたのですが、これって音階を2bit表現させるためだよなあとか。

まあそういったものはゲーム部分がきちんと再現できた後での課題ではあります。

あ、ゲーム部分は絶賛３度目のリライト中（いちからの書き直し）です。

次はゲーム部分について書けたらいいなと思います。