vm2gol v2 製作メモ(26) 配列とVRAM その2 / ダンプ表示の改良


さて、前回やっつけで VRAM を用意しましたが、 今回は VRAM の仕様というか使い方みたいなものを簡単に書いておきます。

あわせて、前回お手軽に inspect で済ませていたダンプ表示を いい感じに修正します。


ライフゲームの盤面のサイズは 縦5 x 横5 = 25 セルとします。

前回 Ruby のコードで書いたように、 次世代の盤面を一時的に置くバッファ領域として 5x5=25 の領域がもう一つ必要です。 これについては、VRAM のサイズを 50 にして、 後ろの方の 25個を使うことにします。

これに関しても、 vram_main, vram_buf のように 2つに分ける方式をちょっと考えた気がしますが、 とりあえず1個のままで進めました。 2つに分けた場合は、VM命令を増やすか、 または VM命令の引数で制御できるように 修正しないといけなくなり、うーんそれはちょっと…… とか、そんなことを考えてたような気がします(忘れました)。


スタック領域のように1行1アドレスの形にすると 表示スペースを取りすぎるので、ダンプではコンパクトに表示させます。 0 か 1 しか入らないし、2次元の表示になってほしいので、

---- memory (vram) ----
..... .....
@.@.. ..@..
.@@.. @.@..
.@... .@@..
..... .....

このように表示されるようにします。 左側がメイン領域、右側がバッファ領域。 . が死んでいるセル、 @ が生きているセルです。


各領域の左上を原点として、 右向きが x 軸、下向きが y 軸とします。

xy座標を VRAM のアドレスに変換するには、 メイン領域の場合は

y * 5 + x

で、バッファ領域の場合はこれにオフセットとして 25 を足してやればよいでしょう。

たとえば原点 (0, 0) にアクセスしたい場合は

メイン領域:        0 * 5 + 0 => 0
バッファ領域: 25 + 0 * 5 + 0 => 25

で、座標 (2, 3) にアクセスしたい場合は

メイン領域:        3 * 5 + 2 => 17
バッファ領域: 25 + 3 * 5 + 2 => 42

という計算で VRAM 用のアドレスに変換できます。

下記はダンプ表示での位置とアドレスの対応関係を図にしたものです。

 0  1  2  3  4 | 25 26 27 28 29
 5  6  7  8  9 | 30 31 32 33 34
10 11 12 13 14 | 35 36 37 38 39
15 16 17 18 19 | 40 41 42 43 44
20 21 22 23 24 | 45 46 47 48 49

では VRAM のダンプ表示部分を修正しましょう。

--- a/vgvm.rb
+++ b/vgvm.rb
@@ -18,7 +18,7 @@ class Memory
     # スタック領域
     @stack = Array.new(stack_size, 0)
 
-    @vram = Array.new(10, 0)
+    @vram = Array.new(50, 0)
   end
 
   def dump_main(pc)
@@ -91,8 +91,18 @@ class Memory
     lines.join("\n")
   end
 
+  def format_cols(cols)
+    cols.map{|col| col == 1 ? "@" : "." }.join("")
+  end
+
   def dump_vram
-    @vram.inspect
+    rows = @vram.each_slice(5).to_a
+    main = rows[0..4]
+    buf = rows[5..9]
+
+    (0..4).map {|li| # line index
+      format_cols(main[li]) + " " + format_cols(buf[li])
+    }.join("\n")
   end
 end
 

死亡セルが . 、生存セルが @ となるようにしてみました。

./run.sh 25_vram_set_get.vgt.json を実行すると、 VRAM のダンプ表示のアドレス 0 の箇所が . から @ に変わって また . に戻り、 次に アドレス 1 の箇所が . から @ に変わる、 という挙動が確認できます。

良さそうですね。