#ifndef _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE 1
#endif
#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;
Timer timer;
U64 msStart;
U64 msStop;
U64 perftcount;
char
userinput[80];
int i,
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 <<
"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"))
{
board.nextMove = BLACK_MOVE;
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;
}
//
=================================================================
// go: computer next move
//
=================================================================
if (!strcmp(buf,
"go"))
{
move = board.think();
if (move.moveInt)
{
makeMove(move);
board.endOfGame++;
board.endOfSearch = board.endOfGame;
}
board.display();
CMD_BUFF_COUNT =
'\0';
return
true;
}
//
=================================================================
// game: show game moves
//
=================================================================
if (!strcmp(buf,
"game"))
{
if (board.endOfGame)
{
for (i = 0
; i < board.endOfGame ; i++)
{
std::cout << i+1 << ". ";
displayMove(board.gameLine[i].move);
std::cout <<std::endl;
}
}
else
{
std::cout
<< "there are no game moves"
<< std::endl;
}
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;
for (i =
board.moveBufLen[0]; i < board.moveBufLen[1]; i++)
{
makeMove(board.moveBuffer[i]);
if (isOtherKingAttacked())
{
unmakeMove(board.moveBuffer[i]);
}
else
{
std::cout << i+1 << ". "
;
displayMove(board.moveBuffer[i]);
std::cout << std::endl;
unmakeMove(board.moveBuffer[i]);
}
}
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;
}
//
=================================================================
// 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 << "pseudo-legal moves
from this position:" << std::endl;
for (i =
board.moveBufLen[0]; i < board.moveBufLen[1]; i++)
{
std::cout << i+1 << ". "
;
displayMove(board.moveBuffer[i]);
std::cout << std::endl;
}
CMD_BUFF_COUNT =
'\0';
return
true;
}
//
=================================================================
// new: start new game
//
=================================================================
if
(!strcmp(buf, "new"))
{
dataInit();
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"))
{
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;
}
There still are some serious issues with the current search
functionality, we will address these one by one in the next sections.
The most important shortcomings are:
-
the search assumes that there will always be a
legal move. Of course that is not true in case one of the variations
leads to a stalemate, or a checkmate, before the end of the tree is
reached. Checkmates are not identified a such !
-
there is no move ordering, which makes the
search still kind of sluggish, and doing a lot of unnecessary work.
-
you will often see a score that is
oscillating for even/odd search depths (high for odd search depths,
low for even search depths), and the last move in
the PV is a capture. This
is because we are searching to a fixed depth and then stop, even if
we are in the middle of an exchange of pieces. Actually,
since there is no check for this, the search will now show a
preference to end the PV with a capture for the side to move (or
promotion), because the side not to move cannot recapture!

√
setup, or read, a position, or just take the start position,
and type "sd 5" to set the search depth at a fixed
value of 5 plies, then type "go" to have your computer
search and carry out the best move.
√
you can compare searches by the minimax, alphabeta, or
alphabetapvs algorithms (just uncomment the respective code
lines in function 'think') and see the differences in search
times and nodes visited.
|
|