とりあえず、ぷよぷよルールだった場合のサンプルを作ってみました。
コンソールアプリです。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define WIDTH 6 // フィールド幅
#define HEIGHT 16 // フィールド高
#define VANISH 4 // 消去に必要な個数
#define COLOR 3 // 色数
// ブロック管理用構造体
struct BLOCK
{
int nColor; // 色
int nVanish; // 消去フラグ
};
// フィールド管理用構造体
struct FIELD
{
struct BLOCK stBlock[WIDTH][HEIGHT]; // ブロック構造体配列
};
// 関数のプロトタイプ宣言
void ShowField(struct FIELD* pField);
int Check(struct FIELD* pField);
void Vanish(struct FIELD* pField);
int Slide(struct FIELD* pField);
void Count(struct FIELD* pField, int nX, int nY, int* pCount);
// メイン関数
int main(void)
{
int nX = 0;
int nY = 0;
int nChain = 0;
struct FIELD stField;
// 乱数の種を仕込む
srand((unsigned)time(NULL));
// フィールドへ適当な色のブロックを仕込む
for (nY = 0; nY < HEIGHT; ++nY)
{
for (nX = 0; nX < WIDTH; ++nX)
{
stField.stBlock[nX][nY].nColor = rand() % COLOR + 1;
stField.stBlock[nX][nY].nVanish = 0;
}
}
// 初期状態の描画
printf("初期状態\n");
ShowField(&stField);
getchar();
// 消去箇所が存在する間はループを続ける
while (Check(&stField) != 0)
{
// 消去チェック後の状態を描画
printf("%2d連鎖\n", ++nChain);
printf("チェック後\n");
ShowField(&stField);
getchar();
// 消去処理後の状態を描画
printf("消去後\n");
Vanish(&stField);
ShowField(&stField);
getchar();
// 空白を詰める為に1段ずつ落下させる
while (Slide(&stField) != 0)
{
printf("1段落下後\n");
ShowField(&stField);
getchar();
}
}
printf("%2d連鎖で終了しました\n", nChain);
return 0;
}
// フィールドを描画
void ShowField(struct FIELD* pField)
{
int nX = 0;
int nY = 0;
for (nY = 0; nY < HEIGHT; ++nY)
{
for (nX = 0; nX < WIDTH; ++nX)
{
// 色と消去フラグを表示する
printf("[%2d,%2d] ", pField->stBlock[nX][nY].nColor, pField->stBlock[nX][nY].nVanish);
}
putc('\n', stdout);
}
putc('\n', stdout);
}
// 全ブロックの同色で隣接している個数をチェックする
int Check(struct FIELD* pField)
{
int nX = 0;
int nY = 0;
int nReturn = 0;
struct FIELD stDummy;
for (nX = 0; nX < WIDTH; ++nX)
{
for (nY = 0; nY < HEIGHT; ++nY)
{
// 空白=0としているので、0の場合は何もしない
if(pField->stBlock[nX][nY].nColor == 0)
{
continue;
}
// 消去フラグをクリアしておく
pField->stBlock[nX][nY].nVanish = 0;
// フィールド構造体をコピーして、検査用の構造体領域を作成する
memcpy(&stDummy, pField, sizeof(struct FIELD));
// 同色で隣接している個数をカウントする
Count(&stDummy, nX, nY, &pField->stBlock[nX][nY].nVanish);
// 同色で隣接している個数がVANISH定数を超えていたら、戻り値を1にする
nReturn |=(pField->stBlock[nX][nY].nVanish >= VANISH);
}
}
// 1箇所でも消去される箇所があれば1、なければ0が返る
return nReturn;
}
// VANISH定数よりたくさん同色で隣接していたら消去する
void Vanish(struct FIELD* pField)
{
int nX = 0;
int nY = 0;
for (nX = 0; nX < WIDTH; ++nX)
{
for (nY = 0; nY < HEIGHT; ++nY)
{
// 同色での隣接数がVANISH定数以上か?
if(pField->stBlock[nX][nY].nVanish >= VANISH)
{
// ブロック情報をクリアする
memset(&pField->stBlock[nX][nY], 0, sizeof(struct BLOCK));
}
}
}
}
// 消去されて空いた隙間を1段だけ詰める
int Slide(struct FIELD* pField)
{
int nX = 0;
int nY = 0;
int nReturn = 0;
for (nY = HEIGHT - 1; nY >= 1; --nY)
{
for (nX = 0; nX < WIDTH; ++nX)
{
// 検査箇所が空白で、1つ上が空白ではない場合
if(pField->stBlock[nX][nY].nColor == 0 &&
pField->stBlock[nX][nY - 1].nColor != 0)
{
// 検査箇所へ1つ上のブロック情報をコピーする
memcpy(&pField->stBlock[nX][nY], &pField->stBlock[nX][nY - 1], sizeof(struct BLOCK));
// 1つ上のブロック情報をクリアする
memset(&pField->stBlock[nX][nY - 1], 0, sizeof(struct BLOCK));
// 動いた箇所があったので、戻り値を1にする
nReturn = 1;
}
}
}
// 動いた箇所があった場合は1、そうでない場合は0が返る
return nReturn;
}
// 同色で隣接している個数を数える(再帰関数)
void Count(struct FIELD* pField, int nX, int nY, int* pCount)
{
// 検査箇所の色を保持する
int nColor = pField->stBlock[nX][nY].nColor;
// ダブって検査しないように、検査した箇所のブロック情報をクリアしておく
memset(&pField->stBlock[nX][nY], 0, sizeof(struct BLOCK));
// カウンタをインクリメントする
++(*pCount);
// 1つ上のブロックを検査
if(nY - 1 >= 0 && nColor == pField->stBlock[nX][nY - 1].nColor)
{
Count(pField, nX, nY - 1, pCount);
}
// 1つ下のブロックを検査
if(nY + 1 < HEIGHT && nColor == pField->stBlock[nX][nY + 1].nColor)
{
Count(pField, nX, nY + 1, pCount);
}
// 1つ左のブロックを検査
if(nX - 1 >= 0 && nColor == pField->stBlock[nX - 1][nY].nColor)
{
Count(pField, nX - 1, nY, pCount);
}
// 1つ右のブロックを検査
if(nX + 1 < WIDTH && nColor == pField->stBlock[nX + 1][nY].nColor)
{
Count(pField, nX + 1, nY, pCount);
}
}