CASIO pocket computer
PB-100の宇宙

top > ゲームライブラリ > BLACK♥JACK > プログラムリスト

脱衣xトランプx偽装アクション
BLACK♥JACK
by PBロッキー

プログラムリスト

    1 VAC :A$="♥[":E$=" ":F$=".":GOSUB 18:PRINT CSR 4;"B♥J"
    2 PRINT " ₑ₋;π";MID(B*5+1,5);"=";:GOSUB 11
    3 V=0:GOSUB 8:Y=V:V=0:GOSUB 9:C=3
    4 GOSUB C+6:IF C≠1 THEN 5-SGN X
    5 V=Y:Y=X
    6 GOSUB 8:IF X-FRAC V≦Z+15 THEN 7-SGN X
    7 Z=SGN (X-Y:B(EXP Z)=B(EXP Z)+1:PRINT D;Y;"×";X:GOTO 2+19*INT (D/4
    8 PRINT "♥";
    9 W=1+INT (RAN#*13:J=W:I(LOG J)=10:I(J)=11.1:V=V+J
   10 U(V/22)=SGN FRAC V*(V-10.1:X=INT V:PRINT W;X;
   11 C=2:N=2:T=0
   12 IF H<0;G=-30:H=-H:C=4
   13 $="Σ:: ]&÷! ]&÷- )8[・D=: ・D=: ・y-":IF C≠2;IF B≠5;PRINT :RETURN
   14 IF KEY="4";C=C-SGN C
   15 IF KEY="6";C=C+SGN (4-C
   16 G=G+1/H:IF G+5<B THEN 12
   17 IF KEY="Q";K(C)=SGN N:M(C*N)=0:P(C)=4
   18 PRINT CSR 0;"/ □□ I=ₑ ";E$(N/2);A$(T);CSR G+5;"&";CSR C+6;"Ω";
   19 IF INT G=0;IF B≦T;H=SGN C+N-5
   20 IF INT G≦C THEN 14
   21 PRINT "Owari"

技術情報

変数表

A$"♥["
Bエリの負け
Cプレイヤーの座標など
Dプレイヤーの負け
E$" "
F$"."
G母の座標
H母の速さ
Jカードの得点
Nトランプの状態
Tエリの状態
V合計内部計算用
Wカード表示用
X合計表示用
Y合計退避
Z結果
I,K-M,O-S,U未使用(破壊)

行番号マップ

1タイトル表示他
2エリのグラフィック表示他
3エリ一枚目、プレイヤー一枚目他
4~5プレイヤーターン
5~6エリのターン
7結果処理、おわり判定
8~10新しいカードの加算、表示他
11部屋モードの初期設定他
12母の設定他
13キー入力からの復帰他
14~15キー入力
16母の移動、部屋モード突入判定
17プレイヤーアクション
18部屋モード表示
19母に見つかる判定、母の速さセット
20部屋モードおわり判定
21おわり表示

オープニングデモの真相

まずは、オープニングデモに注目いただきたいところです. デモ表現は作品のコミカルな世界観に一役買っておりますが、このクラスのゲームとしては不釣合いな機能に感じるかもしれません.

実はこのデモは変数の設定を兼ねていて、:GOSUB 18 の命令だけで GH (母の初期位置と移動速度)さらに $ の設定を終えているのです.

$="~" は巨大なので置き場に困り、結局 13 行目に落ち着くことになりました.ゲーム速度やメモリへの圧迫を最小にするベストな位置のはずです.

配列変数を使って IF 文を省略する

さて、今作で特筆すべきは 9 行目のカードの得点計算と、17 行目の Q キーによるプレイヤーのアクションです.

それぞれ最初は数行が必要だったのですが、一行にまとめることができました.これには配列変数を使って IF 文を省略する、というテクニックが使われています.

省略前のリストを完成版と対応させて紹介しますので解析の参考にしてください.ちなみに私はこのテクニックをメビウス氏の『特集BASICプログラミング入門 1ステップに命を削る』で学びました.

パート処理初めのリスト完成版リスト有効な変数
/被破壊変数
得点計算新しいカード9 W=1+INT (RAN#*13:J=W
10以上の得点:IF J>9;J=10:I(LOG J)=10IJ
Aの得点10 IF J=1;J=11.1:I(J)=11.1JKLMNOPQRS
得点処理合計が22以上10 IF V>21;V=10 U(V/22)=UV
0 点または A を 1 点として計算SGN FRAC V*(V-10.1
(行の追加は 2step 消費!)(別処理は次の行へ):(別処理が続く)
アクションキー入力判定17 IF KEY≠"Q" THEN 2117 IF KEY="Q"
トランプ拾う18 IF C=3;N=SGN N;K(C)=SGN NKLMNO
トランプしまう19 IF C*N=1;N=0:M(C*N)=0MNOPQRS(T)
エリを隠す20 IF C=4;T=4:P(C)=4PQRST

小数部にフラグを持たせる

9 W=1+INT (RAN#*13:J=W:I(LOG J)=10:I(J)=11.1:V=V+J

「1(Aエース)は11点になるのに 11.1 とするのはどうしてだい?」という声が聞こえてきたところで… それについての説明に入りたいと思います.

実はこの 0.1 はエースを 11 点としてカウントした時のフラグなのです.そして得点が加算されたときフラグも合計得点の小数部に保存されます.

手札の中のエースを 11 点として計算していたら、合計得点が 21 点を超えた場合エースを 1 点として数えなおす、というルールをプログラムでは合計得点(変数 V)が 22 以上になった場合、 V の小数部が 0.1 以上なら(エースを 11 点としていたら)、V-10.1 としてエースの数え直しとフラグの処理をします.(エースが連続しても正しくカウントすることに注目!)

FRAC 関数で簡単に小数部を抜き出せることもあり、フラグ用に新たな変数を用意するより少いメモリで処理することができます.

それにしても、「1ステップに命を削る」、すばらしい.

コラム
配列変数を使って IF 文を省略するための変数使用状況の見直し

使い切らない基本変数

上表で被破壊変数の項を参照いただくと、9 行目の処理では実に 10 個もの変数が破壊の対象です. これは変数 I K L M N O P Q R S が 9 行目をまたいでデータを保持する利用には適さない、ということです.

一度にこれほどの変数領域を浪費する手法には抵抗感があるかもしれませんが、そもそも 26 個の基本変数を使い切るゲーム作品は少ないです.

マイナスの DEFM 命令(変数を減らしてステップを増やす命令ってどうしてないのでしょう?)といったものも無いので、頭の隅に入れておく価値はあると思います.

破壊可能変数の確保

ところで今作では連続する大規模な被破壊変数を設けるために、軽度ながら一時的なデータ用の変数の使い回しを行っています.

今回は幸いにしてリストの判読を困難にするほどのものではありませんでしたが、変数の使用状況が切迫すれば変数の使い回しが頻発することは容易に想像できます. (変数の増設はなるべく避けたいですし、Z(1)=100 などと参照しているとメモリを大きく浪費します.)

こういった場合は後のバージョンアップやユーザーの解析に資するためにも、丁寧な変数表を用意しておきましょう. また所要の最適化が達成できた時点で、解析のしやすい変数使用にも留意したいところです.

変数もまたメモリの一部なのです.