次は簡単な「すごろくゲーム」を作ってみます。
説明しやすいようにマス目も少なくし、イベントも最低限しか作りません。
マス目に配列を使いますので、経路の分岐もなく、一本道のすごろくにします。
最初にマス目の準備を行います。
#defineを使ってMAX_MASUを30で定義します。
int型の配列masuをMAX_MASU分用意します。
配列の中身は以下の通りとします。
0 スタート地点 1 通常のマス目 2 ゴール地点
スタート地点は配列の0番目、ゴール地点は配列の最後に設定します。
その他のマス目は通常のマス目とします。
まずはここまで作ってみましょう。
解答例です。
<sample program 074-01>
#define MAX_MASU 30 int main(void) { int masu[MAX_MASU]; int i; /* 全てのマス目に通常1を入れる */ for (i = 0; i < MAX_MASU; i++) { masu[i] = 1; } masu[0] = 0; /* スタート地点 */ masu[MAX_MASU - 1] = 2; /* ゴール地点 */ return 0; } |
上のプログラムでマス目の初期設定が出来ました。
コメントに詳細を書きましたが、もう少し分かりやすいプログラムを考えるのであれば工夫が必要です。
#defineという命令はプログラムの変更などに対応するため、数値などを置き換える役割があります。
もう1つ重要な役割として、数値に名前を付けるという役割があります。
配列の中身は、0がスタート、1が通常、2がゴールですが、種類が増えていくと何番が何の意味が分からなくなってきます。
そこで、次のように#defineを追加します。
#define START 0 #define NORMAL 1 #define GOAL 2 |
こうすれば何番が何を指しているか覚えていなくても、単語でプログラムを組むことが出来ます。
直感的にもわかりやすくなると思いますので、上のプログラムを書き換えてみます。
<sample program 074-02>
#define MAX_MASU 30
#define START 0
#define NORMAL 1
#define GOAL 2
int main(void)
{
int masu[MAX_MASU];
int i;
/* マス目の初期化 */
for (i = 0; i < MAX_MASU; i++) {
masu[i] = NORMAL;
}
masu[0] = START;
masu[MAX_MASU - 1] = GOAL;
return 0;
}
|
わざとコメントは消しましたが、0や1や2を代入するより、意味のある単語で書いた方が分かりやすいと思います。
さて、データがきちんと設定されているかどうか確かめるため、マス目を表示してみましょう。
紙の上ですごろくをプレイする訳ではないので、表示はマス目状で無くても構いません。
今回は文字で置き換えようと思います。
スタート地点 "P" 通常 "." ゴール地点 "G"
switch文で配列masuの中身をチェックしてprintfで表示します。
<sample program 074-03>
#include <stdio.h> #define MAX_MASU 30 #define START 0 #define NORMAL 1 #define GOAL 2 int main(void) { int masu[MAX_MASU]; int i; /* マス目の初期化 */ for (i = 0; i < MAX_MASU; i++) { masu[i] = NORMAL; } masu[0] = START; masu[MAX_MASU - 1] = GOAL; /* マス目の表示 */ for (i = 0; i < MAX_MASU; i++) { switch (masu[i]) { case START: printf("S"); break; case NORMAL: printf("."); break; case GOAL: printf("G"); break; } } printf("\n"); return 0; } |
<実行結果>
S............................G 続行するには何かキーを押してください・・・
次に駒(プレイヤー)のことを考えましょう。
駒がどのマス目に止まっているかが分かれば良いですから、配列の添え字を使うことにします。
上で準備したすごろくを添え字ベースで考えるとマス目0からマス目29(MAX_MASU - 1)までとなります。
スタート地点は0番目のマス目ですから、初期値は決まっていますね。
ゴールは29(MAX_MASU - 1)番目になりますから、ここに止まればゴールになります。
では、変数positionを作成し、初期値として0を入れておきましょう。
<sample program 074-04>
#include <stdio.h> #define MAX_MASU 30 #define START 0 #define NORMAL 1 #define GOAL 2 int main(void) { int masu[MAX_MASU]; int i; int position; /* マス目の初期化 */ for (i = 0; i < MAX_MASU; i++) { masu[i] = NORMAL; } masu[0] = START; masu[MAX_MASU - 1] = GOAL; /* 駒の初期化 */ position = 0; /* マス目の表示 */ for (i = 0; i < MAX_MASU; i++) { switch (masu[i]) { case START: printf("S"); break; case NORMAL: printf("."); break; case GOAL: printf("G"); break; } } printf("\n"); return 0; } |
<実行結果>
S............................G 続行するには何かキーを押してください・・・
初期化は出来ましたが、表示を考えなければなりません。
今、自分がどこにいるか分からなければ面白くないですよね。
コンソールアプリケーションでは、一度表示してしまった文字の上に別の文字を重ねて表示することは出来ません。
今回は、一行下に駒の位置("P")を表示することにしましょう。
結果からするとこのような感じです。
<実行結果>
・初期状態 S............................G P 続行するには何かキーを押してください・・・
・4進んだ状態 S............................G P 続行するには何かキーを押してください・・・
ここでのポイントは、駒を進めた場合、"P"を表示する前に空白を何個か表示する必要があるということです。
"P"を表示する際に、基本的には画面の左端から表示し始めます。
初期状態の時はそのまま"P"を表示すれば良いですが、4進んだ状態の時は"P"を表示する前に空白を4つ表示しています。
・4進んだ状態 S............................G P ↑ここに半角空白が4つ表示されている。
つまり、4進んだ状態であれば進んでいる数だけ空白を表示した後に"P"を表示する必要がある訳です。
どんなプログラムになるか考えてみてください。
結果確認はpositionの初期値を0から4にしたり、別の数値にすることで確認してください。
解答例です。
<sample program 074-05>
#include <stdio.h> #define MAX_MASU 30 #define START 0 #define NORMAL 1 #define GOAL 2 int main(void) { int masu[MAX_MASU]; int i; int position; /* マス目の初期化 */ for (i = 0; i < MAX_MASU; i++) { masu[i] = NORMAL; } masu[0] = START; masu[MAX_MASU - 1] = GOAL; /* 駒の初期化 */ position = 5; /* マス目の表示 */ for (i = 0; i < MAX_MASU; i++) { switch (masu[i]) { case START: printf("S"); break; case NORMAL: printf("."); break; case GOAL: printf("G"); break; } } printf("\n"); /* 駒の表示 */ for (i = 0; i < position; i++) { printf(" "); } printf("P"); printf("\n"); return 0; } |
<実行結果>
S............................G P 続行するには何かキーを押してください・・・
positionの初期値を5にしましたので、空白も5つ表示されています。
※確認出来たらpositionの初期値は0に戻しておいてください。
いよいよ、サイコロを振って駒を進めるプログラムを作ります。
サイコロの作り方は覚えていますか?
変数diceを追加し、駒の表示の後にdiceに1〜6の乱数を設定するプログラムを追加してください。
乱数を使うのに必要な部品の追加も忘れずに!
解答例です。
<sample program 074-06>
#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX_MASU 30 #define START 0 #define NORMAL 1 #define GOAL 2 int main(void) { int masu[MAX_MASU]; int i; int position; int dice; /* 乱数の種をセット */ srand((unsigned int)time(NULL)); /* マス目の初期化 */ for (i = 0; i < MAX_MASU; i++) { masu[i] = NORMAL; } masu[0] = START; masu[MAX_MASU - 1] = GOAL; /* 駒の初期化 */ position = 0; /* マス目の表示 */ for (i = 0; i < MAX_MASU; i++) { switch (masu[i]) { case START: printf("S"); break; case NORMAL: printf("."); break; case GOAL: printf("G"); break; } } printf("\n"); /* 駒の表示 */ for (i = 0; i < position; i++) { printf(" "); } printf("P"); printf("\n"); /* サイコロを振る */ dice = rand() % 6 + 1; return 0; } |
これで出た目の数だけpositionを進めれば良いわけです。
以前使ったgetchar()を用いて、説明を加えながら表示出来るように変更しましょう。
<sample program 074-07>
#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX_MASU 30 #define START 0 #define NORMAL 1 #define GOAL 2 int main(void) { int masu[MAX_MASU]; int i; int position; int dice; /* 乱数の種をセット */ srand((unsigned int)time(NULL)); /* マス目の初期化 */ for (i = 0; i < MAX_MASU; i++) { masu[i] = NORMAL; } masu[0] = START; masu[MAX_MASU - 1] = GOAL; /* 駒の初期化 */ position = 0; /* マス目の表示 */ for (i = 0; i < MAX_MASU; i++) { switch (masu[i]) { case START: printf("S"); break; case NORMAL: printf("."); break; case GOAL: printf("G"); break; } } printf("\n"); /* 駒の表示 */ for (i = 0; i < position; i++) { printf(" "); } printf("P"); printf("\n"); /* サイコロを振る */ printf("サイコロを振ります\n"); getchar(); dice = rand() % 6 + 1; /* 駒を進める */ printf("%d進みます\n", dice); getchar(); position += dice; return 0; } |
<実行結果>
S............................G P サイコロを振ります 3進みます 続行するには何かキーを押してください・・・
positionを更新したら、マス目の表示部分に戻ることで、更新された状態が表示され、またサイコロを振ることが出来ます。
マス目の表示から駒を進める箇所までを無限ループでくくってしまいましょう。
<sample program 074-08>
#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX_MASU 30 #define START 0 #define NORMAL 1 #define GOAL 2 int main(void) { int masu[MAX_MASU]; int i; int position; int dice; /* 乱数の種をセット */ srand((unsigned int)time(NULL)); /* マス目の初期化 */ for (i = 0; i < MAX_MASU; i++) { masu[i] = NORMAL; } masu[0] = START; masu[MAX_MASU - 1] = GOAL; /* 駒の初期化 */ position = 0; for (;;) { /* マス目の表示 */ for (i = 0; i < MAX_MASU; i++) { switch (masu[i]) { case START: printf("S"); break; case NORMAL: printf("."); break; case GOAL: printf("G"); break; } } printf("\n"); /* 駒の表示 */ for (i = 0; i < position; i++) { printf(" "); } printf("P"); printf("\n"); /* サイコロを振る */ printf("サイコロを振ります\n"); getchar(); dice = rand() % 6 + 1; /* 駒を進める */ printf("%d進みます\n", dice); getchar(); position += dice; } return 0; } |
<実行結果>
S............................G P サイコロを振ります 3進みます S............................G P サイコロを振ります 2進みます S............................G P サイコロを振ります 5進みます 延々と続きます・・・
前回やった画面のクリアを無限ループの入り口に付けてください。
<sample program 074-09>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_MASU 30
#define START 0
#define NORMAL 1
#define GOAL 2
int main(void)
{
int masu[MAX_MASU];
int i;
int position;
int dice;
/* 乱数の種をセット */
srand((unsigned int)time(NULL));
/* マス目の初期化 */
for (i = 0; i < MAX_MASU; i++) {
masu[i] = NORMAL;
}
masu[0] = START;
masu[MAX_MASU - 1] = GOAL;
/* 駒の初期化 */
position = 0;
for (;;) {
system("cls");
/* マス目の表示 */
for (i = 0; i < MAX_MASU; i++) {
switch (masu[i]) {
case START:
printf("S");
break;
case NORMAL:
printf(".");
break;
case GOAL:
printf("G");
break;
}
}
printf("\n");
/* 駒の表示 */
for (i = 0; i < position; i++) {
printf(" ");
}
printf("P");
printf("\n");
/* サイコロを振る */
printf("サイコロを振ります\n");
getchar();
dice = rand() % 6 + 1;
/* 駒を進める */
printf("%d進みます\n", dice);
getchar();
position += dice;
}
return 0;
}
|
<実行結果>
S............................G P サイコロを振ります 3進みます 延々と続きます・・・
ずいぶん長くなってきましたが、プログラムは「部品」の集まりです。
どんなに長いプログラムでも細分化すれば「部品」に分けることが出来ます。
上のプログラムでは、コメントで区切ってある箇所が「部品」になります。
どこからどこまでが何の部品になっているか意識しながら作るようにしてください。
この続きは次回に書きます。