Paper Calc 製作過程(3)

Home PC-6001mkII Program etc

 このページでは、V1.3相当(2007/09/18)からV1.4(2007/10/14)までを載せています。
製作過程一覧は、こちら

2007/09/18:やりたい事
 やりたい事としてあったのは、前回入力値を引き継ぐ「定数演算」だ。
どういうものかというと、例えば

105 × 5 = 525
3 = 315

 というように、2回目以降の「105 ×」を省略することができる機能だ。

 この機能は、意外にも現在売っているほとんどの電卓ででき、そしてWindows標準の電卓ではできない(少なくともWindows XPまでは)。

 コンテストとしては、これを入れたところで評価にはほとんど影響しないだろうが、それよりも自分の作りたいモノを作っておきたい。

 その他、無茶ついでに、8/11時点でそこそこの実装にしていた部分も、より忠実に入れるべく挙動を調べる事にする。

2007/09/20:100円電卓の機能調査
 100円電卓を実際に使って、とりあえず2つの数字までの計算で表示結果を調べて計算方法を類推してみる。

 mとnは入力する数字で、Stは一時的に覚えていると思われる値、Ansは=を押したときに表示された結果値、とすると、以下のようになった。一時記録値や結果の計算式はあくまで憶測ではあるが、そう大きくは外してないと思う。いや思いたい。

前回演算子入力結果(Ans)一時記録値(St)
(任意)m + n =m+n
(任意)m − n =m−n
(任意)m × n =n×m
(任意)m ÷ n =m÷n
(任意)m + =St+m
(任意)m − =St−m
(任意)m × =m×m
(任意)m ÷ =1÷m
m =m+St(変化なし)
m =m−St(変化なし)
×m =St×m(変化なし)
÷m =m÷St(変化なし)
Ans+St(変化なし)
Ans−St(変化なし)
×St×Ans(変化なし)
÷Ans÷St(変化なし)
(任意)+ =St+AnsAns
(任意)− =St−AnsAns
(任意)× =Ans×AnsAns
(任意)÷ =1÷AnsAns
(任意)+ =Ans+m
(任意)− =Ans−m
(任意)× =m×AnsAns
(任意)÷ =Ans÷m

 掛け算とその他で演算の方向が逆になる事はわかっていたが、「×=」で二乗、「÷=」で逆数になる事が初めてわかった。やはり何事にもやってみないとわからない事があるもんだと実感する。

 さて、とりあえずプログラムサイズの事は棚に上げておいて実装してみるか。

2007/09/25〜29:実装開始
 9/20までにわかった計算処理を元に、プログラムを作成する。この段階で、9/20時点では m,n,St,Ans の4種類だった値を3種類に切り詰める事にする。こうする事で、同じような処理を統合しやすくなる、はずだ。

 具体的には、入力値がmとnの2種類あるときに計算の種類にとってどちらかの値を一時記録値Stに代入することで、計算に必要な値をひとつ減らすことにする。

 具体的と言っておきながらなかなか曖昧だが、まあなんとかなるだろう。プログラムには、時としてある種の勢いも必要だ。

 という事で、値の代入には少してこずったが、なんとかそれらしい計算処理まで行えるようになった。

2007/09/27〜29:キー入力が...
 9/16に「objsel」を外して様子を見ていた件だが、問題が出た。実効中に他のウインドウに移ってからPaper Calcのウィンドウに戻ると、一部を除くキー入力が効かなくなっていた。

 どうやら、Paper Calcの画面が非アクティブになった時点で入力ボックスからフォーカスが外れるらしい。かといって「objsel」を常に付けるようにすると、せっかく対策した非アクティブ時のキー入力に反応するバグが復活してしまう...。

 しばらく解決策が思いつかなかったが、翌々日になってふと気付いた。「アクティブ時だけobjselを常に付ける」とうまくいくのでは、と。

 HSP標準で「ginfo_act」という今回の処理にはおあつらえ向きの情報があったので、これを条件としてobjselの実行を行うようにする。...うまく行っているようだ。

 細かいバグはもう少しあるかも知れないが、予定していたものは全て入れ終えた。あとは、プログラムサイズとの戦いだ。

2007/09/30:関数化で減量
 この時点で、start.axのサイズは7,707バイト。規定より1,707バイトも大きい、という事で、棚に上げておいたサイズ削減を集中して行う事にする。

 まず、各場合の計算処理の書式を合わせた後に、1つの関数に置き換える。ここでどこまで削減できるかが大きな山になる。結果は...6,777バイト。あと777バイトだ。

これまでも何度かサイズ削減した上でこの状態なので、正直な話ここまでサイズを詰められるとは思えない。

2007/09/30〜10/04:サイズ削減記録早回し
 ここからは地味なサイズ削減が続く。少し手抜きだが、この時に書き留めたメモを小さく紹介しておく。サイズ削減は一日にしてならず、だ。

2007/09/30:6,777 → 6,587 (削減:190)
・関数Rの第3パラメタが0の時に第3パラメタを付けない ⇒ 6,757
・=処理で、[3]と[4]or[6]の処理をまとめる ⇒ 6,723
・c_mode = 0 → dim c_mode ⇒ 6,719
・=処理で、さらに[3]〜[7]の処理をまとめる ⇒ 6,667
・82行「s_000 = "0000000"」が未使用のため削除 ⇒ 6,647
・関数Rの処理で、演算子なしの場合の戻りを忘れてた ⇒ 6,655
・154行「if ginfo_act = 0: objsel」→「if ginfo_act: else objsel」 ⇒ 6,653
・199行「if c_mode < 7 && c_mode > 3」→「c_mode = 5」 ⇒ 6,637
・203行「cf_val = F0_0」削除(直後にc_valを元にした数が入るため) ⇒ 6,625
・if c_mode = 1: c_mode = 4
 if c_mode = 3 || c_mode = 5 || c_mode = 7 {
  cf_stock = R(cf_stock, cf_val)
  c_mode = 6
 }
 →
 if c_mode = 1 { c_mode = 4 } else {
  if c_mode & 1 { ;c_mode:3, 5, 7
  cf_stock = R(cf_stock, cf_val)
  c_mode = 6
  }
 }
  ⇒ 6,599
・542行「objsel」削除(アクティブ時に毎回objsel実行するようにした) ⇒ 6,595
・145行「input I, 0, , 1」→「input I, 0」 ⇒ 6,587

2007/10/01:6,587 → 6,470 (削減:114)
・「if b_code * c_dot = -10: dim c_dot ;b_code = 10 && c_dot = -1」
 → 「c_dot *= (b_code * c_dot != -10)」 ⇒ 6,581
・335行〜
 keta = c_dot + (c_dot = MINUS1)
 c_str0 = strf("%." + keta + "f", cf_disp)
 if keta : else { c_str0 += "."}
 →
 c_str0 = strf("%." + c_dot1 + "f.", cf_disp)
 c_len = strlen(c_str0) - 1 - (c_dot1 != 0) ⇒ 6,540
・348行「poke c_str0, c_len + 1, 0」削除 ⇒ 6,516
・c_lenの値を+1する ⇒ 6,508
・481行「if d_sy > 580: d_sy = 0」→「d_sy *= (d_sy < 581)」 ⇒ 6,498
・497行「W(0)」→「W()」 ⇒ 6,494
・547行「onkey 0: await: onkey 1」削除 ⇒ 6,474
・538行「end」削除 ⇒ 6,470

2007/10/02:6,470 → 6,438 (削減:32)
・122行「bc = 164 - cnt * 4」
 →
 (loop外)「bc = 168」(loop内)「bc += 4」 ⇒ 6,466
・「if ginfo_act : else objsel」→「objsel ginfo_act」 ⇒ 6,454
・280行「if c_mode = 0 {」→「if c_mode: else {」 ⇒ 6,452
・328行「if c_mode = 0 || c_mode = 2: cf_disp = cf_ret」
 →
 「if c_mode * (c_mode - 2): else { cf_disp = cf_ret}」 ⇒ 6,450
・「if cf_disp >= 100000000 || cf_disp <= -100000000 {」
 →
 「if cf_disp * cf_disp >= 10000000000000000.0 {」 ⇒ 6,446
・554行「input I, 0, , 1」→「input I, 0」 ⇒ 6,438

2007/10/03:6,438 → 6,408 (削減:30)
・227行 クリアボタンの処理をc_err判定より前に移動、かつ
 「if c_err && (b_code < 16): b_code = MINUS1」
 → 「if c_err: b_code = MINUS1」 ⇒ 6,422
・「if b_code > MINUS1」部分を外出し かつ
 「if (b_code > MINUS1) && (b_code < 11) && ((c_mode & 1) = 0) {」
 → 「if (b_code < 11) && ((c_mode & 1) = 0) {」かつ
 「if b_code > MINUS1 && b_code < 10 {」
 → 「if b_code < 10」 ⇒ 6,408

2007/10/04:6,408 → 6,136 (削減:272)
・30行「if c_ope = 4 {」→「if c_ope {」 ⇒ 6,400
・190行「peek(I, 0)」→「peek(I)」 ⇒ 6,396
・c_mode:6 → 12, c_mode:7 → 13 ⇒ 6,380
・130行「boxf bx, by, bx + 80, by + 80」
 → 「boxf bx, by」 ⇒ 6,356
・星クリックでキャラクタが変わる隠しを削除 ⇒ 6,270
・390行〜 n を -1スタートにしてnカウントの順序を前にする ⇒ 6,266
・431行「peek(c_str, 0)」→「peek(c_str)」 ⇒ 6,262
・引きずり処理X方向の対象をX=0〜4 → X=1〜5 に変更 ⇒ 6,254
・関数Wの計算を、左上を基準にした4点の平均ベクトルに変更 ⇒ 6,136

2007/10/05:奇跡
 もう無理、と何度も思いながらも、ようやくあと136バイトまでこじつける事ができた。あともう数歩、でももう無理。

 ここで、作成した関数の戻り値を見直すことにする。これまで、メイン処理の計算式中で同じ関数を何度か呼び出していたが、思い切ってその計算部分を関数の戻り値に含めてみた。

 関数部分のサイズは増えるが、全体ではサイズが減るのでは、と期待して変更してみると、予想を超える事態が起こった。なんと一気に 228バイトも縮まり、逆に92バイトの余裕ができた。奇跡だ。

 こうなると次にする事は、10/04で泣く泣く外した隠し処理の復活だ。
 もともとは★をクリックすると●等のキャラクタに置き換わるものだったが、これを 凹凸モード切り替えに変更する。凸モードも、これはこれでしっくりきているような気がする。

2007/10/14:動作確認
 プログラムを一通り終えた後に残るのがテストだ。この工程がもっとも重要な事は良くわかっているが、どうにもやる気がおきない。という事で、どうしてものびのびになる。

 いい加減にケリを付けようと思い立ち、さまざまなケースでテストを行う。すると、いつの間にか0割り時のエラーが出ない事がわかった。この修正を終えると、今度は start.axが6,006バイトと若干オーバーしてしまった。

 幸い、また別に削減できる箇所が見つかり、ギリギリに近い 5,998バイトに収まった。

 これで、ようやく V1.4として完成した。


製作過程(2) Paper Calc 製作過程