ループの理解はとても大切で、これが出来なければゲームが出来ないと言い切っても過言ではありません。そのため、今回は抜き打ち的にテストを実施しました。ループは最低でももう一度テスト、もしかするとさらにもう一回テストを行うかもしれません。ループを徹底的に理解できるように、内藤としては祈っております。では、各設問毎に解説していきます。
- 解13. よくあるRPGの導入部
入力判定とループを如何に組み合わせるかが、この問いの肝要な部分となります。ループからの脱出を break; とする場合は、ループそのものはどのような方法でも構いません。ループの脱出を入力された文字が y または Y だったら…とする事も出来ますが、その場合は、メッセージの表示の流れが悪くなりますのでオススメできません。
ということで、私なら以下のように処理します。
char key; while (1) { printf("これを長老まで届けてくれぬか?(Y/N) : "); rewind(stdin); scanf_s("%c", &key, 1); if (key == 'y' || key == 'Y') break; if (key == 'n' || key == 'N') { printf("そう言わんと頼みます。\n"); } } printf("さすがは勇者様ですな。\n");
ループを while による無限ループとしています。なお、VS2022 のインテリセンスは while(1) ではなく while(true) をオススメしてきました。どちらでも構いませんので、理解しやすい方を選択して大丈夫です。
最初に問いかけのメッセージを表示します。そして scanf_s …と書きたいところですが、ループしてきた場合、この入力の前にキーバッファに余分な文字が残っている可能性があります。これを消すために、直前で rewind(stdin); と記述しています。rewind(stdin); は標準入力を巻き戻すという動作です。標準入力は特に変更していない場合はキーボード入力です。これを巻き戻すという事で、全ての入力を無かった事にしています。
scanf_s で文字入力を行う場合は、バッファオーバーランというセキュリティホールを潰すために、第3引数として入力文字限度数を設定します。今回は1文字だけなので、1 としています。その結果、key という変数に入力された文字が y または Y なら break; つまり、無限ループから脱出しています。無限ループから脱出した直後に「さすがは…」と表示して終了となります。
ループが中断されなかった場合は、今度は n または N が入力されていたら「そう言わんと…」と表示しています。それでループのスコープが終わりますので、またスコープのトップに戻って、while のループ条件を確認します。ここは固定値 1 なので、ループが絶対に終わる事は無く、そのまま二周目三周目と無限に続きます。
- 解14. ランダムスター
こちらはループ回数の指定がありますので、for を使うのが適当です。そして、色は7種類ありますので、その場合分けを行うには switch の使用が適当と考えます。実は文字列配列という処理方法を覚えたら、もう少し簡単に実装する方法はありますが、これは後日説明します。
という事で、私のサンプルを提示します。
srand(time(NULL)); for (int i = 0; i < 10000; ++i) { int x = (rand() % 76) + 1; int y = (rand() % 25) + 1; printf(LOCATE, y, x); switch (rand() % 7) { case 0: printf(FBLUE); break; case 1: printf(FRED); break; case 2: printf(FMAGENTA); break; case 3: printf(FGREEN); break; case 4: printf(FCYAN); break; case 5: printf(FYELLOW); break; case 6: printf(FWHITE); break; } printf("★ミ"); } printf(FBLACK); printf(LOCATE, 24, 0);
ループ開始前に乱数の初期化を行います。そして、for で 10000回のループを指定します。座標は範囲で剰余を求めてから、+1 として取得しています。座標系は 1 からとなりますので +1 が必要なんですね。この座標取得を直接 printf 内に記述しても良かったのですが、デバッグで x,y の座標を見たかったので、一旦変数に入れていたりします。
色は7種類なので、rand() で得られた値を 7 で割った余りを求めれば 0 ~ 6 までの数値を得る事が出来ます。その値を直接 switch の判定内部で記述しています。case 0 から case 6 まで用意して、そこに直接色変更の printf を記述しています。個人的には +1 して青色が 1 で、白色が 7 のほうがより理解しやすいのですが、まあデジタルカラーコードは今時知っている人の方が少ないので😓
座標と色が指定できたら、その場所に printf で ★ミ を表示します。これでループのスコープが終わりますので、二周目のループとなります。ループの際に ++i されて、ループ条件が 1 が 10000 未満なので、結果として 10000回のループとなるわけです。
最後の最後、ループから抜けた直後に黒色で画面下にカーソルを移動させているのは、折角楽しく作ったランダムスターを、システムメッセージで壊されるのが悲しかったためですね。
※ 仲間内が集まったらこんなゲームで遊ぶのも良い!- 解15. 歩く人間
これの実装方法は本当にいろいろあります。
- 画面全体を消して人間を描き直す
- 以前の人間を消してから新しい座標で描き直す
- 左側移動なので、右一列だけ余分に空白を表示する
上記の方法ほどちらつきが激しくなります(が、今時のPCは高速なのでさほど気にならなかったり😓)。私は一番下の方法で実装してます。このいろんな考え方の事をアルゴリズムと言います。同じ処理なのに、高速に動作したり綺麗に表示したり消費メモリが少なかったりと、アルゴリズムによってかなりの差が出る事を理解してください。小手先の高速化で苦しむより、アルゴリズムを最適化する事でサクッと数百倍に高速化する事なんてざらにあります。
という前置きはそろそろ置いといて、私のコードを提示します。
for (int x = 79; x > 0; --x) { printf(FWHITE); printf(LOCATE, 1, 1); printf("X座標:%2d", x); if (x % 2 == 0) { printf(LOCATE, 3, x); printf(FYELLOW); printf("<●/ "); printf(LOCATE, 4, x); printf(FGREEN); printf(" ■ "); printf(LOCATE, 5, x); printf(FCYAN); printf(" |/ "); } else { printf(LOCATE, 3, x); printf(FYELLOW); printf("_●> "); printf(LOCATE, 4, x); printf(FGREEN); printf(" ■ "); printf(LOCATE, 5, x); printf(FCYAN); printf("/ | "); } Sleep(200); } printf(LOCATE, 24, 0);
右側から左側に移動してます。これはX座標が徐々に小さくなってゼロになったら終了するカウンターだと考えられるため、私は for を使いました。動きが固定的であれば、for を使うのは悪くない選択となります。…が、それがベストかどうかは、自分が実装したい内容によって異なる点に注意してください。例えば、X描画毎回ランダムに変化して、それがたまたま 40 なら表示が終わるという実装なら、for よりも while や do~while のほうが適切になると思います。
さて、ループの最初に現在の座標を左上に表示します。ループの結果、色が何色になっているか分からないので、白色で初期化しています。%d ではなく %2d としているのは、数値表示を常に 2桁とするためです。これで、座標が 2桁から 1桁に減った際に文字が残らずに済みます。
※ 直後の1文字が勝手に消える環境もあります
アニメですが、私は X座標とリンクさせる事にしました。これは X 座標が奇数か偶数かでどちらの人間パターンを表示するかを振り分けています。ここは switch でも問題ないです。あるいは別途アニメカウンター変数を用意してても良いです。例えば、キーボードで上下左右に歩けるようにした場合は、座標とリンクさせてしまうとアニメが正しく行われません。先にも説明しましたが、何をしたいかによってベストな実装方法は変わってきます。
人間を表示した後は Sleep(200) として時間待ちをしています。
※ このような時間待ち処理は、今はあまり推奨されていませんが今回はお勉強なので😁
ループから抜けたら、システムメッセージが表示の邪魔をしないように、下にカーソルを移動させて終了しています。
※ サメが出たら馬鹿ゲー決定!サメの映画監督に感想聞いている時点でお察しwww
>> C言語 実力確認テスト04 ループに戻る
>> C言語014 ループ制御に進む
※ サメが出たら馬鹿ゲー決定!サメの映画監督に感想聞いている時点でお察しwww
コメント