★関数(再帰呼び出し7)★


「ぷよぷよ」のラストになります。

残りはCheckDeletePuyo関数内で呼び出す3つの関数を作成するのみです。


4.「ぷよ」のつながりをチェックする

これが再帰呼び出しをする関数になります。

未チェックの「ぷよ」を起点に上下左右のつながりを探し、削除フラグに1(CHECKING)を入れていきます。

必要な引数は以下の通りです。

配列                       field

配列                       deleteFlag

座標                       x, y

チェックしたい「ぷよ」の色 sourColor

前回の塗りつぶしの応用ですから、仕組みは皆さんで考えてみてください。

関数名 CheckConnection
戻り値 なし
引 数 フィールド、削除フラグ、X座標、Y座標、チェックしたい「ぷよ」の色
機 能 同じ色の「ぷよ」のつながりをチェックする
void CheckConnection(const int field[ROW][COL], int deleteFlag[ROW][COL], const int x, const int y, const int sourColor)
{
    if (deleteFlag[y][x] != NO_CHECK) {
        return;
    }
  
    deleteFlag[y][x] = CHECKING;
  
    if (y - 1 >= 0) {
        if (field[y - 1][x] == sourColor) {
            CheckConnection(field, deleteFlag, x, y - 1, sourColor);
        }
    }
  
    if (x + 1 < COL) {
        if (field[y][x + 1] == sourColor) {
            CheckConnection(field, deleteFlag, x + 1, y, sourColor);
        }
    }
  
    if (y + 1 < ROW) {
        if (field[y + 1][x] == sourColor) {
            CheckConnection(field, deleteFlag, x, y + 1, sourColor);
        }
    }
  
    if (x - 1 >= 0) {
        if (field[y][x - 1] == sourColor) {
            CheckConnection(field, deleteFlag, x - 1, y, sourColor);
        }
    }
}

これで、つながっている「ぷよ」の個所に1(CHECKING)が格納されます。

この関数を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) {

                CheckConnection(field, deleteFlag, j, i, field[i][j]);
            }
        }
    }
}

5.つながっている「ぷよ」の個数を調べる

次は、作成した削除フラグを元に1(CHECKING)の個数を調べて戻す関数を作ります。

関数名 CountCheckFlag
戻り値 つながっている「ぷよ」の数
引 数 削除フラグ
機 能 つながっている「ぷよ」の個数を調べる
int CountCheckFlag(const int deleteFlag[ROW][COL])
{
    int i;
    int j;
  
    int counter = 0;
  
    for (i = 0; i < ROW; i++) {
        for (j = 0; j < COL; j++) {
            if (deleteFlag[i][j] == CHECKING) {
                counter++;
            }
        }
    }
  
    return counter;
}

難しい内容ではありませんね。

CheckDeletePuyo関数も更新します。

void CheckDeletePuyo(const int field[ROW][COL], int deleteFlag[ROW][COL])
{
    int i;
    int j;

    int counter;

    for (i = 0; i < ROW; i++) {

        for (j = 0; j < COL; j++) {

            if (field[i][j] != NONE && deleteFlag[i][j] == NO_CHECK) {

                CheckConnection(field, deleteFlag, j, i, field[i][j]);

                counter = CountCheckFlag(deleteFlag);
            }
        }
    }
}

6.削除フラグを更新する

個数を元に、削除すべきものは3(DELETE)に、そうでないものは2(CHECKED)に変更します。

関数名 UpdateDeleteFlag
戻り値 なし
引 数 削除フラグ、つながっている「ぷよ」の個数
機 能 削除フラグを更新する
void UpdateDeleteFlag(int deleteFlag[ROW][COL], const int counter)
{
    int i;
    int j;

    for (i = 0; i < ROW; i++) {
        for (j = 0; j < COL; j++) {
            if (deleteFlag[i][j] == CHECKING) {
                if (counter >= 4) {
                    deleteFlag[i][j] = DELETE;
                }
                else {
                    deleteFlag[i][j] = CHECKED;
                }
            }
        }
    }
}

これで関数は全て揃いました。

CheckDeletePuyo関数も完成です。

void CheckDeletePuyo(const int field[ROW][COL], int deleteFlag[ROW][COL])
{
    int i;
    int j;

    int counter;

    for (i = 0; i < ROW; i++) {

        for (j = 0; j < COL; j++) {

            if (field[i][j] != NONE && deleteFlag[i][j] == NO_CHECK) {

                CheckConnection(field, deleteFlag, j, i, field[i][j]);

                counter = CountCheckFlag(deleteFlag);

                UpdateDeleteFlag(deleteFlag, counter);
            }
        }
    }
}

それでは、最後にプログラムの全文を書いておきます。

<sample program 153-01>

#include <stdio.h>

#define ROW 10
#define COL 6

#define COLOR 6

enum {
    NONE,
    RED,
    BLUE,
    YELLOW,
    GREEN,
    PURPLE,
};

enum {
    NO_CHECK,
    CHECKING,
    CHECKED,
    DELETE,
};

void ShowField(const int field[ROW][COL]);

void ShowDeleteFlag(const int deleteFlag[ROW][COL]);

void CheckDeletePuyo(const int field[ROW][COL], int deleteFlag[ROW][COL]);

void CheckConnection(const int field[ROW][COL], int deleteFlag[ROW][COL], const int x, const int y, const int sourColor);

int CountCheckFlag(const int deleteFlag[ROW][COL]);

void UpdateDeleteFlag(int deleteFlag[ROW][COL], const int counter);

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 };

    ShowField(field);

    CheckDeletePuyo(field, deleteFlag);

    ShowDeleteFlag(deleteFlag);

    return 0;
}

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");
}

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");
}

void CheckDeletePuyo(const int field[ROW][COL], int deleteFlag[ROW][COL])
{
    int i;
    int j;

    int counter;
    
    for (i = 0; i < ROW; i++) {

        for (j = 0; j < COL; j++) {

            if (field[i][j] != NONE && deleteFlag[i][j] == NO_CHECK) {

                CheckConnection(field, deleteFlag, j, i, field[i][j]);

                counter = CountCheckFlag(deleteFlag);

                UpdateDeleteFlag(deleteFlag, counter);
            }
        }
    }
}

void CheckConnection(const int field[ROW][COL], int deleteFlag[ROW][COL], const int x, const int y, const int sourColor)
{
    if (deleteFlag[y][x] != NO_CHECK) {
        return;
    }

    deleteFlag[y][x] = CHECKING;

    if (y - 1 >= 0) {
        if (field[y - 1][x] == sourColor) {
            CheckConnection(field, deleteFlag, x, y - 1, sourColor);
        }
    }

    if (x + 1 < COL) {
        if (field[y][x + 1] == sourColor) {
            CheckConnection(field, deleteFlag, x + 1, y, sourColor);
        }
    }

    if (y + 1 < ROW) {
        if (field[y + 1][x] == sourColor) {
            CheckConnection(field, deleteFlag, x, y + 1, sourColor);
        }
    }

    if (x - 1 >= 0) {
        if (field[y][x - 1] == sourColor) {
            CheckConnection(field, deleteFlag, x - 1, y, sourColor);
        }
    }
}

int CountCheckFlag(const int deleteFlag[ROW][COL])
{
    int i;
    int j;

    int counter = 0;

    for (i = 0; i < ROW; i++) {
        for (j = 0; j < COL; j++) {
            if (deleteFlag[i][j] == CHECKING) {
                counter++;
            }
        }
    }

    return counter;
}

void UpdateDeleteFlag(int deleteFlag[ROW][COL], const int counter)
{
    int i;
    int j;

    for (i = 0; i < ROW; i++) {
        for (j = 0; j < COL; j++) {
            if (deleteFlag[i][j] == CHECKING) {
                if (counter >= 4) {
                    deleteFlag[i][j] = DELETE;
                }
                else {
                    deleteFlag[i][j] = 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 3 0 0 0
 0 2 3 2 2 0
 0 3 3 2 2 0

続行するには何かキーを押してください・・・

これで完成です。

このような考え方は色々なゲームで使われています。

ゲームをプレイするだけでなく、仕組みについて考え、一部でも作ってみるようにしましょう。

※コンソールなので限界はありますが・・・


次へ

戻る

目次へ