From acab0f83a1b11ed1d5e045417b09fbce15ceda8a Mon Sep 17 00:00:00 2001 From: chouhy Date: Fri, 7 Jan 2022 21:42:42 -0500 Subject: [PATCH] Fix some replay problem --- tetris_ai/Replay.h | 6 ++-- tetris_ai/main.cpp | 69 ++++++++++++++++++++++++++++++------------ tetris_ai/tetrisgame.h | 2 ++ 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/tetris_ai/Replay.h b/tetris_ai/Replay.h index d1f6e0e..c57991a 100644 --- a/tetris_ai/Replay.h +++ b/tetris_ai/Replay.h @@ -213,7 +213,7 @@ namespace RP { ige_reorder.push_back(*it); continue; } - while (!ige_reorder.empty() && ige_reorder.front()["frame"] < (*it)["frame"]) { + while (!ige_reorder.empty() && ige_reorder.front()["frame"] <= (*it)["frame"]) { this->evt["events"].push_back(ige_reorder.front()); ige_reorder.pop_front(); } @@ -287,7 +287,7 @@ namespace RP { temp_evt.push_back(last); } } - void markEndofStep() { + void commitStep() { temp_evt.back().done = true; } void insertTmpEvent(json evt) { @@ -403,7 +403,7 @@ namespace RP { default: break; } - if (evt == FULL || evt == START || evt == TARGETS || evt == END) { + if (undoSteps == 0 || (evt == FULL || evt == START || evt == TARGETS || evt == END)) { this->evt["events"].push_back(event); } else { diff --git a/tetris_ai/main.cpp b/tetris_ai/main.cpp index 39a5fff..0caa5f4 100644 --- a/tetris_ai/main.cpp +++ b/tetris_ai/main.cpp @@ -25,6 +25,7 @@ bool done_pupu = false; #define GETPPS(t) ((t.m_drop_frame==0)?0:(double(t.n_pieces - 1) * 60.0 / t.m_drop_frame)) #define GETAPM(t) ((t.m_drop_frame==0)?0:(double(t.total_atts) * 3600.0 / t.m_drop_frame)) #define GETVSSCORE(t) (double(t.total_atts + t.m_clearGarbageLines) / max(1,t.n_pieces - 1) * GETPPS(t) * 100.0) +#define UNDO_AVAILABLE (rule.turnbase && rule.undoSteps > 0 && ai[0].style == 0) PIMAGE colorCell( int w, int h, color_t normal, color_t lt, color_t rb ) { PIMAGE img; @@ -1138,6 +1139,8 @@ void mainscene() { RP::GameRecord gRecord; std::vector pRecord(2); bool gameExported = false; + bool softDrop[2] = { false }; + int garbageReady = 1; for (int i = 0; i < players_num; i++) { pRecord[i].setUSer(tetris[i].m_name,i); pRecord[i].setHandling(player.arr, player.das, (ai[i].style == 0) ? player.softdropdelay : 0); @@ -1315,8 +1318,8 @@ void mainscene() { // reset replay classes rp.reset(fn, str); gRecord.reset(); - pRecord[0].reset(rule.undoSteps); - pRecord[1].reset(rule.undoSteps+10); + pRecord[0].reset(UNDO_AVAILABLE?rule.undoSteps:0); + pRecord[1].reset(UNDO_AVAILABLE ? rule.undoSteps+10 : 0); // int seed = (unsigned)time(0), pass = rnd.randint(1024); delayed_attack_q.clear(); @@ -1357,19 +1360,19 @@ void mainscene() { GETVSSCORE(tetris[0]), GETVSSCORE(tetris[1]), }; - pRecord[0].setEndGameStat(tetris[0].m_drop_frame, apm[0], pps[0], vs[0]); - pRecord[1].setEndGameStat(tetris[1].m_drop_frame, apm[1], pps[1], vs[1]); + pRecord[0].setEndGameStat(tetris[0].m_drop_frame+1, apm[0], pps[0], vs[0]); + pRecord[1].setEndGameStat(tetris[1].m_drop_frame+1, apm[1], pps[1], vs[1]); if (tetris[1].alive()) { pRecord[0].setWin(false); pRecord[1].setWin(true); - pRecord[0].insertEvent(RP::END, tetris[0].m_drop_frame, tf); - pRecord[1].insertEvent(RP::END, tetris[1].m_drop_frame, &tf[1]); + pRecord[0].insertEvent(RP::END, tetris[0].m_drop_frame+1, tf); + pRecord[1].insertEvent(RP::END, tetris[1].m_drop_frame+1, &tf[1]); } else { pRecord[1].setWin(false); pRecord[0].setWin(true); - pRecord[1].insertEvent(RP::END, tetris[1].m_drop_frame, tf); - pRecord[0].insertEvent(RP::END, tetris[0].m_drop_frame, &tf[1]); + pRecord[1].insertEvent(RP::END, tetris[1].m_drop_frame+1, tf); + pRecord[0].insertEvent(RP::END, tetris[0].m_drop_frame+1, &tf[1]); } gRecord.reset(); gRecord.insertGame(pRecord[0]); @@ -1402,6 +1405,7 @@ void mainscene() { if ( PUBLIC_VERSION == 0 ) { if ( k.key == key_f9 ) { tetris[1].accept_atts.push_back(tetris[1].genAttack(1)); + tetris[1].accept_atts_frame.push_back(tetris[1].m_frames); } } } @@ -1445,6 +1449,8 @@ void mainscene() { } } } + atk_t atkCurFrame; + int atkRecver = -1; for ( int i = 0; i < players_num; ++i ) { // before any player move handle delayed attack first if (DELAYED_ATTACK && rule.DelayedAttackTime != 0) { @@ -1456,6 +1462,7 @@ void mainscene() { if (atk.attacker == j) continue; if (rule.GarbageBuffer) { tetris[j].accept_atts.push_back(atk.attack); + tetris[j].accept_atts_frame.push_back(tetris[i].m_frames); pRecord[j].insertEvent(RP::IGE, tetris[j].m_frames, &(atk.attack)); if (rule.turnbase) tetris[j].env_change = 2; // don't know what it means } @@ -1472,6 +1479,11 @@ void mainscene() { tetris[i].env_change = 1; tetris[i].n_pieces += 1; + if (softDrop[i]) { + pRecord[i].insertEvent(RP::KEYUP, tetris[i].m_frames, &key2action[2]); + softDrop[i] = false; + } + int att = tetris[i].m_attack; int clearLines = tetris[i].m_clearLines; #ifndef XP_RELEASE @@ -1495,8 +1507,13 @@ void mainscene() { int m = min( att, tetris[i].accept_atts[0].atk); att -= m; tetris[i].accept_atts[0].atk -= m; + // cancel atk in the same frame for replay file + if (atkRecver == i && tetris[i].accept_atts_frame.front() == tetris[i].m_frames) { + atkCurFrame.atk -= m; + } if ( tetris[i].accept_atts[0].atk <= 0 ) { tetris[i].accept_atts.erase( tetris[i].accept_atts.begin() ); + tetris[i].accept_atts_frame.erase(tetris[i].accept_atts_frame.begin()); } } // second cancel delayed attack @@ -1522,12 +1539,12 @@ void mainscene() { if (i == j) continue; if (rule.GarbageBuffer) { tetris[j].accept_atts.push_back(tetris[i].genAttack(att)); - if (j == 0 && saved_board[j].back().n_pieces == tetris[j].n_pieces) { + tetris[j].accept_atts_frame.push_back(tetris[i].m_frames); + atkCurFrame = tetris[j].accept_atts.back(); + atkRecver = j; + if (UNDO_AVAILABLE && j == 0 && saved_board[j].back().n_pieces == tetris[j].n_pieces) { saved_board[j].back().accept_atts = tetris[j].accept_atts; - pRecord[j].amendIGEEvt(tetris[j].m_frames, tetris[j].accept_atts.back()); - } - else { - pRecord[j].insertEvent(RP::IGE, tetris[j].m_frames, &tetris[j].accept_atts.back()); + saved_board[j].back().accept_atts_frame = tetris[j].accept_atts_frame; } tetris[i].total_sent += att; if (rule.turnbase) tetris[j].env_change = 2; @@ -1544,7 +1561,7 @@ void mainscene() { if ( player_accept_attack && ( rule.GarbageBlocking == 0 || clearLines == 0) ) { int cap = (rule.GarbageCap == 0)?-1:rule.GarbageCap; - while ( ! tetris[i].accept_atts.empty() ) { + while ( ! tetris[i].accept_atts.empty() && tetris[i].accept_atts_frame.front() + garbageReady <= tetris[i].m_frames) { if (cap == 0) break; if (TETRIO_ATTACK_TABLE && cap != -1) { if (cap < tetris[i].accept_atts.front().atk) { @@ -1571,15 +1588,16 @@ void mainscene() { } } tetris[i].accept_atts.erase( tetris[i].accept_atts.begin() ); + tetris[i].accept_atts_frame.erase(tetris[i].accept_atts_frame.begin()); } } } // Have to record state before ai start to calculate - if (tetris[i].n_pieces > saved_board[i].back().n_pieces) { + if (UNDO_AVAILABLE && tetris[i].n_pieces > saved_board[i].back().n_pieces) { while (saved_board[i].size() > saved_board_num[i]) saved_board[i].pop_front(); saved_board[i].push_back(tetris[i]); - pRecord[i].markEndofStep(); + pRecord[i].commitStep(); pRecord[i].queueCheck(); } if ( tetris[i].env_change && tetris[i].ai_movs_flag == -1) { // AI ¼ÆËã @@ -1638,6 +1656,14 @@ void mainscene() { tetris[i].env_change = 0; } } + if (atkRecver != -1 && atkCurFrame.atk > 0) { + if (UNDO_AVAILABLE && atkRecver == 0 && saved_board[atkRecver].back().n_pieces == tetris[atkRecver].n_pieces) { + pRecord[atkRecver].amendIGEEvt(tetris[atkRecver].m_frames, atkCurFrame); + } + else { + pRecord[atkRecver].insertEvent(RP::IGE, tetris[atkRecver].m_frames, &atkCurFrame); + } + } for ( int i = 0; i < players_num; ++i ) { // 100 garbage buffer get lost if ( ! tetris[i].alive() ) continue; int total = 0; @@ -1698,7 +1724,8 @@ void mainscene() { else if (mov == AI::Moving::MOV_D) { // better not use, replay will be strange tetris[i].tryYMove(1); pRecord[i].insertEvent(RP::KEYDOWN, tetris[i].m_frames, &key2action[2], subframe += smalldiff); - pRecord[i].insertEvent(RP::KEYUP, tetris[i].m_frames+1, &key2action[2], subframe += smalldiff); + softDrop[i] = true; + break; } else if (mov == AI::Moving::MOV_LSPIN) { tetris[i].trySpin(1); @@ -1727,14 +1754,16 @@ void mainscene() { else if (mov == AI::Moving::MOV_DD) { tetris[i].tryYYMove(1); pRecord[i].insertEvent(RP::KEYDOWN, tetris[i].m_frames, &key2action[2], subframe += smalldiff); - // need to keep pressing sd for at least 1 frame - pRecord[i].insertEvent(RP::KEYUP, tetris[i].m_frames+1, &key2action[2], subframe); + // need to keep pressing sd for at least 1 frame, insert event in next frame + // pRecord[i].insertEvent(RP::KEYUP, tetris[i].m_frames+1, &key2action[2], subframe); + softDrop[i] = true; // incase still more movement in this frame. break; } else if (mov == AI::Moving::MOV_DROP) { tetris[i].drop(); // hd will drop immediately, better move to next frame + //hardDrop[i] = true; pRecord[i].insertEvent(RP::KEYDOWN, tetris[i].m_frames+1, &key2action[6], subframe += smalldiff); pRecord[i].insertEvent(RP::KEYUP, tetris[i].m_frames+1, &key2action[6], subframe += smalldiff); } @@ -1764,7 +1793,7 @@ void mainscene() { } cleardevice(); // undo - if (undo && saved_board[0].size() > 1 && rule.turnbase && rule.undoSteps > 0) { + if (UNDO_AVAILABLE && undo && saved_board[0].size() > 1) { lastGameState = 0; saved_board[0].pop_back(); pRecord[0].undo(); diff --git a/tetris_ai/tetrisgame.h b/tetris_ai/tetrisgame.h index 43da93b..8c7818e 100644 --- a/tetris_ai/tetrisgame.h +++ b/tetris_ai/tetrisgame.h @@ -130,6 +130,7 @@ class TetrisGame : public AI::Tetris { ai_last_deep = 0; ai_movs_flag = -1; accept_atts.clear(); + accept_atts_frame.clear(); m_last_hole_x = -1; total_clears = 0; total_atts = 0; @@ -344,6 +345,7 @@ class TetrisGame : public AI::Tetris { int env_change; int n_pieces; std::vector accept_atts; + std::vector accept_atts_frame; int m_last_hole_x; int n_win; int total_clears;