void PrintHelp() { static const char * const help[] = { // Assume TTY has 72 columns. Let's try to keep everything to 70 max. // 1 2 3 4 5 6 7 // 1234567890123456789012345678901234567890123456789012345678901234567890 "Enter a move using file letter, rank number for source and target.", "For example, White moving king pawn forward two squares: e2e4.", "To castle, just move the king two squares. Example: e1g1.", "", "You may also enter any of the following commands:", "board Print the board now (see 'hide', 'show').", "help Print this help text.", "hide Print the board only when asked (see 'board', 'show').", "new Start a new game.", "quit Exit the game.", "show Print the board every time it is your turn.", "swap Swap sides with the computer.", "time Adjust computer's think time (difficulty).", NULL }; TheTerminal.printline(); for (int i=0; help[i]; ++i) { TheTerminal.printline(help[i]); } TheTerminal.printline(); }
int main(int argc, const char *argv[]) { int rc = 1; try { LoadIniFile("ttychess.ini"); TheTerminal.printline(); TheTerminal.printline(std::string("Teletype chess program (") + ConvertDateToVersion(__DATE__) + ") by Don Cross."); TheTerminal.printline("http://cosinekitty.com/chenard"); while (true) { ChessBoard board; ChessUI_TTY ui; ChessGame game(board, ui); ui.SetGame(&game); game.Play(); ui.SetGame(NULL); } rc = 0; } catch (const char *message) { TheTerminal.print(message); TheTerminal.printline(); } TheTerminal.close(); return rc; }
virtual void Resign(ChessSide iGiveUp, QuitGameReason reason) { switch (reason) { case qgr_resign: switch (iGiveUp) { case SIDE_WHITE: TheTerminal.printline("White resigns."); break; case SIDE_BLACK: TheTerminal.printline("Black resigns."); break; } break; case qgr_lostConnection: TheTerminal.printline("Lost connection."); break; case qgr_startNewGame: TheTerminal.printline("Starting new game."); break; } }
// NOTE: The following is called only when there is a // checkmate, stalemate, or draw by attrition. // The function is NOT called if a player resigns. virtual void ReportEndOfGame(ChessSide winner) { switch (winner) { case SIDE_WHITE: TheTerminal.printline("White wins."); break; case SIDE_BLACK: TheTerminal.printline("Black wins."); break; case SIDE_NEITHER: TheTerminal.printline("Draw game."); break; } }
void ReallyDrawBoard(const ChessBoard &board) { // Show the board from the human player's point of view. char startFile, startRank; int deltaFile, deltaRank; if (humanSide == SIDE_WHITE) { // We draw the board with White (rank 1) at the bottom, so we start with rank 8. startFile = 'a'; startRank = '8'; deltaFile = +1; deltaRank = -1; } else { // We draw the board with Black (rank 8) at the bottom, so we start with rank 1. startFile = 'h'; startRank = '1'; deltaFile = -1; deltaRank = +1; } for (int y=0, rank=startRank; y < 8; ++y, rank += deltaRank) { TheTerminal.print(static_cast<char>(rank)); TheTerminal.print(" "); for (int x=0, file=startFile; x < 8; ++x, file += deltaFile) { const SQUARE square = board.GetSquareContents(file - 'a', rank - '1'); const char *text; switch (square) { case EMPTY: text = ". "; break; case WPAWN: text = "WP"; break; case WKNIGHT: text = "WN"; break; case WBISHOP: text = "WB"; break; case WROOK: text = "WR"; break; case WQUEEN: text = "WQ"; break; case WKING: text = "WK"; break; case BPAWN: text = "BP"; break; case BKNIGHT: text = "BN"; break; case BBISHOP: text = "BB"; break; case BROOK: text = "BR"; break; case BQUEEN: text = "BQ"; break; case BKING: text = "BK"; break; default: text = "??"; break; } TheTerminal.print(text); if (x < 7) // no need for white space at end of line { TheTerminal.print(" "); } } TheTerminal.printline(); TheTerminal.printline(); } // Print file letters at the bottom. TheTerminal.print(" "); for (int x=0, file=startFile; x < 8; ++x, file += deltaFile) { TheTerminal.print(static_cast<char>(file)); if (x < 7) // no need for white space at end of line { TheTerminal.print(" "); } } TheTerminal.printline(); TheTerminal.printline(); }
//---------------------------------------------------------------- // The following function is called by the ChessGame after // each player moves, so that the move can be displayed // in standard chess notation, if the UI desires. // It is helpful to use the ::FormatChessMove() function // for this purpose. // The parameter 'thinkTime' is how long the player thought // about the move, expressed in hundredths of seconds. // // NOTE: This function is called BEFORE the move // has been made on the given ChessBoard. // This is necessary for ::FormatChessMove() to work. //---------------------------------------------------------------- virtual void RecordMove(ChessBoard &board, Move move, INT32 thinkTime) { TheTerminal.print(BoolSideName(board.WhiteToMove())); TheTerminal.print(" move #"); TheTerminal.printInteger((board.GetCurrentPlyNumber()/2) + 1); TheTerminal.print(": "); int source, dest; SQUARE prom = move.actualOffsets(board, source, dest); char sourceFile = XPART(source) - 2 + 'a'; char sourceRank = YPART(source) - 2 + '1'; char destFile = XPART(dest) - 2 + 'a'; char destRank = YPART(dest) - 2 + '1'; TheTerminal.print(sourceFile); TheTerminal.print(sourceRank); TheTerminal.print(destFile); TheTerminal.print(destRank); if (prom) { char pchar = '?'; int pindex = UPIECE_INDEX(prom); switch (pindex) { case Q_INDEX: pchar = 'Q'; break; case R_INDEX: pchar = 'R'; break; case B_INDEX: pchar = 'B'; break; case N_INDEX: pchar = 'N'; break; } TheTerminal.print(pchar); } // Temporarily make the move, so we can display what the board // looks like after the move has been made. // We also use this to determine if the move causes check, // checkmate, stalemate, etc. UnmoveInfo unmove; board.MakeMove(move, unmove); // Report check, checkmate, draws. bool inCheck = board.CurrentPlayerInCheck(); bool canMove = board.CurrentPlayerCanMove(); if (canMove) { if (inCheck) { TheTerminal.print('+'); } } else { // The game is over! if (inCheck) { if (board.WhiteToMove()) { // White just got checkmated. TheTerminal.print("# 0-1"); } else { // Black just got checkmated. TheTerminal.print("# 1-0"); } } else { // The game is a draw (could be stalemate, could be by repetition, insufficient material, ...) TheTerminal.print(" 1/2-1/2"); } } TheTerminal.printline(); // Unmake the move, because the caller will make the move itself. board.UnmakeMove(move, unmove); }
//-------------------------------------------------------------- // The following function should return true if the Move // was read successfully, or false to abort the game. // The move does not have to be legal; if an illegal move // is returned, the caller will repeatedly call until a // legal move is obtained. //-------------------------------------------------------------- virtual bool ReadMove ( ChessBoard &board, int &source, int &dest, SQUARE &promPieceIndex ) // set to 0 (P_INDEX) if no promotion, or call to PromotePawn is needed; set to N_INDEX..Q_INDEX to specify promotion. { promPieceIndex = P_INDEX; bool boardWasAlreadyPrinted = AutoPrintBoard; // accept either of the following two formats: e2e4, g7g8q while (true) { if (IsFirstPrompt) { IsFirstPrompt = false; TheTerminal.printline("Enter 'help' for info and more options."); } TheTerminal.print("Your move? "); std::string line = TheTerminal.readline(); // ================================================================= // REMEMBER: Update "PrintHelp()" every time you add a command! // ================================================================= if (line == "board") { ReallyDrawBoard(board); boardWasAlreadyPrinted = true; } else if (line == "help") { PrintHelp(); } else if (line == "new") { if (human) { human->SetQuitReason(qgr_startNewGame); // suppress saying that the player resigned } return false; // Start a new game. } else if (line == "quit") { throw "Chess program exited."; } else if (line == "show") { AutoPrintBoard = true; if (!boardWasAlreadyPrinted) { ReallyDrawBoard(board); boardWasAlreadyPrinted = true; } } else if (line == "swap") { if (game) { humanSide = OppositeSide(humanSide); if (humanSide == SIDE_WHITE) { game->SetPlayers(human, computer); } else { game->SetPlayers(computer, human); } TheTerminal.print("You are now playing as "); TheTerminal.print(SideName(humanSide)); TheTerminal.printline("."); source = 0; dest = SPECIAL_MOVE_NULL; return true; } } else if (line == "time") { // Adjust computer's think time. TheTerminal.print("The computer's max think time is now "); TheTerminal.printChessTime(ComputerThinkTime); TheTerminal.printline("."); TheTerminal.print("Enter new think time (0.1 .. 600): "); std::string line = TheTerminal.readline(); double thinkTime = atof(line.c_str()); if ((thinkTime >= 0.1) && (thinkTime < 600.0)) { ComputerThinkTime = static_cast<int>(100.0*thinkTime + 0.5); // round seconds to integer centiseconds if (computer) { computer->SetTimeLimit(ComputerThinkTime); } } else { TheTerminal.printline("Invalid think time - ignoring."); } } else { if (ParseFancyMove(line.c_str(), board, source, dest, promPieceIndex)) { return true; } } } }