見出し画像

【IchigoJam】多いし泉ゲーム【大石泉生誕祭2024】

今日は大石泉の誕生日だ。
そこで、IchigoJamで「大石泉」をたくさん集めるゲームを作ってみた。

※IchigoJamはjig.jpの登録商標です。

ルール

グリッド上の各マスに、「大」「石」「泉」の文字がランダムに配置される。
一番左上のマスから一番右下のマスまで移動する間に、文字を「大石泉」の列ができるだけ多くできるように通ろう!
ただし、この順番に合わない文字のマスに移動したとき、その文字は無視される。
また、移動できるのは、今居るマスから1つ右のマスと1つ下のマスだけである。
(すなわち、左や上には行けない)

操作方法

  • Dキー / →キー:右に移動する

  • Sキー / ↓キー:下に移動する

  • スペースキー:ゲーム終了時、次のゲームを開始する

実行例

ゲームを行った結果の例

プログラム

10 ' オオイ シ イズミ ゲーム
20 POKE#700,16,16,254,16,16,40,198,0,254,32,32,124,164,36,60,0,16,124,68,124,218,84,178,0:FORI=0TO23:POKE#718+I,~PEEK(#700+I):NEXT
30 CLS:CLV:C=#800:P=#840:FORY=19TO0STEP-1:FORX=19TO0STEP-1:R=RND(3):LOCATE2+X,2+Y:?CHR$(#E0+R);:FORI=0TO2:IFR=IJ=(I+1)%3:D=I=2ELSEJ=I:D=0
40 A=PEEK(C+X*3+3+J):B=PEEK(P+X*3+J):POKEC+X*3+I,A+(B-A)*(B>A)+D:NEXT:NEXT:T=C:C=P:P=T:NEXT:M=PEEK(P):X=0:Y=0:C=0:S=0:LOCATE24,2:?CHR$(#E0,#E1,#E2);"x0";
50 R=SCR(X+2,Y+2)&3:LOCATEX+2,Y+2:?CHR$(#E3+R);:IFR<>SGOTO70
60 S=(S+1)%3:IFS=0C=C+1:LOCATE28,2:?C;:LOCATE24,4:?"   ";ELSELOCATE23+S,4:?CHR$(#DF+S);
70 LOCATE0,22:IFX=19ANDY=19GOTO110
80 K=INKEY():IFX<19AND(K=RIGHTORK=#44ORK=#64)X=X+1:GOTO50
90 IFY<19AND(K=DOWNORK=#53ORK=#73)Y=Y+1:GOTO50
100 GOTO80
110 LOCATE24,6:?"コンカイ ノ";:LOCATE24,7:?"サイダイ ハ";:LOCATE24,8:?M;" デシタ";
120 LOCATE24,10:IF C<M?"ザンネン!";ELSE?"ヤッタネ!";
130 LOCATE24,12:?"スペース デ";:LOCATE24,13:?"ツギ ノ";:LOCATE24,14:?"モンダイ";:LOCATE0,22
140 IFINKEY()=#20GOTO30ELSEGOTO140

このプログラムは、CC BY 4.0 でライセンスする。

OneFiveCrowd で実行 (高速、非公式) (推奨)
IchigoJam web で実行 (公式、低速)

解説

各変数の役割

  • 初期化処理

    • I:ループ変数

  • 文字配置・最適解計算

    • C:現在の行の情報のポインタ

    • P:1段前の行の情報のポインタ

    • X:今の状態における横座標

    • Y:今の状態における縦座標

    • R:選択した文字

    • I:今の状態における取るべき文字

    • J:次の状態における取るべき文字

    • D:今の状態で増える得点

    • A:今の状態から右に進んだ後の得点

    • B:今の状態から下に進んだ後の得点

    • T:ポインタ交換用の変数

    • M:求めた最適解 (得点)

  • ゲーム

    • X:今居る横座標

    • Y:今居る縦座標

    • C:今の得点

    • S:次に取るべき文字

    • R:今の位置にある文字

    • K:入力されたキー

各行の役割

  • 10行目:FILES 対応のタイトル

  • 20行目:美咲フォントの「大石泉」をキャラクターパターン領域に格納し、さらにその白黒を反転したキャラクターパターンを生成する

  • 30~40行目:「大」「石」「泉」のランダム配置と最適解の計算を行い、画面と状態を初期化する

  • 50行目:通った場所を白黒反転し、次に取るべき文字かを判定する

  • 60行目:次に取るべき文字を通った場合、状態 (スコア・次に取るべき文字) を更新する

  • 70行目:プログラム停止時の見栄えを良くするためのカーソル位置設定を行い、右下に到達したかを判定する

  • 80~100行目:キー入力を受け付け、それに従って移動を行う

  • 110~130行目:ゲームが終了したので、最適解などのメッセージを表示する

  • 140行目:スペースキーが押されるまで待機し、押されたら次のゲームを開始する

最適解の求め方

動的計画法を用いて最適解を求める。
移動とは逆の下から上、右から左に計算を進め、各マス・およびそのマスに入った際の次に取るべき文字について、その状態から得られる得点の最大値を計算していく。
その状態から得られる得点の最大値とは、その状態から右に移動したときに得られる得点の最大値と、その状態から下に移動したときに得られる得点の最大値の大きい方 (小さくない方) である。
ただし、次に取るべき文字が「泉」で、マスに配置された文字も「泉」のときは、この値に 1 を足した値になる。
一番右のマスから右に移動したときの得点の最大値、および一番下のマスから下に移動したときの得点の最大値は 0 とすることで、これらを特別扱いせずに計算が可能である。
次に取るべき文字とマスに配置された文字が一致しているときは、移動する際、次に取るべき文字を1個進める。

マスに配置された文字 (「大」「石」「泉」をそれぞれ 0、1、2 で表す) を g[y][x]、次に取るべき文字が c のときの得点の最大値を s[y][x][c] とすると、漸化式は

s[y][x][c] = max(s[y + 1][x][n(y, x, c)], s[y][x + 1][n(y, x, c)]) + d(y, x, c)

n(y, x, c) = (c + 1) mod 3 (g[y][x] = c のとき)
              c            (そうでないとき)

d(y, x, c) = 1 (g[y][x] = 2 かつ c = 2 のとき)
             0 (そうでないとき)

となる。

今回扱うグリッドのサイズは、20×20である。
各マスについて3通りの次に取るべき文字を考えるので、20×20×3=1200 通りの状態がある。
この状態全てを IchigoJam のメモリに乗せるのは難しいが、計算を行う上では現在計算している行とその1個下の行の情報だけを保持しておけばよい。
これは 20×2×3=120 通りの状態である。
さらに、今回の移動で通るマスの数は約40であるため、得点の最大値は255以下であり、1バイトで表現できる。
よって、この 120 通りの状態の情報は、約200バイトある配列用の領域に格納することができる。


いいなと思ったら応援しよう!

この記事が参加している募集