Home Previous Bottom Next

Writing a chess program in 99 steps


step 63: command.cpp

#ifndef _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE
#endif
#include <conio.h>
#include <iostream>
#include "defines.h"
#include "protos.h"
#include "extglobals.h"
#include "board.h"
#include "timer.h"
 
void readCommands()
{
       int nextc;
 
       if (board.nextMove == WHITE_MOVE)
       {
              std::cout << "wt> ";
       }
              else
       {
              std::cout << "bl> ";
       }
       std::cout.flush();
 
// ===========================================================================
// Read a command and call doCommand:
// ===========================================================================
       while ((nextc = getc(stdin)) != EOF)
       {
              if (nextc == '\n')
              {
                     CMD_BUFF[CMD_BUFF_COUNT] = '\0';
                     while (CMD_BUFF_COUNT)
                     {
                           if (!doCommand(CMD_BUFF)) return;
                     }
                     if (board.nextMove == WHITE_MOVE)
                     {
                           std::cout << "wt> ";
                     }
                     else
                     {
                           std::cout << "bl> ";
                     }
                     std::cout.flush();
              }
              else
              {
                     if (CMD_BUFF_COUNT >= MAX_CMD_BUFF-1)
                     {
                           std::cout << "Warning: command buffer full !! " << std::endl;
                           CMD_BUFF_COUNT = 0;
                     }
                     CMD_BUFF[CMD_BUFF_COUNT++] = nextc;
              }
       }
}
 
BOOLTYPE doCommand(const char *buf)
{
       Move move, dummy;
       char sanMove[12];
       Timer timer;
       U64 msStart;
       U64 msStop;
       U64 perftcount;
       char userinput[80];
       int i, j, number;
 
// =================================================================
// return when command buffer is empty
// =================================================================
 
       if (!strcmp(buf, ""))
       {
              CMD_BUFF_COUNT = '\0';
              return true;   
       }
 
// =================================================================
// help, h, or ?: show this help
// =================================================================
 
       if ((!strcmp(buf, "help")) || (!strcmp(buf, "h")) || (!strcmp(buf, "?")))
       {
              std::cout << std::endl << "help:" << std::endl;
              std::cout << "black               : BLACK to move" << std::endl;
              std::cout << "cc                  : play computer-to-computer " << std::endl;
              std::cout << "d                   : display board " << std::endl;
              std::cout << "exit                : exit program " << std::endl;
              std::cout << "eval                : show static evaluation of this position" << std::endl;
              std::cout << "game                : show game moves " << std::endl;
              std::cout << "go                  : computer next move " << std::endl;
              std::cout << "help, h, or ?       : show this help " << std::endl;
              std::cout << "info                : display variables (for testing purposes)" << std::endl;
              std::cout << "move e2e4, or h7h8q : enter a move (use this format)" << std::endl;
              std::cout << "moves               : show all legal moves" << std::endl;
              std::cout << "new                 : start new game" << std::endl;
              std::cout << "perf                : benchmark a number of key functions" << std::endl;
              std::cout << "perft n             : calculate raw number of nodes from here, depth n " << std::endl;
              std::cout << "quit                : exit program " << std::endl;
              std::cout << "r                   : rotate board " << std::endl;
              std::cout << "readfen filename n  : reads #-th FEN position from filename" << std::endl;
              std::cout << "sd n                : set the search depth to n" << std::endl;
              std::cout << "setup               : setup board... " << std::endl;
              std::cout << "time s              : time per move in seconds" << std::endl;
              std::cout << "undo                : take back last move" << std::endl;
              std::cout << "white               : WHITE to move" << std::endl;
              std::cout << std::endl;
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// black: black to move
// =================================================================
 
       if (!strcmp(buf, "black"))
       {
              if (board.nextMove == WHITE_MOVE)
              {
                     board.endOfSearch = 0;
                     board.endOfGame = 0;
              }
              board.nextMove = BLACK_MOVE;
              CMD_BUFF_COUNT = '\0';
              return true;
       }    
 
// =================================================================
// cc: play computer-to-computer
// =================================================================
 
       if (!strcmp(buf, "cc"))
       {
              while (!_kbhit() && !board.isEndOfgame(i, dummy))
              {
                     move = board.think();
                     if (move.moveInt)
                     {
                           makeMove(move);
                           board.endOfGame++;
                           board.endOfSearch = board.endOfGame;
                           board.display();
                     }
                     else
                     {
                           CMD_BUFF_COUNT = '\0';
                           return true;
                     }
              }
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// d: display board
// =================================================================
 
       if (!strcmp(buf, "d"))
       {
              board.display();
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// eval (do a static evaluation of the board)
// =================================================================
 
       if (!strcmp(buf, "eval"))
       {
              number = board.eval();
              std::cout << "eval score = " << number << std::endl;
              #ifdef WINGLET_DEBUG_EVAL
                     board.mirror();
                     board.display();
                     i = board.eval();
                     std::cout << "eval score = " << i << std::endl;
                     board.mirror();
                     if (number != i) std::cout << "evaluation is not symmetrical! " << number << std::endl;
                     else std::cout << "evaluation is symmetrical" << std::endl;
              #endif
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// exit or quit: exit program
// =================================================================
 
       if ((!strcmp(buf, "exit")) || (!strcmp(buf, "quit")))
       {
              CMD_BUFF_COUNT = '\0';
              return false;
       }
 
// =================================================================
// game: show game moves
// =================================================================
 
       if (!strcmp(buf, "game"))
       {
              if (board.endOfGame)
              {
                     // make a temporary copy of board.gameLine[];
                     number = board.endOfGame;
                     GameLineRecord *tmp = new GameLineRecord[number];
                     memcpy(tmp, board.gameLine, number * sizeof(GameLineRecord));
 
                     // unmake all moves:
                     for (i = number-1 ; i >= 0 ; i--)
                     {
                           unmakeMove(tmp[i].move);
                           board.endOfSearch = --board.endOfGame;
                     }
 
                     // redo all moves:
                     j = board.nextMove;
                     for (i = 0 ; i < number; i++)
                     {
                           // move numbering:
                           if (!((i+j+2)%2)) std::cout << (i+2*j+2)/2 << ". ";
                           else if (!i) std::cout << "1. ... ";
 
                           // construct the move string
                           toSan(tmp[i].move, sanMove);
                           std::cout << sanMove;
 
                           // output CRLF, or space:
                           if (!((i+j+1)%2)) std::cout << std::endl;
                           else std::cout << " ";
 
                           // make the move:
                           makeMove(tmp[i].move);
                           board.endOfSearch = ++board.endOfGame;
                     }
                     std::cout << std::endl;
 
                     // delete the temporary copy:
                     delete[] tmp;
              }
              else
              {
                     std::cout << "there are no game moves" << std::endl;       
              }
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// go: computer next move
// =================================================================
 
       if (!strcmp(buf, "go"))
       {
              if (!board.isEndOfgame(i, dummy))
              {
                     move = board.think();
                     if (move.moveInt)
                     {
                           makeMove(move);
                           board.endOfGame++;
                           board.endOfSearch = board.endOfGame;
                     }
                     board.display();
                     board.isEndOfgame(i, dummy);
                     CMD_BUFF_COUNT = '\0';
                     return true;
              }
              else
              {
                     board.display();
                     CMD_BUFF_COUNT = '\0';
                     return true;
              }
       }
 
// =================================================================
// info: display variables (for testing purposes)
// =================================================================
 
       if (!strcmp(buf, "info"))
       {
              info();
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// moves: show all legal moves
// =================================================================
 
       if (!strcmp(buf, "moves"))
       {
              board.moveBufLen[0] = 0;
              board.moveBufLen[1] = movegen(board.moveBufLen[0]);
              std::cout << std::endl << "moves from this position:" << std::endl;
              number = 0;
              for (i = board.moveBufLen[0]; i < board.moveBufLen[1]; i++)
              {
                     makeMove(board.moveBuffer[i]);
                     if (isOtherKingAttacked())
                     {
                           unmakeMove(board.moveBuffer[i]);
                     }
                     else
                     {
                           unmakeMove(board.moveBuffer[i]);
                           toSan(board.moveBuffer[i], sanMove);
                           std::cout << ++number << ". " << sanMove << std::endl;
                     }
              }
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// move (do a move) [console mode only]
// =================================================================
 
       if (!strncmp(buf, "move", 4))
       {
              sscanf(buf+4,"%s",userinput);
 
              // generate the pseudo-legal move list
              board.moveBufLen[0] = 0;
              board.moveBufLen[1] = movegen(board.moveBufLen[0]);
 
              if (isValidTextMove(userinput, move))        // check to see if the user move is also found in the pseudo-legal move list
              {
                     makeMove(move);
 
                     if (isOtherKingAttacked())              // post-move check to see if we are leaving our king in check
                     {
                           unmakeMove(move);
                           std::cout << "    invalid move, leaving king in check: " << userinput << std::endl;
                     }
                     else
                     {
                           board.endOfGame++;
                           board.endOfSearch = board.endOfGame;
                           board.display();
                     }
              }
              else
              {
                     std::cout << "    move is invalid or not recognized: " << userinput << std::endl;
              }
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// new: start new game
// =================================================================
 
       if (!strcmp(buf, "new"))
       {
              board.init();
              board.display();
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// perft n  : calculate raw number of nodes from here, depth n
// =================================================================
 
       if (!strncmp(buf, "perft", 5))
       {
              sscanf(buf+5,"%d", &number);
              std::cout << "    starting perft " << number << "..." << std::endl;
              timer.init();
              board.moveBufLen[0] = 0;
 
              #ifdef WINGLET_DEBUG_PERFT
                     ICAPT = 0;
                     IEP = 0;
                     IPROM = 0;
                     ICASTLOO = 0;
                     ICASTLOOO = 0;
                     ICHECK = 0;
              #endif
 
              msStart = timer.getms();
              perftcount = perft(0, number);
              msStop = timer.getms();
 
              std::cout << "nodes        = " << perftcount << ", " << msStop - msStart << " ms, ";
              if ((msStop - msStart) > 0)
              std::cout << (perftcount/(msStop - msStart)) << " knods/s";
              std::cout << std::endl;
              CMD_BUFF_COUNT = '\0';
 
              #ifdef WINGLET_DEBUG_PERFT
                     std::cout << "captures     = " << ICAPT << std::endl;
                     std::cout << "en-passant   = " << IEP << std::endl;
                     std::cout << "castlings    = " << ICASTLOO + ICASTLOOO << std::endl;
                     std::cout << "promotions   = " << IPROM << std::endl;
                     std::cout << "checks       = " << ICHECK << std::endl;
              #endif
              return true;
       }
 
// =================================================================
// r: rotate board
// =================================================================
 
       if (!strcmp(buf, "r"))
       {
              board.viewRotated = !board.viewRotated;
              board.display();
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// readfen filename n : reads #-th FEN position from filename
// =================================================================
 
       if (!strncmp(buf, "readfen", 7))
       {
              sscanf(buf+7,"%s %d", userinput, &number);
              board.init();
              readFen(userinput, number);
              board.display();
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// sd n: set the search depth to n
// =================================================================
 
       if (!strncmp(buf, "sd", 2))
       {
              sscanf(buf+2,"%d", &board.searchDepth);
              std::cout << "winglet> search depth " << board.searchDepth << std::endl;
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// setup : setup board...
// =================================================================
 
       if (!strncmp(buf, "setup", 5))
       {
              setup();
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// undo: take back last move
// =================================================================
 
       if (!strcmp(buf, "undo"))
       {
              if (board.endOfGame)
              {
                     unmakeMove(board.gameLine[--board.endOfGame].move);
                     board.endOfSearch = board.endOfGame;
                     board.display();
              }
              else
              {
                     std::cout << "already at start of game" << std::endl;
              }
              CMD_BUFF_COUNT = '\0';
              return true;
       }
 
// =================================================================
// white: white to move
// =================================================================
 
       if (!strcmp(buf, "white"))
       {
              if (board.nextMove == BLACK_MOVE)
              {
                     board.endOfSearch = 0;
                     board.endOfGame = 0;
              }
              board.nextMove = WHITE_MOVE;
              CMD_BUFF_COUNT = '\0';
              return true;
       }    
 
// ================================================================
// unknown command
// =================================================================
 
       std::cout << "    command not implemented: " << buf << ", type 'help' for more info" << std::endl;
       CMD_BUFF_COUNT = '\0';
       return true;
}

 

step 64: data.cpp

(...)
//     ===========================================================================
//     Initialize MIRRORed data:
//     ===========================================================================
       // Data is supplied as mirrored for WHITE, so it's ready for BLACK to use:
       for (square = 0; square < 64; square++)
       {
              PAWNPOS_B[square] = PAWNPOS_W[square];
              KNIGHTPOS_B[square] = KNIGHTPOS_W[square];
              BISHOPPOS_B[square] = BISHOPPOS_W[square];
              ROOKPOS_B[square] = ROOKPOS_W[square];
              QUEENPOS_B[square] = QUEENPOS_W[square];
              KINGPOS_B[square] = KINGPOS_W[square];
              KINGPOS_ENDGAME_B[square] = KINGPOS_ENDGAME_W[square];
       }
 
       // Complete missing mirrored data:
       for (i = 0; i < 64; i++)
       {
              PAWNPOS_W[i] = PAWNPOS_B[MIRROR[i]];
              KNIGHTPOS_W[i] = KNIGHTPOS_B[MIRROR[i]];
              BISHOPPOS_W[i] = BISHOPPOS_B[MIRROR[i]];
              ROOKPOS_W[i] = ROOKPOS_B[MIRROR[i]];
              QUEENPOS_W[i] = QUEENPOS_B[MIRROR[i]];
              KINGPOS_W[i] = KINGPOS_B[MIRROR[i]];
              KINGPOS_ENDGAME_W[i] = KINGPOS_ENDGAME_B[MIRROR[i]];
 
              for (square = 0; square < 64; square ++)
              {
                     //  PASSED_BLACK bitmaps (mirror of PASSED_WHITE bitmaps):
                     if (PASSED_WHITE[i] & BITSET[square]) PASSED_BLACK[MIRROR[i]] |= BITSET[MIRROR[square]];
 
                     //  ISOLATED_BLACK bitmaps (mirror of ISOLATED_WHITE bitmaps):
                     if (ISOLATED_WHITE[i] & BITSET[square]) ISOLATED_BLACK[MIRROR[i]] |= BITSET[MIRROR[square]];
 
                     //  BACKWARD_BLACK bitmaps (mirror of BACKWARD_WHITE bitmaps):
                     if (BACKWARD_WHITE[i] & BITSET[square]) BACKWARD_BLACK[MIRROR[i]] |= BITSET[MIRROR[square]];
 
                     //  KINGSHIELD_STRONG_B bitmaps (mirror of KINGSHIELD_STRONG_W bitmaps):
                     if (KINGSHIELD_STRONG_W[i] & BITSET[square]) KINGSHIELD_STRONG_B[MIRROR[i]] |= BITSET[MIRROR[square]];
 
                     //  KINGSHIELD_WEAK_B bitmaps (mirror of KINGSHIELD_WEAK_W bitmaps):
                     if (KINGSHIELD_WEAK_W[i] & BITSET[square]) KINGSHIELD_WEAK_B[MIRROR[i]] |= BITSET[MIRROR[square]];
              }
       }
 
       NOMOVE.moveInt = 0;
 
    return;
}
 
void info()
{
 
       //  your playground... display variables - meant for testing/verification purposes only
       std::cout << std::endl << "============ info start ==============" << std::endl;
       std::cout << "size of board, in bytes   = " << sizeof(board) << std::endl;
       std::cout << "Material value            = " << board.Material << std::endl;
       std::cout << "White castling rights     = " << int(board.castleWhite) << std::endl;
       std::cout << "Black castling rights     = " << int(board.castleBlack) << std::endl;
       std::cout << "En-passant square         = " << board.epSquare << std::endl;
       std::cout << "Fifty move count          = " << board.fiftyMove << std::endl;
 
       std::cout << "bitCnt of white pawns     = " << bitCnt(board.whitePawns) << std::endl;
       std::cout << std::endl << "bitmap of blackKnights | board.whitePawns:" << std::endl;
       displayBitmap(board.blackKnights | board.whitePawns);
       std::cout << "============ info end ================" << std::endl << std::endl;
 
       return;
}

 


Home Previous Top Next

last update: Friday 17 June 2011