#include #include #include #include #include #include "common.h" #include "board.h" #include "player.h" void ClearConsole(); void SleepInSec(double sleep_sec); extern void* a_player_libhandle; extern void* b_player_libhandle; string LoadPlayer(IPlayer*& ab_player, string libpath, int board_rows, int board_cols, char box_type, char line_type); void CloseLibs(); struct PlayerInfo { public: IPlayer* iplayer; int score; char box; char line; double timespent; PlayerInfo* next; // play-list (linked list) PlayerInfo* prev; // play-list (linked list) PlayerInfo(IPlayer* p, char b, char l) { iplayer = p; score = 0; box = b; line = l; timespent = 0; } }; void PrintBoard(int iter, const Board& board, const vector& players) { // print board cout << board; cout << endl; // print iteration number cout << "iter : " << iter << endl; // find winning scores and winner numbers int maxscore = 0; int maxscore_cnt = 0; for(int i=0; iPlayerInfo() << ") has "; if(players[i].score >= 2) cout << players[i].score << " boxes"; else cout << players[i].score << " box"; cout << " and spent " << players[i].timespent*100 << " msec"; if(maxscore == players[i].score) { if(maxscore_cnt == 1) cout << " (win)." << endl; else cout << " (tie)." << endl; } else { cout << "." << endl; } } cout << endl; } // send add-line event to players void EventAddLine(const vector& players, char line, const Loc& loc) { for(int j = 0; j < players.size(); j++) { if(players[j].next == nullptr) continue; players[j].iplayer->EventAddLine(line, loc); } } // send add-box event to players void EventAddBox(const vector& players, char box, const Loc& loc) { for(int j = 0; j < players.size(); j++) { if(players[j].next == nullptr) continue; players[j].iplayer->EventAddBox(box, loc); } } // update box with player box info, and return true (for gaining box) or false (for not gaining box) bool AddBox(Board& board, int row, int col, char box, const vector& players) { assert(Loc(row,col).IsBoxLocation()); if(board(row,col) == ' ' && board(row+1,col) != ' ' && board(row-1,col) != ' ' && board(row,col+1) != ' ' && board(row,col-1) != ' ') { board(row,col) = box; EventAddBox(players, box, Loc(row,col)); return true; } return false; } string GameMaster(const vector& libpaths, vector& scores, vector& timespents, double sleep_sec) { /////////////////////////////////////////////////// // create board int board_rows, board_cols, board_blanklinecount; cin >> board_rows >> board_cols; cout << endl; Board board; board.AllocateBoard(board_rows, board_cols, board_blanklinecount); /////////////////////////////////////////////////// // load players vector players; int ibox = 0; for(int i=0; iClose(); continue; } players.push_back(PlayerInfo(player, box_type, line_type)); } catch(...) { cout << "Exception while loading a player (" << libpath << ")." << endl; if(player != nullptr) player->Close(); continue; } } /////////////////////////////////////////////////// // set player sequence and first player int iter = 0; for(int i=0; ibox; //////////////////////////////////////////////////////////// // determine player's line location // if the player put a line into a invalid location, then makr the player lose Loc loc; double timespent = 0; try { auto begin = chrono::high_resolution_clock::now(); loc = player->iplayer->SelectLineLocation(); auto end = std::chrono::high_resolution_clock::now(); auto elapsed = std::chrono::duration_cast(end - begin); player->timespent += (elapsed.count() * 1e-9); if(loc.IsBoxLocation()) throw "lose"; if(loc.IsDotLocation()) throw "lose"; if(board(loc) != ' ' ) throw "lose"; } catch(...) { // if the player put line into a wrong location or throw exception, // make the player have -1 score (invalid move) and // remove the player from play-list (linked-list) player->score = -1; if(player->next == player) { // if player is the last player, make the linked-list empty player = nullptr; } else { // if the player is not the last player, remove the player in the linked-list, and select the next player PlayerInfo* next_player = player->next; player->next->prev = player->prev; player->prev->next = player->next; player->next = nullptr; player->prev = nullptr; player = next_player; } // print play-log if(sleep_sec == 0) cout << " made an invalid move." << endl; continue; } //////////////////////////////////////////////////////////// // add the line into the board assert(loc.IsLineLocation()); assert(board(loc) == ' ' ); board(loc) = player->line; board_blanklinecount --; EventAddLine(players, player->line, loc); //////////////////////////////////////////////////////////// // if the player gain a box, then // mark the box owner and // make gainbox true int gainbox = 0; if(loc.IsLineHorizontalLocation()) { if(loc.row-1 >= 0 ) if(AddBox(board, loc.row-1, loc.col, player->box, players)) { player->score++; gainbox++; } if(loc.row+1 < board.GetRows()) if(AddBox(board, loc.row+1, loc.col, player->box, players)) { player->score++; gainbox++; } } if(loc.IsLineVerticalLocation()) { if(loc.col-1 >= 0 ) if(AddBox(board, loc.row, loc.col-1, player->box, players)) { player->score++; gainbox++; } if(loc.col+1 < board.GetCols()) if(AddBox(board, loc.row, loc.col+1, player->box, players)) { player->score++; gainbox++; } } //////////////////////////////////////////////////////////// // print board or play-log if(sleep_sec == 0) { cout << " add a line at (" << loc.row << "," << loc.col << ")"; if(gainbox == 1) cout << " and gain " << gainbox << " box." << endl; else if(gainbox >= 2) cout << " and gain " << gainbox << " boxes." << endl; else cout << "." << endl; } else { ClearConsole(); PrintBoard(iter, board, players); SleepInSec(sleep_sec); } //////////////////////////////////////////////////////////// // if the player does not gain a box // move to the next player if(gainbox == 0) player = player->next; } //////////////////////////////////////////////////////////// // print board if(sleep_sec != 0) ClearConsole(); else cout << endl; PrintBoard(iter, board, players); for(int i = 0; i < players.size(); i++) { scores [i] = players[i].score; timespents[i] = players[i].timespent; } return ""; }