配列の使い方に慣れてきましたか?
そろそろ、ゲームを題材にして配列の復習や応用を考えてみましょう。
まずはスロットマシンのようなものを作ってみましょう。
最も単純なつくりで、下のような形のものを考えます。
[ 7 ] [ 7 ] [ 7 ]
リールは3本で、1ラインだけ判定します。
チェリーなどの絵は表示出来ませんから、番号で置き換えます。
また、リールを回すのは難しいため、乱数を使ってスロットっぽく見えるように工夫します。
まずは、考え方を理解するためリール1本でやってみましょう。
#defineを使ってMAX_NUMを定義します。
※NUMはNUMBERの略です。
今回は4種類の絵柄があると考え、MAX_NUMを4とします。
変数reelを作成します。
この変数reelを無限ループの中で乱数を使って更新し続けます。
乱数は1からMAX_NUMまで発生させます。
新しい乱数がセットされたら、画面に表示します。
イメージが出来たら作ってみましょう。
解答例です。
<sample program 073-01>
#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX_NUM 4 int main(void) { int reel; srand((unsigned int)time(NULL)); for (;;) { reel = rand() % MAX_NUM + 1; printf("%d\n", reel); } return 0; } |
<実行結果>
2
1
4
2
1
3
3
1
2
無限に続く・・・
続行するには何かキーを押してください・・・
画面が下にスクロールするので、スロットマシンというイメージでは無いですね。
1つ命令を追加しましょう。
for (;;) { |
の下の行に、
system("cls"); |
と追加してください。
これは、スクリーンをクリアするという命令になります。
<sample program 073-02>
#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX_NUM 4 int main(void) { int reel; srand((unsigned int)time(NULL)); for (;;) { system("cls"); reel = rand() % MAX_NUM + 1; printf("%d\n", reel); } return 0; } |
<実行結果>
2 ↑この数値が次々と変わっていく 無限に続く・・・ 続行するには何かキーを押してください・・・
これでリールが1本できましたから、これを3本に増やすことを考えます。
せっかく配列を勉強してきましたから、変数reelを配列にしましょう。
#defineでREEL_NUMを3に定義し、プログラムを改良してください。
実行結果は以下のようにします。
<実行結果>
[ 1 ] [ 3 ] [ 2 ] ↑この数値が次々と変わっていく 無限に続く・・・ 続行するには何かキーを押してください・・・
解答例です。
<sample program 073-03>
#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX_NUM 4 #define REEL_NUM 3 int main(void) { int reel[REEL_NUM]; srand((unsigned int)time(NULL)); for (;;) { system("cls"); reel[0] = rand() % MAX_NUM + 1; reel[1] = rand() % MAX_NUM + 1; reel[2] = rand() % MAX_NUM + 1; printf("[ %d ] [ %d ] [ %d ]\n", reel[0], reel[1], reel[2]); } return 0; } |
<実行結果>
[ 1 ] [ 3 ] [ 2 ] ↑この数値が次々と変わっていく 無限に続く・・・ 続行するには何かキーを押してください・・・
さて、次はこれをどうやって止めるか考えなければなりません。
自動的に止まるという考え方もありますが、プレイヤーの意志によってリールを止める、ということがゲームという性質上重要なことだと思います。
しかし、これまで使ってきた入力方法はscanfしかありません。
scanfは何かが入力されるまでプログラムを止めてしまいます。
実際に組み込んでみましょう。
<sample program 073-04>
#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX_NUM 4 #define REEL_NUM 3 int main(void) { int reel[REEL_NUM]; int input; srand((unsigned int)time(NULL)); for (;;) { scanf("%d", &input); system("cls"); reel[0] = rand() % MAX_NUM + 1; reel[1] = rand() % MAX_NUM + 1; reel[2] = rand() % MAX_NUM + 1; printf("[ %d ] [ %d ] [ %d ]\n", reel[0], reel[1], reel[2]); } return 0; } |
<実行結果>
[ 3 ] [ 1 ] [ 2 ] 1 ←scanfの入力 [ 1 ] [ 2 ] [ 4 ] 無限に続く・・・ 続行するには何かキーを押してください・・・
このように、何か入力しなければ次の数値が出てこないためゲームになりません。
つまり、今回はscanfが使えないということですので、消してしまいましょう。
※赤い箇所(変数inputとscanfの行)を削除してください。
では、何を使えばプログラムを止めることなく入力を待つことが出来るのかということですよね。
conio.hをインクルードすることで使える_kbhitという命令(関数)を使います。
_kbhitは入力する時にプログラムを止めません。
プログラム例を書いておきますので、別のプロジェクトで試してみてください。
下のプログラムを実行し、zキーを押すと無限ループを抜けて終了します。
#include <stdio.h> #include <conio.h> int main(void) { int key; for (;;) { if (_kbhit()) { /* 入力されたキー(文字)を取得 */ key = _getch(); if (key == 'z') { break; } } printf("*"); } return 0; } |
<実行結果>
************************************************** ************************************************** ************************************************** **************続行するには何かキーを押してください・・・
実行すると「*」が延々と出力されます。
何かキーが押されると、_kbhitが「真」を返してくるため、if文が成立します。
※「真(しん)」は”成り立つ”と捉えてください。逆に”成り立たない”ことを「偽(ぎ)」と言います。
そのキーを取得するため_getchを使って、キー情報を取り出します。
取り出したキーがzキーであればbreak文が実行され、無限ループを抜け出します。
この仕組みを組み込めば、何か特定のキーを押すことでリールを止めることが出来そうです。
< sample program 073-04 >の変数inputをkeyに変更し、scanfの部分を_kbhitを使ったプログラムに変更してみてください。
解答例です。
<sample program 073-06>
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <conio.h> #define MAX_NUM 4 #define REEL_NUM 3 int main(void) { int reel[REEL_NUM]; int key; srand((unsigned int)time(NULL)); for (;;) { if (_kbhit()) { key = _getch(); if (key == 'z') { break; } } system("cls"); reel[0] = rand() % MAX_NUM + 1; reel[1] = rand() % MAX_NUM + 1; reel[2] = rand() % MAX_NUM + 1; printf("[ %d ] [ %d ] [ %d ]\n", reel[0], reel[1], reel[2]); } return 0; } |
<実行結果>
[ 3 ] [ 1 ] [ 2 ]
↑この数値が次々と変わっていき、zキーを押すと数値が確定する。
[ 1 ] [ 2 ] [ 4 ]
続行するには何かキーを押してください・・・
無限ループを抜けた後に、3つの数値がそろっていれば「あたり」です。
3つの数値が同じかどうか調べるプログラムを加え、そろっていれば「あたり!」と表示するよう改良してください。
解答例です。
<sample program 073-07>
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <conio.h> #define MAX_NUM 4 #define REEL_NUM 3 int main(void) { int reel[REEL_NUM]; int key; srand((unsigned int)time(NULL)); for (;;) { if (_kbhit()) { key = _getch(); if (key == 'z') { break; } } system("cls"); reel[0] = rand() % MAX_NUM + 1; reel[1] = rand() % MAX_NUM + 1; reel[2] = rand() % MAX_NUM + 1; printf("[ %d ] [ %d ] [ %d ]\n", reel[0], reel[1], reel[2]); } if (reel[0] == reel[1] && reel[1] == reel[2]){ printf("あたり!\n"); } return 0; } |
<実行結果>
[ 3 ] [ 1 ] [ 2 ]
↑この数値が次々と変わっていき、zキーを押すと数値が確定する。
[ 2 ] [ 2 ] [ 2 ]
あたり!
続行するには何かキーを押してください・・・
とりあえず完成しました!
が、これで満足せず発展形を考えましょう。
今の状態では、3つのリールが一度に止まりますが、それぞれ個別に止める方法を考えます。
例えば、1のキーを押すと左のリールが止まり、2キーで真ん中、3キーで右のリールが止まるようにしたいです。
3つのリールが止まらないと無限ループを抜けられませんし、すでに止まっているリールは数値を更新してはいけません。
さて、皆さんならどうしますか?
各リールに対して停止フラグを設定し、全てのフラグが1になったら無限ループを抜けるという方法で作ってみます。
int型の配列stopFlagをリール分だけ作り、初期値として0を入れておきます。
フラグの値が0の間は乱数を発生させ、リールの数値を変え続けますが、フラグが1になると乱数の発生を止めなければなりません。
_getchから返って来た値が「'1'」であればstopFlagの「0」番目を1にして、左のリールを止めます。
真ん中、右のリールについても同様に作成し、完成させてみてください。
解答例です。
<sample program 073-08>
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <conio.h> #define MAX_NUM 4 #define REEL_NUM 3 int main(void) { int reel[REEL_NUM]; int stopFlag[REEL_NUM] = { 0, 0, 0 }; int key; srand((unsigned int)time(NULL)); for (;;) { if (_kbhit()) { key = _getch(); /* 押されたキーによってフラグを切り替える */ if (key == '1') { stopFlag[0] = 1; } if (key == '2') { stopFlag[1] = 1; } if (key == '3') { stopFlag[2] = 1; } /* 全てのフラグが1になったら無限ループを抜ける */ if (stopFlag[0] == 1 && stopFlag[1] == 1 && stopFlag[2] == 1) { break; } } system("cls"); /* フラグが0の間は乱数を発生させる。 */ if (stopFlag[0] == 0) { reel[0] = rand() % MAX_NUM + 1; } if (stopFlag[1] == 0) { reel[1] = rand() % MAX_NUM + 1; } if (stopFlag[2] == 0) { reel[2] = rand() % MAX_NUM + 1; } printf("[ %d ] [ %d ] [ %d ]\n", reel[0], reel[1], reel[2]); } if (reel[0] == reel[1] && reel[1] == reel[2]){ printf("あたり!\n"); } return 0; } |
<実行結果>
[ 3 ] [ 1 ] [ 2 ]
↑この数値が次々と変わっていき、1,2,3キーを押すと数値が確定する。
[ 2 ] [ 2 ] [ 2 ]
あたり!
続行するには何かキーを押してください・・・
まだまだ工夫の余地はありそうですが、後は自分自身で考えて作ってみてください。