/*
puzzdra_solver
パズドラのルート解析プログラムです
コンパイラはMinGWを推奨します
コマンドは以下の通りです
g++ -O2 -std=c++11 -fopenmp puzzdra_solver.cpp -o puzzdra_solver
なるべく少ない時間でなるべく大きいコンボを出したいです
printf("TotalDuration:%fSec\n", t_sum);
printf("Avg.NormalCombo #:%f/%f\n", avg / (double)i, MAXCOMBO / (double)i);
これらが改善されればpull request受け付けます
チェック1:これを10コンボできるか
962679
381515
489942
763852
917439
914769
264812
379934
355886
951279
チェック2:1000盤面平均落ちコンボ数が9.20付近か
チェック3:1000盤面平均コンボ数が理論値付近か
全チェック達成したら合格
*/
#pragma warning(disable:4710)
#pragma warning(disable:4711)
#pragma warning(disable:4820)
#include <vector>
#include <cfloat>
#include <cstdio>
#include <cstring>
#include <climits>
#include <ctime>
#include <cstdlib>
#include <cmath>
#include <string>
#include <iostream>
#include <cstdint>
#include <algorithm>
#include <cassert>
#include <random>
#include <queue>
#include <deque>
#include <list>
#include <map>
#include <array>
#include <chrono>
#include <fstream>
#include <functional>
#include <unordered_map>
#ifdef _OPENMP
#include <omp.h>
#endif
#ifdef _MSC_VER
#include <intrin.h>
#endif
using namespace std;
#define DLT(ST,ED) ((double)((ED)-(ST))/CLOCKS_PER_SEC)//時間差分
#define XX(PT) ((PT)&15)
#define YY(PT) XX((PT)>>4)
#define YX(Y,X) ((Y)<<4|(X))
#define DIR 4//方向
#define ROW 5//縦//MAX6
#define COL 6//横//MAX7
#define DROP 6//ドロップの種類//MAX9
#define TRN 155//手数//MAX155
#define STP YX(7,7)//無効手[無効座標]
#define MAX_TURN 150//最大ルート長//MAX150
#define BEAM_WIDTH 5000//ビーム幅//MAX200000
#define PROBLEM 1000//問題数
#define BONUS 10//評価値改善係数
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define NODE_SIZE MAX(150,4*BEAM_WIDTH)
typedef char F_T;//盤面型
typedef char T_T;//手数型
typedef unsigned long long ll;
enum { EVAL_NONE = 0, EVAL_FALL, EVAL_SET, EVAL_FS, EVAL_COMBO };
void init(int board[COL]); //初期配置生成関数
void set2(int board[COL], int force); //空マスを埋める関数
void show_board(int board[COL]); //盤面表示関数
unsigned int rnd(int mini, int maxi); //整数乱数
//上下左右に連結しているドロップを再帰的に探索していく関数
int chain(int nrw, int ncl, int d, int board[COL], F_T chkflag[ROW][COL], F_T delflag[ROW][COL]);
//int evaluate(int board[COL], int flag); //コンボ数判定関数
//int sum_e(int board[COL]);//落とし有り、落ちコン無しコンボ数判定関数
//int sum_evaluate(int board[COL]);//落としも落ちコンも有りコンボ数判定関数
void operation(int board[COL], T_T route[TRN]); //スワイプ処理関数
int evaluate2(int board[COL], int flag, int* combo, ll* hash);//落とし減点評価関数
int sum_e2(int board[COL], int* combo, ll* hash);//評価関数
ll xor128();//xorshift整数乱数
ll zoblish_field[ROW][COL][DROP + 1];
int GetHeight(int x, int board[COL]);//高さを求める
#ifdef _MSC_VER
int __builtin_clzll(unsigned int x) { unsigned long r; _BitScanReverse(&r, x); return 31 - r; }
#endif // _MSC_VER
unsigned int bsr(unsigned int v) { return 31 - __builtin_clzll(v); } // 最上位の1は下から数えて何ビット目か?
void check_operation(F_T field[ROW][COL],T_T route[TRN]);
void set_field(int board[COL],F_T field[ROW][COL]);
int chain2(int nrw, int ncl, int d, int board[COL],ll* chkflag, ll delflag);
int iss_same(int board[COL],F_T field[ROW][COL]);
void show_field(F_T field[ROW][COL]);
void fall(int x, F_T field[ROW][COL]);
void set(F_T field[ROW][COL], int force);
inline int Get(int x, int y, int board[COL]);//x,y座標のブロックの数字を取得
inline void SetBit(int x, int y, int n, int board[COL]);//x,y座標のブロックをブロックnに変える
inline void fall2(int x, int board[COL]); //ドロップの落下処理関数
struct node {//どういう手かの構造体
T_T movei[TRN];//スワイプ移動座標
int score;//評価値
int combo;//コンボ数
int nowC;//今どのx座標にいるか
int nowR;//今どのy座標にいるか
int prev;//1手前は上下左右のどっちを選んだか
int prev_score;//1手前の評価値
int improving;//評価値改善回数
ll hash;//盤面のハッシュ値
node() {//初期化
this->score = 0;
this->prev = -1;
//memset(this->movei, STP, sizeof(this->movei));
}
bool operator < (const node& n)const {//スコアが高い方が優先される
return score < n.score;
}
}fff[NODE_SIZE];
struct Action {//最終的に探索された手
int score;//コンボ数
int maxcombo;//理論コンボ数
T_T moving[TRN];//スワイプ移動座標
Action() {//初期化
this->score = 0;
//memset(this->moving, STP, sizeof(this->moving));
}
};
inline int Get(int x, int y, int board[COL])
{
return ((board[x] >> ((y) * 4))& 15);
}
inline void SetBit(int x, int y, int n, int board[COL])
{
int shift = ((y) * 4);
board[x] &= (~(15 << shift));
board[x] |= ((n) << shift);
}
int GetHeight(int x, int board[COL])
{
if (board[x] == 0)
{
return 0;
}
else
{
int p = bsr(board[x]);
p /= 4;
p += 1;
return p;
}
}
Action BEAM_SEARCH(int f_board[COL]); //ルート探索関数
double part1 = 0, part2 = 0, part3 = 0, part4 = 0, MAXCOMBO = 0;
Action BEAM_SEARCH(int f_board[COL]) {
int stop = 0;//理論最大コンボ数
int drop[DROP + 1] = { 0 };
for (int row = 0; row < ROW; row++) {
for (int col = 0; col < COL; col++) {
//if (1 <= f_field[row][col] && f_field[row][col] <= DROP) {
int b = Get(col, row, f_board);
if (1 <= b && b <= DROP) {
drop[b]++;
}
}
}
for (int i = 1; i <= DROP; i++) {
stop += drop[i] / 3;
}
MAXCOMBO += (double)stop;
deque<node>dque;
double start, st;
//1手目を全通り探索する
dque.clear();
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
node cand;
cand.nowR = ROW-1-i;//y座標
cand.nowC = j;//x座標
cand.prev = -1;//1手前はない
cand.movei[0] = (T_T)YX(ROW-1-i, j);//1手目のyx座標
for (int trn = 1; trn < TRN; trn++) {
cand.movei[trn] = STP;
}
int ff_board[COL];
memcpy(ff_board, f_board, sizeof(ff_board));
int cmb;
ll ha;
cand.prev_score = sum_e2(ff_board, &cmb, &ha);
cand.improving = 0;
cand.hash = ha;
dque.push_back(cand);
}
} // L, U,D,R //
int dx[DIR] = { -1, 0,0,1 },
dy[DIR] = { 0,-1,1,0 };
Action bestAction;//最善手
int maxValue = 0;//最高スコア
bestAction.maxcombo = stop;
unordered_map<ll, bool> checkNodeList[ROW * COL];
//2手目以降をビームサーチで探索
for (int i = 1; i < MAX_TURN; i++) {
int ks = (int)dque.size();
start = omp_get_wtime();
#pragma omp parallel for private(st),reduction(+:part1,part4)
for (int k = 0; k < ks; k++) {
#ifdef _OPENMP
if (i == 1 && k == 0) {
printf("Threads[%d/%d]\n",
omp_get_num_threads(),
omp_get_max_threads());
}
#endif
node temp = dque[k];//que.front(); que.pop();
int temp_board[COL];
memcpy(temp_board, f_board, sizeof(temp_board));
operation(temp_board, temp.movei);
for (int j = 0; j < DIR; j++) {//上下左右の4方向が発生
node cand = temp;
if (0 <= (cand.nowC + dx[j]) && (cand.nowC + dx[j]) < COL &&
0 <= (cand.nowR + dy[j]) && (cand.nowR + dy[j]) < ROW) {
if (cand.prev + j != 3) {
int board[COL];//盤面
memcpy(board, temp_board, sizeof(temp_board));//盤面をもどす
int tmp = Get(cand.nowC, cand.nowR, board);
SetBit(cand.nowC, cand.nowR, Get(cand.nowC + dx[j], cand.nowR + dy[j], board), board);
SetBit(cand.nowC + dx[j], cand.nowR + dy[j], tmp, board);
cand.nowC += dx[j];
cand.nowR += dy[j];
cand.movei[i] = (T_T)YX(cand.nowR, cand.nowC);
st = omp_get_wtime();
int cmb;
ll ha;
cand.score = sum_e2(board, &cmb, &ha);
cand.combo = cmb;
cand.hash = ha;
part1 += omp_get_wtime() - st;
cand.prev = j;
st = omp_get_wtime();
//#pragma omp critical
//{ pque.push(cand); }
fff[(4 * k) + j] = cand;
part4 += omp_get_wtime() - st;
}
else {
cand.combo = -1;
fff[(4 * k) + j] = cand;
}
}
else {
cand.combo = -1;
fff[(4 * k) + j] = cand;
}
}
}
part2 += omp_get_wtime() - start;
start = omp_get_wtime();
dque.clear();
vector<pair<int, int> >vec;
int ks2 = 0;
for (int j = 0; j < 4 * ks; j++) {
if (fff[j].combo != -1) {
if (fff[j].score > fff[j].prev_score) { fff[j].improving = fff[j].improving + 1; }
fff[j].prev_score = fff[j].score;
vec.push_back(make_pair(fff[j].score + (BONUS * fff[j].improving), j));
ks2++;
}
}
sort(vec.begin(), vec.end());
int push_node = 0;
for (int j = 0; push_node < BEAM_WIDTH && j < ks2; j++) {
node temp = fff[vec[ks2 - 1 - j].second];
if (maxValue < temp.combo) {//コンボ数が増えたらその手を記憶する
maxValue = temp.combo;
bestAction.score = maxValue;
memcpy(bestAction.moving, temp.movei, sizeof(temp.movei));
//コンボ数が理論値になったらreturn
if (temp.combo == stop) { return bestAction; }
}
if (i < MAX_TURN - 1) {
int pos = (temp.nowR * COL) + temp.nowC;
if (!checkNodeList[pos][temp.hash]) {
checkNodeList[pos][temp.hash] = true;
dque.push_back(temp);
push_node++;
}
}
}
part3 += omp_get_wtime() - start;
}
return bestAction;
}
void show_board(int board[COL]) {
for (int i = ROW - 1; i >= 0; i--) {
for (int j = 0; j < COL; j++) {
printf("%d", Get(j, i, board));
}
printf("\n");
}
}
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");
}
}
inline void fall2(int x, int board[COL]) {
int n = 0;
int offset = 0;//空きマスが途中に何個あるか
for (int i = 0; i < ROW; i++)
{
int b = (board[x] & (15 << ((i)* 4)));//map[x]のi番目の高さまでの値をbに格納
if (b == 0)//空きマスなら
{
offset += 4;
}
else
{
n |= (b >> offset);
}
}
board[x] = n;
}
void fall(int x, F_T field[ROW][COL]) {
int tgt;
for (tgt = ROW - 1; tgt >= 0 && field[tgt][x] != 0; tgt--);
for (int i = tgt - 1; i >= 0; i--) {
if (field[i][x] != 0) {
F_T c = field[i][x];
field[i][x] = 0;
field[tgt][x] = c;
tgt--;
}
}
}
void init(int board[COL]) { set2(board, !0); }
void set2(int board[COL], int force) {
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
if (Get(j, i, board) == 0 || force) {//空マスだったらうめる
int n = rnd(force ? 0 : 1, DROP);//1-DROPの整数乱数
SetBit(j, i, n, board);
}
}
}
}
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, DROP);//1-DROPの整数乱数
}
}
}
}
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 && delflag[Y][X] > 0)
//連結している同じ色の消去ドロップが未探索だったら
if (CHK_CF(nrw, ncl)) {
++count; //連結ドロップ数の更新
chkflag[nrw][ncl]=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 chain2(int nrw, int ncl, int d, int board[COL],
ll* chkflag, ll delflag) {
int count = 0;
#define CHK_CF2(Y,X) (Get(X,Y,board) == d && !((*chkflag) & (1ll<<(((Y)*COL)+X))) && (delflag & (1ll<<((Y)*COL+X))) != 0)
//連結している同じ色の消去ドロップが未探索だったら
if (CHK_CF2(nrw, ncl)) {
++count; //連結ドロップ数の更新
(*chkflag) |= (1ll << ((nrw) * COL + ncl)); //探索済みにする
//以下上下左右に連結しているドロップを再帰的に探索していく
if (0 < nrw && CHK_CF2(nrw - 1, ncl)) {
count += chain2(nrw - 1, ncl, d, board, chkflag, delflag);
}
if (nrw < ROW - 1 && CHK_CF2(nrw + 1, ncl)) {
count += chain2(nrw + 1, ncl, d, board, chkflag, delflag);
}
if (0 < ncl && CHK_CF2(nrw, ncl - 1)) {
count += chain2(nrw, ncl - 1, d, board, chkflag, delflag);
}
if (ncl < COL - 1 && CHK_CF2(nrw, ncl + 1)) {
count += chain2(nrw, ncl + 1, d, board, 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 delflag[ROW][COL] = { 0 };
for (int row = 0; row < ROW; row++) {
for (int col = 0; col < COL; col++) {
if (col <= COL - 3 && field[row][col] == field[row][col + 1] && field[row][col] == field[row][col + 2] && field[row][col] > 0) {
delflag[row][col] = field[row][col];
delflag[row][col + 1] = field[row][col];
delflag[row][col + 2] = field[row][col];
}
if (row <= ROW - 3 && field[row][col] == field[row + 1][col] && field[row][col] == field[row + 2][col] && field[row][col] > 0) {
delflag[row][col] = field[row][col];
delflag[row + 1][col] = field[row][col];
delflag[row + 2][col] = field[row][col];
}
}
}
for (int row = 0; row < ROW; row++) {
for (int col = 0; col < COL; col++) {
if (delflag[row][col] > 0) {
if (chain(row, col, field[row][col], field, chkflag, delflag) >= 3) {
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 (delflag[row][col] > 0) { field[row][col] = 0; }
}
}
if (flag & EVAL_FALL){
for(int x=0;x<COL;x++){
fall(x,field);
}
}//落下処理発生
if (flag & EVAL_SET){set(field, 0);}//落ちコン発生
}
return combo;
}
int evaluate2(int board[COL], int flag, int* combo, ll* hash) {
int ev = 0;
*combo = 0;
ll ha = 0;
int oti = 0;
while (1) {
int cmb = 0;
int cmb2 = 0;
ll chkflag = 0;
ll delflag = 0;
for (int row = ROW - 1; row >= 0; row--) {
for (int col = 0; col < COL; col++) {
int num = Get(col, row, board);
if (oti == 0) {
ha ^= zoblish_field[row][col][num];
}
if (col <= COL - 3 && Get(col + 1, row, board) == num && Get(col + 2, row, board) == num && num > 0) {
delflag |= (1ll << (((row) * COL) + col));
delflag |= (1ll << (((row) * COL) + col + 1));
delflag |= (1ll << (((row) * COL) + col + 2));
}
if (row >= 2 && Get(col, row - 1, board) == num && Get(col, row - 2, board) == num && num > 0) {
delflag |= (1ll << (((row) * COL) + col));
delflag |= (1ll << (((row - 1) * COL) + col));
delflag |= (1ll << (((row - 2) * COL) + col));
}
}
}
F_T cnt[DROP + 1] = { 0 };
F_T drop[DROP + 1][ROW * COL][2] = { 0 };
for (int row = ROW - 1; row >= 0; row--) {
for (int col = 0; col < COL; col++) {
int num = Get(col, row, board);
drop[num][cnt[num]][0] = (F_T)row;
drop[num][cnt[num]][1] = (F_T)col;
cnt[num]++;
if ((delflag & (1ll << (((row) * COL) + col))) != 0) {
int c = chain2(row, col, num, board, &chkflag, delflag);
if (c >= 3) {
cmb++;
if (c == 3) { cmb2 += 30; }
else { cmb2 += 20; }
}
}
}
}
F_T erase_x[COL] = {0};
for (int i = 1; i <= DROP; i++) {
for (int j = 0; j < cnt[i] - 1; j++) {
int d1 = (int)drop[i][j][0];
int d2 = (int)drop[i][j][1];
int d3 = (int)drop[i][j + 1][0];
int d4 = (int)drop[i][j + 1][1];
int add = max(d1 - d3, d3 - d1) + max(d2 - d4, d4 - d2);
add += add;
add /= 3;
cmb2 -= add;
if ((delflag & (1ll << (((d1) * COL) + d2))) != 0) {
SetBit(d2, d1, 0, board);
erase_x[d2]=1;
}
if ((delflag & (1ll << (((d3) * COL) + d4))) != 0) {
SetBit(d4, d3, 0, board);
erase_x[d4]=1;
}
}
}
(*combo) += cmb;
ev += cmb2;
//コンボが発生しなかったら終了
if (cmb == 0 || 0 == (flag & EVAL_COMBO)) { break; }
oti++;
if (flag & EVAL_FALL){//落下処理発生
for(int x=0;x<COL;x++){
if(erase_x[x]==1){
fall2(x,board);
}
}
}
if (flag & EVAL_SET) {
set2(board, 0);
}//落ちコン発生
}
ev += oti;
(*hash) = ha;
return ev;
}
int sum_e2(int board[COL], int* combo, ll* hash) {//落とし有り、落ちコン無し評価関数
return evaluate2(board, EVAL_FALL | EVAL_COMBO, combo, hash);
}
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);
}
//移動した後の盤面を生成する関数
void operation(int board[COL], T_T route[TRN]) {
int prw = (int)YY(route[0]), pcl = (int)XX(route[0]), i;
for (i = 1; i < MAX_TURN; i++) {
if (route[i] == STP) { break; }
//移動したら、移動前ドロップと移動後ドロップを交換する
int row = (int)YY(route[i]), col = (int)XX(route[i]);
int c = Get(pcl, prw, board);
SetBit(pcl, prw, Get(col, row, board), board);
SetBit(col, row, c, board);
prw = row, pcl = col;
}
}
unsigned int rnd(int mini, int maxi) {
static mt19937 mt((int)time(0));
uniform_int_distribution<int> dice(mini, maxi);
return dice(mt);
}
ll xor128() {//xorshift整数乱数
static unsigned long long rx = 123456789, ry = 362436069, rz = 521288629, rw = 88675123;
ll rt = (rx ^ (rx << 11));
rx = ry; ry = rz; rz = rw;
return (rw = (rw ^ (rw >> 19)) ^ (rt ^ (rt >> 8)));
}
void check_operation(F_T field[ROW][COL],T_T route[TRN]){
int prw = ROW-1-((int)YY(route[0]));
int pcl = (int)XX(route[0]);
int i;
for (i = 1; i < MAX_TURN; i++) {
if (route[i] == STP) { break; }
//移動したら、移動前ドロップと移動後ドロップを交換する
int row= ROW-1-((int)YY(route[i]));
int col = (int)XX(route[i]);
int c =field[prw][pcl];
field[prw][pcl]=field[row][col];
field[row][col]=c;
prw = row, pcl = col;
}
}
void set_field(int board[COL],F_T field[ROW][COL]){
for (int i = ROW - 1; i >= 0; i--) {
for (int j = 0; j < COL; j++) {
int num=Get(j,i,board);
field[ROW-1-i][j]=num;
}
}
}
int iss_same(int board[COL],F_T field[ROW][COL]){
for (int i = ROW - 1; i >= 0; i--) {
for (int j = 0; j < COL; j++) {
int num=Get(j,i,board);
if(num!=field[ROW-1-i][j]){return 0;}
}
}
return 1;
}
int main() {
int i, j, k;
for (i = 0; i < ROW; ++i) {
for (j = 0; j < COL; ++j) {
for (k = 0; k <= DROP; k++) {
zoblish_field[i][j][k] = xor128();
}
}
}
double avg = 0;//平均コンボ数
double start;
double t_sum = 0;
double oti_avg = 0;//平均落ちコンボ数
for (i = 0; i < PROBLEM; i++) {//PROBLEM問解く
printf("input:No.%d/%d\n", i + 1, PROBLEM);
//init(f_field); set(f_field, 0);//初期盤面生成
//show_field(f_field);//盤面表示
int board[COL];
init(board); set2(board, 0);
show_board(board);
int f_board[COL];
/*
for (j = 0; j < ROW; j++) {
string s = "";
cin >> s;
for (k = 0; k < COL; k++) {
SetBit(k,ROW-1-j,s[k]-'0',board);
}
}
*/
memcpy(f_board, board, sizeof(board));
F_T field[ROW][COL];
set_field(board,field);
start = omp_get_wtime();
Action tmp = BEAM_SEARCH(board);//ビームサーチしてtmpに最善手を保存
double diff = omp_get_wtime() - start;
t_sum += diff;
printf("(x,y)=(%d,%d)", XX(tmp.moving[0]), YY(tmp.moving[0]));
for (j = 1; j < MAX_TURN; j++) {//y座標は下にいくほど小さくなる
if (tmp.moving[j] == STP) { break; }
if (XX(tmp.moving[j]) == XX(tmp.moving[j - 1]) + 1) { printf("R"); } //"RIGHT"); }
if (XX(tmp.moving[j]) == XX(tmp.moving[j - 1]) - 1) { printf("L"); } //"LEFT"); }
if (YY(tmp.moving[j]) == YY(tmp.moving[j - 1]) + 1) { printf("U"); } //"UP"); }
if (YY(tmp.moving[j]) == YY(tmp.moving[j - 1]) - 1) { printf("D"); } //"DOWN"); }
} printf("\n");
operation(f_board, tmp.moving);
check_operation(field,tmp.moving);
printf("output:No.%d/%d\n", i + 1, PROBLEM);
show_board(f_board);
int res=iss_same(f_board,field);
if(res==0){
for(int t=0;t<10;t++){
printf("akan");
}
printf("show_field invalid\n");
show_field(field);
break;
}
int combo = sum_e(field);
if(combo!=tmp.score){
for(int t=0;t<10;t++){
printf("akan");
}
printf("score invalid\n");
break;
}
//int oti = sum_evaluate(oti_field);
printf("Normal:%d/%dCombo\n", tmp.score, tmp.maxcombo);
printf("elapsed time:%fSec\n", diff);
printf("------------\n");
//avg += (double)combo;
//oti_avg += (double)oti;
avg += (double)tmp.score;
}
printf("TotalDuration:%fSec\n", t_sum);
printf("Avg.NormalCombo #:%f/%f\n", avg / (double)i, MAXCOMBO / (double)i);
printf("Avg.OtiCombo #:%f\n", oti_avg / (double)i);
printf("p1:%f,p2:%f,p3:%f,p4:%f\n", part1, part2, part3, part4);
j = getchar();
return 0;
}