monolithic kernel

HSP3 ショートプログラミングTips その2

前回の続きです。ひとつの記事にだらだらと続けてしまうといつまでたっても書き終わらないし、なにより読みづらいので分割しました。

double型のリテラル・定数 (-24bytes)

改善前 (60bytes)

x = 0.0
y = 0.0
z = 0.0

改善後 (56bytes)

_0_0 = 0.0
x = _0_0
y = _0_0
z = _0_0

解説

axファイルの構造上、整数と変数はその場に埋め込まれますが、それ以外の値は別セクションのテーブルに書きこまれ、そこへの参照が保存されるため容量が膨らみます。そこで、同じ実数値を3回以上利用する場合、一度変数に入れておいたほうが容量を削減できます。また、整数は16ビット符合なしの範囲で表現できるものは4バイト、表現できないものは6バイトになるため、65535を超える正の整数や負の整数についても利用回数が多い場合は一度変数へ代入することで容量削減になります。

さらに改善後 (36bytes)

#const VARTYPE_DOUBLE 3
dimtype x, VARTYPE_DOUBLE
dimtype y, VARTYPE_DOUBLE
dimtype z, VARTYPE_DOUBLE

解説 その2

こちらは0.0を代入する場合に限りますが、dimtypeを利用することで更に容量を削減することができます。型タイプはvartype関数で取得できるとドキュメントには記述されていますが、組み込み型の値は固定されているので決め打ちしても問題なさそうです。

2つの値のうち大きい方をとる(max) (-10bytes)

改善前 (42 bytes)

x = a
if b > a {
  x = b
}

改善後 (32bytes)

#const INFINITY 65535

x = limit(a, b, INFINITY)

解説

limit関数はaが第2引数以上第3引数以下の範囲に収まるようにする関数ですが、このうち片側のみを利用することで、aがb以上であればa、bより小さければbを返す関数として利用できます。もう片側は絶対に使わないような大きな値を指定しておけば無視できます。INFINITYを65536以上の値にすると2バイト増えますが、それでも改善前よりは小さく抑えられます。limit関数は地味ながらかなり強力で、少ない容量でいろいろできる楽しい関数です。

HSPTVのランキング表示 (-181bytes)

改善前 (383bytes)

#include "hsptv.as"

hsptv_up -1, ""
repeat
  hsptv_getrank score, name, comment, cnt
  if score : else { break }
  // ...
loop

改善後 (202bytes)

#runtime "hsptv"
#regcmd 18
#cmd hsptv_send $00

if 0 {
#define global notenext _
#defcfunc notenext
  noteget temp
  notedel
  return temp
}

notesel ranking
hsptv_send ranking, -1
ranking_temp = ranking
notesel ranking_temp
repeat notemax / 3
  score = notenext()
  name = notenext()
  comment = notenext()
  // ...
loop

解説

hsptv.asで定義される命令はhsptv_send命令のラッパなので、直接hsptv_send命令を利用したほうが容量を削減できます。hsptv_send命令で取得できるランキング情報は改行区切りでスコア・ユーザ名・コメントが列挙されているだけのテキストファイルなので、note系の命令を使うと効率よく処理できます。この時、別バッファに一旦データをコピーし、破壊しながら読み取るようにして常に先頭行のデータを読むようにすることで、読み込み位置を指定する引数を省略できるようになり、容量を節約できます。

追記

  • 2011/03/15
    • 整数について追記