テーブルの複製

テーブルコピーの実験 PICO-8
テーブルコピーの実験

ゲームを作っていると、テーブルをコピーしたい時があります(私にはありました)。

そもそも、テーブルのコピーは、「A = B」のように名前をイコールで繋げても出来ません。

次のPICO-8のコンソールでの実験結果を見てください。

テーブルコピーの実験
テーブルコピーの実験

まず、テーブルAには1と2を、テーブルBには3と4をリストとして、入れておきます。

テーブルBの内容をテーブルAにコピーしようとして、「A = B」を実行します。

テーブルAには、テーブルBの3と4がコピーされたかのようですが、テーブルBの1番目に5を代入すると、テーブルAの1番目も3ではなく、5になってしまいます。

つまり、これはアドレスをコピーして、実際のデータを指す場所をコピーしたので、テーブルAとテーブルBは、同じテーブルを指しているのです。

なので、「内容自体を複製したい」場合は、テーブルの要素(フィールドと言うらしい)を読み取って書き込まなくてはならないのです(ループ構文必須)。

現在制作中のゲーム「Magic Line」では、線で囲んだ部分の情報を得るためにテーブルのコピーを使っていました。

こんな感じです。

function t_copy(tag_t,src_t)
  for x=1,31 do
    for y=1,31 do
      tag_t[x][y]=src_t[x][y]
    end
  end
end

第1引数にコピー先のテーブル、第2引数にコピー元のテーブルを渡して、XとYの二重ループで一つ一つ読み取り写します。

最近、アイテムの所持チェックなどを行うために、元の所持リストからコピーしてテンポラリリストとして更新に使い、ステージをクリアしたら、テンポラリリストを元の所持リストへコピーするように考えました。

ただ、今回は「アイテム名=bool値(真偽)」の辞書のテーブルとなるため、
「(先で紹介した)テーブルのコピー関数を使うわけにはいかない、また別に専用のコピー関数を作って実装するしか無いか、だとすると トークンを余計に使ってしまうな」
と考えていました。

そんな時、最近お世話になりまくりのチャッピーこと、ChatGPT!

質問したら、素敵なコードを吐き出してくれました。

function deepcopy(t)
    local r = {}
    for k,v in pairs(t) do
        if type(v)=="table" then
            r[k] = deepcopy(v) -- 再帰コピー
        else
            r[k] = v
        end
    end
    return r
end

これです。

これだと、リストタイプ、辞書タイプ、混合でも良いし、テーブルの中のフィールドがテーブルにも対応しています(マルチ)!

for文のpairsを使って、インデックスや辞書のキーを読み込む所や、if文でフィールドをtypeでテーブルか調べて、そうならば再帰で自分自身を呼び出しているところがミソです。

returnでコピーテーブルを返しているところは違いますが、コピー先で受け取ればいいだけなので、2つ作る必要のあった関数を1つで済ますことが出来ました。

コメント

タイトルとURLをコピーしました