#pragma warning(disable:4710)
#pragma warning(disable:4711)
#pragma warning(disable:4820)
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cstdlib>
#include <climits>
using namespace std;
#define ROW 5//縦
#define COL 6//横
typedef char F_T;//盤面型
typedef char T_T;//手数型
enum { EVAL_NONE = 0, EVAL_FALL, EVAL_SET, EVAL_FS, EVAL_COMBO };
//初期配置生成関数
void init(F_T field[ROW][COL]);
//ドロップの落下処理関数
void fall(F_T field[ROW][COL]);
//空マスを埋める関数
void set(F_T field[ROW][COL], int force);
//盤面表示関数
void show_field(F_T field[ROW][COL]);
//整数乱数
unsigned int rnd(int mini, int maxi);
//上下左右に連結しているドロップを再帰的に探索していく関数
int chain(int nrw, int ncl, int d, F_T field[ROW][COL],F_T chkflag[ROW][COL], F_T delflag[ROW][COL]);
//最終的にコンボが発生したか、さらにどのドロップが消えるのか判定する関数
int check(F_T field[ROW][COL], F_T delflag[ROW][COL], F_T t_erase[ROW][COL]);
//コンボ数判定関数
int evaluate(F_T field[ROW][COL], int flag);
//落とし有り、落ちコン無しコンボ数判定関数
int sum_e(F_T field[ROW][COL]);
//落としも落ちコンも有りコンボ数判定関数
int sum_evaluate(F_T field[ROW][COL]);
void show_field(F_T field[ROW][COL]) {
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
printf("%d", field[i][j]);
}
printf("\n");
}
}
void fall(F_T field[ROW][COL]) {
for (int j = 0; j < COL; j++) {
int tgt;
for (tgt = ROW - 1; tgt >= 0 && field[tgt][j] != 0; tgt--);
for (int i = tgt - 1; i >= 0; i--) {
if (field[i][j] != 0) {
F_T c = field[i][j];
field[i][j] = 0;
field[tgt][j] = c;
tgt--;
}
}
}
}
void init(F_T field[ROW][COL]) { set(field, !0); }
void set(F_T field[ROW][COL], int force) {
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
if (field[i][j] == 0 || force) {//空マスだったらうめる
field[i][j] = (F_T)rnd(force ? 0 : 1, 6);//1-6の整数乱数
}
}
}
}
int chain(int nrw, int ncl, int d, F_T field[ROW][COL],
F_T chkflag[ROW][COL], F_T delflag[ROW][COL]) {
int count = 0;
#define CHK_CF(Y,X) (field[Y][X] == d && chkflag[Y][X] == 0)
//連結している同じ色のドロップが未探索だったら
if (CHK_CF(nrw, ncl)) {
++count; //連結ドロップ数の更新
chkflag[nrw][ncl] = //探索済みにする
delflag[nrw][ncl] = 1;//コンボがつながる可能性があるので、1に設定
//以下上下左右に連結しているドロップを再帰的に探索していく
if (0 < nrw && CHK_CF(nrw - 1, ncl)) {
count += chain(nrw - 1, ncl, d, field, chkflag, delflag);
}
if (nrw < ROW - 1 && CHK_CF(nrw + 1, ncl)) {
count += chain(nrw + 1, ncl, d, field, chkflag, delflag);
}
if (0 < ncl && CHK_CF(nrw, ncl - 1)) {
count += chain(nrw, ncl - 1, d, field, chkflag, delflag);
}
if (ncl < COL - 1 && CHK_CF(nrw, ncl + 1)) {
count += chain(nrw, ncl + 1, d, field, chkflag, delflag);
}
}
return count;
}
int evaluate(F_T field[ROW][COL], int flag) {//コンボ数判定関数
int combo = 0;
while (1) {
int cmb = 0;
F_T chkflag[ROW][COL] = { 0 }; //未探索ドロップか否か格納する配列
F_T t_erase[ROW][COL] = { 0 }; //消去ドロップか否か格納する配列
for (int row = 0; row < ROW; row++) {
for (int col = 0; col < COL; col++) {
if (chkflag[row][col] == 0 && field[row][col] != 0) {
//未探索ドロップで、空マスじゃない場合
F_T delflag[ROW][COL] = { 0 }; //消去ドロップがありうるか格納する配列
int max_count = chain(row, col, field[row][col],
field, chkflag, delflag); //連結ドロップを探索する
if (max_count >= 3) {//3つ以上連結している場合、コンボが発生しうる
if (check(field, delflag, t_erase) == 1) { cmb++; }//コンボ発生
}
}
}
}
combo += cmb;
//コンボが発生しなかったら終了
if (cmb == 0 || 0 == (flag&EVAL_COMBO)) { break; }
for (int row = 0; row < ROW; row++) {
for (int col = 0; col < COL; col++) {
//コンボになったドロップは空になる。
if (t_erase[row][col] != 0) { field[row][col] = 0; }
}
}
if (flag&EVAL_FALL)fall(field);//落下処理発生
if (flag&EVAL_SET)set(field, 0);//落ちコン発生
}
return combo;
}
int sum_e(F_T field[ROW][COL]) {//落とし有り、落ちコン無しコンボ数判定関数
return evaluate(field, EVAL_FALL | EVAL_COMBO);
}
int sum_evaluate(F_T field[ROW][COL]) {//落としも落ちコンも有りコンボ数判定関数
return evaluate(field, EVAL_FS | EVAL_COMBO);
}
//最終的にコンボが発生したか、さらにどのドロップが消えるのか判定する関数
int check(F_T field[ROW][COL], F_T delflag[ROW][COL], F_T t_erase[ROW][COL]) {
int cmb = 0;
for (int row = 0; row < ROW; row++) {
for (int col = 0; col < COL - 2; col++) {
if (delflag[row][col] != 0 &&
delflag[row][col + 1] != 0 &&
delflag[row][col + 2] != 0 &&
field[row][col] == field[row][col + 1] &&
field[row][col] == field[row][col + 2]) {
//コンボが発生しうるドロップでなおかつ、横に3つつながってたら、
//その3つのドロップはコンボになるので消える。
t_erase[row][col] =
t_erase[row][col + 1] =
t_erase[row][col + 2] = 1;
cmb = 1;
//for (col += 3; col < COL; col++) {
// if(delflag[row][col] != 0 &&
// field[row][col] == field[row][col - 1]) {
// t_erase[row][col] = 1;
//} }
}
}
}
for (int col = 0; col < COL; col++) {
for (int row = 0; row < ROW - 2; row++) {
if (delflag[row][col] != 0 &&
delflag[row + 1][col] != 0 &&
delflag[row + 2][col] != 0 &&
field[row][col] == field[row + 1][col] &&
field[row][col] == field[row + 2][col]) {
//コンボが発生しうるドロップでなおかつ、縦に3つつながってたら、
//その3つのドロップはコンボになるので消える。
t_erase[row][col] =
t_erase[row + 1][col] =
t_erase[row + 2][col] = 1;
cmb = 1;
//for (row += 3; row < ROW; row++) {
// if(delflag[row][col] != 0 &&
// field[row][col] == field[row - 1][col]) {
// t_erase[row][col] = 1;
//} }
}
}
}
//cmb=0ならコンボは発生しなかった。1ならコンボが発生した
return cmb;
}
unsigned int rnd(int mini, int maxi) {//xorshift整数乱数
static unsigned int x = 123456789;
static unsigned int y = 362436069;
static unsigned int z = 521288629;
static unsigned int w = 0U;
if (w == 0U) { w = time(NULL) % INT_MAX; }
unsigned int t;
t = x ^ (x << 11);
x = y; y = z; z = w;
w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
return mini + (w % (maxi - mini + 1));
}
int main() {
int i;
for (i = 0; i < 1; i++) {//1問解く
F_T f_field[ROW][COL]; //盤面
printf("problem:%d\n", i + 1);
init(f_field); set(f_field, 0);//初期盤面生成
show_field(f_field);//盤面表示
printf("%dCombo\n", sum_e(f_field));//コンボ数表示
}
return 0;
}