今回は、人気ゲームの一部を題材にします。
そのゲームとは「ぷよぷよ」です。
同じ色の「ぷよ」を4つ以上つなげることで「ぷよ」を消していくゲームですね。
落ちものゲームの元祖「テトリス」は横一列にブロックを並べるとその列が消えるというルールでした。
ぷよぷよは、同じ色が4つつながっていれば消えますので、「ぷよ」を消すプログラムも考えなければなりません。
例えば、
赤 赤 赤 赤
でも消えますし、
赤赤赤 赤
でも
赤 赤赤 赤
でもOKです。
この4つ並んだ「ぷよ」を選択する部分だけ再帰呼び出しを使って再現してみます。
※あくまでも筆者の考えた方法です。
まずはシチュエーションを考えます。
↓こんな感じで表現してみましょう。
□□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □赤青□□□ □赤青赤青□ □青青黄青□
<準備するもの> 定数(define) ROW 10 → 縦のマスの数 COL 6 → 横のマスの数 COLOR 6 → 色数(無、赤、青、黄、緑、紫) 列挙体(enum) NONE → 無 RED → 赤 BLUE → 青 YELLOW → 黄 GREEN → 緑 PURPLE → 紫 データ field → 2次元配列 関数 ShowField → フィールドの表示 |
とりあえず、main関数を作ります。
定数、列挙体、データも書いておきます。
<sample program 151-01>
#include <stdio.h> #define ROW 10 #define COL 6 #define COLOR 6 enum { NONE, RED, BLUE, YELLOW, GREEN, PURPLE, }; int main(void) { int field[ROW][COL] = { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, { 0, 1, 2, 0, 0, 0 }, { 0, 1, 2, 1, 2, 0 }, { 0, 2, 2, 3, 2, 0 }, }; return 0; } |
ここから関数を追加していきますが、長くなりますのでプログラムの全文は最後に載せます。
1.フィールドを表示する
関数名 ShowField 戻り値 なし 引 数 フィールド 機 能 フィールドの表示 |
void ShowField(const int field[ROW][COL]) { const char GRAPHIC[COLOR][3] = { "□", "赤", "青", "黄", "緑", "紫", }; int i; int j; for (i = 0; i < ROW; i++) { for (j = 0; j < COL; j++) { printf("%s", GRAPHIC[field[i][j]]); } printf("\n"); } printf("\n"); } |
これまでは、switch文で数値に応じた記号(□など)を表示していました。
数が多くなってくるとプログラムが長くなるので、今回は少し変えています。
文字列の配列(定数)を用意し、
printf("%s", GRAPHIC[0]); |
と書くと
□
が、
printf("%s", GRAPHIC[2]); |
と書くと
青
が表示されます。
配列fieldの中にグラフィックの番号(添え字)が入っていますので、
printf("%s", GRAPHIC[field[i][j]]); |
と書くことで、番号に応じた文字が表示されます。
関数のプロトタイプ宣言と本体を追加してください。
main関数にはShowField関数の呼び出しを追加してみましょう。
※ここから先もプロトタイプ宣言と本体は皆さんで追加してください。
<sample program 151-02>
int main(void)
{
int field[ROW][COL] = {
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 1, 2, 0, 0, 0 },
{ 0, 1, 2, 1, 2, 0 },
{ 0, 2, 2, 3, 2, 0 },
};
ShowField(field);
return 0;
}
|
<実行結果>
□□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □赤青□□□ □赤青赤青□ □青青黄青□ 続行するには何かキーを押してください・・・
さて、次は↑の状態から青が4つ並んでいる個所を抜き出すことを考えます。
fieldと同じ大きさの配列を作って、↓のように表示することにします。
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0
※1になっている個所が削除するべき「ぷよ」です。
配列の名前は、削除フラグ配列ということで
deleteFlag |
にしましょう。
<sample program 151-03>
int main(void)
{
int field[ROW][COL] = {
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 1, 2, 0, 0, 0 },
{ 0, 1, 2, 1, 2, 0 },
{ 0, 2, 2, 3, 2, 0 },
};
int deleteFlag[ROW][COL] = { 0 };
ShowField(field);
return 0;
}
|
※今回は1回だけチェックするプログラムですから、配列の初期化は宣言時にしておきます。
2.削除フラグを表示する
関数名 ShowDeleteFlag 戻り値 なし 引 数 削除フラグ 機 能 削除フラグの表示 |
void ShowDeleteFlag(const int deleteFlag[ROW][COL]) { int i; int j; for (i = 0; i < ROW; i++) { for (j = 0; j < COL; j++) { printf("%2d", deleteFlag[i][j]); } printf("\n"); } printf("\n"); } |
単純に配列の中身を表示するだけです。
<sample program 151-04>
int main(void)
{
int field[ROW][COL] = {
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 0, 1, 2, 0, 0, 0 },
{ 0, 1, 2, 1, 2, 0 },
{ 0, 2, 2, 3, 2, 0 },
};
int deleteFlag[ROW][COL] = { 0 };
ShowField(field);
ShowDeleteFlag(deleteFlag);
return 0;
}
|
<実行結果>
□□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □赤青□□□ □赤青赤青□ □青青黄青□ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 続行するには何かキーを押してください・・・
長くなるので3回に分けます。