「ぷよぷよ」の続きです。
3.削除するべき「ぷよ」を調べる
ここからが核心部分です。
どこで「ぷよ」がつながっているのか分かりませんから、フィールドを1つ1つチェックしていかなければなりません。
この関数は、内部でさらにいくつかの関数に分けて作ります。
少しずつ説明しながら完成させていきましょう。
関数名 CheckDeletePuyo 戻り値 なし 引 数 フィールド、削除フラグ 機 能 削除するべき「ぷよ」を調べる |
void CheckDeletePuyo(const int field[ROW][COL], int deleteFlag[ROW][COL]) { int i; int j; for (i = 0; i < ROW; i++) { for (j = 0; j < COL; j++) { } } } |
まだ中身はほとんどありません。
フィールドの中身を全て調べるため、2重ループを準備しました。
しかし、中にはチェックしなくても良いマスもあるはずです。
例えば、
「ぷよ」が無いマス すでに削除予定のマス すでにチェック済みのマス
などです。
「ぷよ」が無いマスは意味が分かると思いますが、すでに削除予定のマスとは何でしょうか。
上の方に書いたシチュエーションは、4つ以上つながっている「ぷよ」は1組です。
□□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □赤青□□□ □赤青赤青□ □青青黄青□
しかし、1度に落ちてくる「ぷよ」は2つですから、2組同時に消えることもあるはずです。
□□□□□□ □□青黄□□ □□↓↓□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □赤□□□□ □赤青黄黄□ □青青黄青□
このまま落とすと「青」と「黄」が消えます。
□□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □赤青黄□□ □赤青黄黄□ □青青黄青□
この場合、フィールドを確認する順番から考えて、「青」の方を先にチェックします。
「青」が4つ並んでいることが分かれば、その時点での削除フラグは↓のようになっているはずです。
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になっている個所はチェック不要になります。
以上を踏まえて関数に追加します。
void CheckDeletePuyo(const int field[ROW][COL], int deleteFlag[ROW][COL])
{
int i;
int j;
for (i = 0; i < ROW; i++) {
for (j = 0; j < COL; j++) {
if (field[i][j] != NONE && deleteFlag[i][j] == 0) {
}
}
}
}
|
次に考えることは、つながっている「ぷよ」をチェックすることです。
これは、前回の塗りつぶしと同じ考えでチェックすれば出来ます。
しかし、最終的に削除するのは「4つ以上つながっている「ぷよ」」だけです。
チェック中は、何個つながっているか分かりません。
2つとか3つの時もあるでしょう。
もし、削除フラグの配列を直接使って調べるとなった場合、つながりが4つ未満の「ぷよ」は除外しなければなりません。
↓のシチュエーションの場合、最初にチェックされるのは左上の「赤」です。
□□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □赤青黄□□ □赤青黄青□ □青青黄青□
これをチェックした時の削除フラグの内容は、
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 0 0 0 0 0 0
となると思います。
2つしかつながっていませんので、削除フラグを戻さなければなりません。
配列全体を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 1 0 0 0 0 0 1 0 0 0 0 1 1 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 1 1 0 0 0 0 1 1 0 0 0 1 1 1 0 0
「黄」の「ぷよ」は3つしかつながっていませんので、削除対象ではありません。
しかし、この削除フラグの状態から「黄」の場所だけ「0」に戻すのはかなり面倒です。
もっと簡単な方法が無いか考えます。
削除フラグに格納する数字を「0」「1」だけでなく、種類を増やしてみます。
0 → 未チェック 1 → チェック中 2 → チェック済み 3 → 削除
最初は0で初期化しておき、チェック中の「ぷよ」には1を格納していきます。
一旦チェックが終わったら、1の数を数え、4以上であれば1を3に書き換え削除確定とします。
4未満であれば、1を2に書き換えチェック済みにします。
※チェック済みの個所は再度調べる必要が無くなりますよね。
とりあえず、流れを書くと、
□□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □□□□□□ □赤青黄□□ □赤青黄青□ □青青黄青□
この状態からチェックを始めます。
最初の「赤」のチェック中は、↓のようになります。
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 0 0 0 0 0 0
チェック後に1の数を数えると2つですから、削除対象ではありません。
チェック済みに分類しますので、1(CHECKING)を2(CHECKED)に変えます。
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 2 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0
次に1つ右の「青」をチェックします。
チェック後は↓のようになります。
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 2 1 0 0 0 0 2 1 0 0 0 0 1 1 0 0 0
1の個数は4つですから、1(CHEKING)を3(DELETE)に変えて削除対象にします。
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 2 3 0 0 0 0 2 3 0 0 0 0 3 3 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 2 3 2 0 0 0 2 3 2 2 0 0 3 3 2 2 0
3になっている個所の「ぷよ」を消せば良いことが分かります。
まずは、列挙体を追加しましょう。
enum { NO_CHECK, CHECKING, CHECKED, DELETE, }; |
次に、これまで書いたプログラムの変更箇所を書いておきます。
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] = { NO_CHECK }; CheckDeletePuyo(field, deleteFlag); ShowField(field); return 0; } |
main関数にはCheckDeletePuyo関数の呼び出しも追加しておきました。
void CheckDeletePuyo(const int field[ROW][COL], int deleteFlag[ROW][COL])
{
int i;
int j;
for (i = 0; i < ROW; i++) {
for (j = 0; j < COL; j++) {
if (field[i][j] != NONE && deleteFlag[i][j] == NO_CHECK) {
}
}
}
}
|
次回がラストです。