summaryrefslogtreecommitdiffstats
path: root/knights/logic.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'knights/logic.cpp')
-rw-r--r--knights/logic.cpp1495
1 files changed, 1495 insertions, 0 deletions
diff --git a/knights/logic.cpp b/knights/logic.cpp
new file mode 100644
index 0000000..9d889d4
--- /dev/null
+++ b/knights/logic.cpp
@@ -0,0 +1,1495 @@
+/***************************************************************************
+ logic.cpp - description
+ -------------------
+ begin : Sat Sep 29 2001
+ copyright : (C) 2003 by Troy Corbin Jr.
+ email : tcorbin@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "logic.h"
+#include "dlg_promote.h"
+#include "command.h"
+#include <stdlib.h>
+
+///////////////////////////////////////
+//
+// logic::logic
+//
+///////////////////////////////////////
+logic::logic( resource *Rsrc, match_param *param )
+{
+ Resource = Rsrc;
+ Param = param;
+ int tmp;
+
+ GameType = Type_Standard;
+ for( tmp = 0; tmp < 64; tmp++ )
+ {
+ current[tmp].File = ( tmp % 8 );
+ current[tmp].Rank = ( tmp >> 3 );
+ }
+ clearBoard();
+}
+///////////////////////////////////////
+//
+// logic::~logic
+//
+///////////////////////////////////////
+logic::~logic()
+{
+}
+///////////////////////////////////////
+//
+// logic::Pointer
+//
+///////////////////////////////////////
+int logic::Pointer( const char File, const char Rank )
+{
+ if( ( File < 0 ) || ( File > 7 ) ) return Null;
+ if( ( Rank < 0 ) || ( Rank > 7 ) ) return Null;
+ return ( ( Rank << 3 ) + File );
+}
+///////////////////////////////////////
+//
+// logic::CalcPointer
+//
+///////////////////////////////////////
+int logic::CalcPointer( const char File, const char Rank )
+{
+ char tmpFile, tmpRank;
+
+ tmpFile = chessman[ManPtr].File + File;
+ tmpRank = chessman[ManPtr].Rank + Rank;
+ return Pointer( tmpFile, tmpRank );
+}
+///////////////////////////////////////
+//
+// logic::isChessman
+//
+///////////////////////////////////////
+bool logic::isChessman( const char ChessmanPtr )
+{
+ char BoardPtr = Pointer( chessman[ChessmanPtr].File, chessman[ChessmanPtr].Rank );
+ if( ( BoardPtr < 0 ) || ( BoardPtr > 63 ) ) return FALSE;
+ if( current[BoardPtr].ManPtr != ChessmanPtr ) return FALSE;
+ return TRUE;
+}
+///////////////////////////////////////
+//
+// logic::clearBoard
+//
+///////////////////////////////////////
+void logic::clearBoard( void )
+{
+ for( register int tmp = 0; tmp < 64; tmp++ )
+ {
+ chessman[tmp].Type = Null;
+ current[tmp].ManPtr = Null;
+ current[tmp].Note = NOTE_NONE;
+ }
+}
+///////////////////////////////////////
+//
+// logic::Init
+//
+///////////////////////////////////////
+void logic::Init( const int Var )
+{
+ GameType = Var;
+ switch( GameType )
+ {
+ case Type_Standard: // Fall Through
+ default:
+ Init_Standard();
+ break;
+ }
+}
+///////////////////////////////////////
+//
+// logic::Init_Standard
+//
+///////////////////////////////////////
+void logic::Init_Standard( void )
+{
+ register int tmp;
+
+ clearBoard();
+ for( tmp = 0; tmp < 32; tmp++ )
+ {
+ if( tmp < 16 )
+ {
+ chessman[tmp].Army = WHITE;
+ chessman[tmp].Rank = 0;
+ }
+ else
+ {
+ chessman[tmp].Army = BLACK;
+ chessman[tmp].Rank = 7;
+ }
+ switch( tmp % 16 )
+ {
+ case 0:
+ chessman[tmp].Type = King;
+ chessman[tmp].File = 4;
+ break;
+ case 1:
+ chessman[tmp].Type = Queen;
+ chessman[tmp].File = 3;
+ break;
+ case 2:
+ chessman[tmp].Type = Bishop;
+ chessman[tmp].File = 2;
+ break;
+ case 3:
+ chessman[tmp].Type = Bishop;
+ chessman[tmp].File = 5;
+ break;
+ case 4:
+ chessman[tmp].Type = Knight;
+ chessman[tmp].File = 1;
+ break;
+ case 5:
+ chessman[tmp].Type = Knight;
+ chessman[tmp].File = 6;
+ break;
+ case 6:
+ chessman[tmp].Type = Rook;
+ chessman[tmp].File = 0;
+ break;
+ case 7:
+ chessman[tmp].Type = Rook;
+ chessman[tmp].File = 7;
+ break;
+ default:
+ chessman[tmp].Type = Pawn;
+ chessman[tmp].File = ( tmp % 16 ) - 8;
+ if( chessman[tmp].Army == WHITE ) chessman[tmp].Rank = 1;
+ else chessman[tmp].Rank = 6;
+ break;
+ }
+ current[ Pointer( chessman[tmp].File, chessman[tmp].Rank ) ].ManPtr = tmp;
+ CastleFlag[0] = CF_King + CF_RookQ + CF_RookK;
+ CastleFlag[1] = CF_King + CF_RookQ + CF_RookK;
+ OnMove = WHITE;
+ }
+}
+///////////////////////////////////////
+//
+// logic::parseCAN
+//
+///////////////////////////////////////
+bool logic::parseCAN( const bool Army )
+{
+ if( chessMove.CAN == NULL ) return FALSE;
+ if( ( chessMove.CAN[0] != 'o' ) && ( chessMove.CAN[0] != 'O' ) )
+ {
+ if( ( chessMove.CAN[0] < 'a' ) || ( chessMove.CAN[0] > 'h' ) ) return FALSE;
+ chessMove.fromFile = chessMove.CAN[0] - 97;
+ if( ( chessMove.CAN[1] < '1' ) || ( chessMove.CAN[1] > '8' ) ) return FALSE;
+ chessMove.fromRank = chessMove.CAN[1] - 49;
+ if( ( chessMove.CAN[2] < 'a' ) || ( chessMove.CAN[2] > 'h' ) ) return FALSE;
+ chessMove.toFile = chessMove.CAN[2] - 97;
+ if( ( chessMove.CAN[3] < '1' ) || ( chessMove.CAN[3] > '8' ) ) return FALSE;
+ chessMove.toRank = chessMove.CAN[3] - 49;
+ if( strlen( chessMove.CAN ) == 5 ) chessMove.Promote = chessMove.CAN[4];
+ else chessMove.Promote = Null;
+ }
+ /*
+ For some reason some engines w/ CAN output
+ express castling using SAN, not to name names GNUChess v4
+ */
+ else
+ {
+ chessMove.fromFile = 4;
+ if( QString( chessMove.CAN ).lower() == "o-o" ) chessMove.toFile = 6;
+ else chessMove.toFile = 2;
+ if( Army == WHITE )
+ {
+ chessMove.fromRank = 0;
+ chessMove.toRank = 0;
+ }
+ else
+ {
+ chessMove.fromRank = 7;
+ chessMove.toRank = 7;
+ }
+ }
+ return TRUE;
+}
+///////////////////////////////////////
+//
+// logic::parseSAN
+//
+///////////////////////////////////////
+bool logic::parseSAN( void )
+{
+ bool Army(OnMove);
+ char Type(Pawn);
+ char SANPtr(0), tmp(0);
+
+ chessMove.fromFile = Null;
+ chessMove.fromRank = Null;
+ chessMove.toFile = Null;
+ chessMove.toRank = Null;
+ chessMove.Promote = Null;
+ chessMove.ManTaken = Null;
+ chessMove.NAG = 0;
+ while( SANPtr < (signed)QString( chessMove.SAN ).length() )
+ {
+ /* Parse a character */
+ switch( chessMove.SAN[SANPtr] )
+ {
+ case 'K':
+ if( SANPtr == 0 )
+ Type = King;
+ else
+ chessMove.Promote = 'k';
+ break;
+ case 'Q':
+ if( SANPtr == 0 )
+ Type = Queen;
+ else
+ chessMove.Promote = 'q';
+ break;
+ case 'B':
+ if( SANPtr == 0 )
+ Type = Bishop;
+ else
+ chessMove.Promote = 'b';
+ break;
+ case 'N':
+ if( SANPtr == 0 )
+ Type = Knight;
+ else
+ chessMove.Promote = 'n';
+ break;
+ case 'R':
+ if( SANPtr == 0 )
+ Type = Rook;
+ else
+ chessMove.Promote = 'r';
+ break;
+ /* Parse castle */
+ case 'o':
+ case 'O':
+ if( SANPtr != 0 )
+ break;
+ Type = King;
+ if( Army == WHITE )
+ chessMove.toRank = 0;
+ else
+ chessMove.toRank = 7;
+ if( QString( chessMove.SAN ).lower() == "o-o-o" )
+ chessMove.toFile = 2;
+ if( QString( chessMove.SAN ).lower() == "o-o" )
+ chessMove.toFile = 6;
+ break;
+ /* Ignore some symbols... these fall through */
+ case 'x':
+ case '=':
+ case '#':
+ case '+':
+ case '-':
+ case 'P':
+ break;
+ /* Handle annotations */
+ case '!':
+ chessMove.NAG = 1;
+ if( chessMove.SAN[SANPtr - 1] == '!' )
+ chessMove.NAG = 3;
+ if( chessMove.SAN[SANPtr - 1] == '?' )
+ chessMove.NAG = 6;
+ break;
+ case '?':
+ chessMove.NAG = 2;
+ if( chessMove.SAN[SANPtr - 1] == '!' )
+ chessMove.NAG = 5;
+ if( chessMove.SAN[SANPtr - 1] == '?' )
+ chessMove.NAG = 4;
+ break;
+ default:
+ if( ( chessMove.SAN[SANPtr] >= '1' ) && ( chessMove.SAN[SANPtr] <= '8' ) )
+ {
+ if( chessMove.toRank != Null )
+ chessMove.fromRank = chessMove.toRank;
+ chessMove.toRank = chessMove.SAN[SANPtr] - 49;
+ break;
+ }
+ if( ( chessMove.SAN[SANPtr] >= 'a' ) && ( chessMove.SAN[SANPtr] <= 'h' ) )
+ {
+ if( chessMove.toFile != Null )
+ chessMove.fromFile = chessMove.toFile;
+ chessMove.toFile = chessMove.SAN[SANPtr] - 97;
+ break;
+ }
+ /* Unknown symbol... Can not process this chessMove */
+// kdDebug() << "logic::ParseSAN: Unknown Symbol: " << chessMove.SAN[SANPtr] << "\n";
+ return FALSE;
+ break;
+ }
+ SANPtr++;
+ }
+ for( tmp = 0; tmp < 64; tmp++ )
+ {
+ if( chessman[tmp].Type != Type )
+ continue;
+ if( chessman[tmp].Army != Army )
+ continue;
+ if( ( chessMove.fromFile != Null ) && ( chessman[tmp].File != chessMove.fromFile ) )
+ continue;
+ if( ( chessMove.fromRank != Null ) && ( chessman[tmp].Rank != chessMove.fromRank ) )
+ continue;
+ if( !isChessman( tmp ) )
+ continue;
+ HashLegal( tmp );
+ if( current[ ( chessMove.toRank << 3 ) + chessMove.toFile ].Note < NOTE_MOVE )
+ continue;
+ chessMove.fromFile = chessman[tmp].File;
+ chessMove.fromRank = chessman[tmp].Rank;
+ break;
+ }
+ if( tmp == 64 )
+ {
+// kdWarning() << "logic::ParseSAN could not make a legal chessMove out of " << QString( chessMove.SAN ) << endl;
+// kdWarning() << (int)Army << " " << (int)Type << " " << (int)chessMove.fromFile << " " << (int)chessMove.fromRank
+// << " " << (int)chessMove.toFile << " " << (int)chessMove.toRank << endl;
+ return FALSE;
+ }
+ return TRUE;
+}
+///////////////////////////////////////
+//
+// logic::writeCAN
+//
+///////////////////////////////////////
+void logic::writeCAN( void )
+{
+ chessMove.CAN[0] = chessMove.fromFile + 97;
+ chessMove.CAN[1] = chessMove.fromRank + 49;
+ chessMove.CAN[2] = chessMove.toFile + 97;
+ chessMove.CAN[3] = chessMove.toRank + 49;
+ if( chessMove.Promote == Null ) chessMove.CAN[4] = 0;
+ else
+ {
+ chessMove.CAN[4] = chessMove.Promote;
+ chessMove.CAN[5] = 0;
+ }
+}
+///////////////////////////////////////
+//
+// logic::writeSAN
+//
+///////////////////////////////////////
+void logic::writeSAN( void )
+{
+ Position backup[64];
+ bool SANambig(FALSE);
+ bool SANambig2(FALSE);
+ register char tmp, manPtr, toPtr, fromPtr;
+ QString SAN;
+
+ /*
+ writeSAN calls HashLegal(), which writes on current[],
+ which we need intact for Move()... so we need a backup
+ copy of current[]. Removing this breaks en passant moves
+ */
+ copyPositions( current, backup );
+ fromPtr = ( chessMove.fromRank << 3 ) + chessMove.fromFile;
+ toPtr = ( chessMove.toRank << 3 ) + chessMove.toFile;
+ if( ( fromPtr > 63 ) || ( toPtr > 63 ) ) return;
+ if( ( fromPtr < 0 ) || ( toPtr < 0 ) ) return;
+ manPtr = current[fromPtr].ManPtr;
+ if( manPtr == Null ) return;
+
+ /* Check ambiguity for SAN notation */
+ for( tmp = 0; tmp < 64; tmp++ )
+ {
+ if( tmp == manPtr ) continue;
+ if( !isChessman( tmp ) ) continue;
+ if( chessman[tmp].Army == chessman[manPtr].Army )
+ {
+ if( chessman[tmp].Type == chessman[manPtr].Type )
+ {
+ HashLegal( tmp );
+ if( current[toPtr].Note >= NOTE_MOVE )
+ {
+ SANambig = TRUE;
+ if( chessman[tmp].File == chessman[manPtr].File )
+ SANambig2 = TRUE;
+ }
+ }
+ /*
+ This IF was added to fix an ambiguity that occurs when a pawn
+ on B file and a Bishop can attack the same spot
+ */
+ else
+ if( ( ( chessman[manPtr].Type == Bishop ) && ( chessman[tmp].Type == Pawn ) ) ||
+ ( ( chessman[manPtr].Type == Pawn ) && ( chessman[tmp].Type == Bishop ) ) )
+ {
+ if( ( chessman[manPtr].File == 1 ) || ( chessman[tmp].File == 1 ) )
+ {
+ HashLegal( tmp );
+ if( current[toPtr].Note >= NOTE_MOVE )
+ {
+ SANambig = TRUE;
+ SANambig2 = TRUE;
+ }
+ }
+ }
+ }
+ }
+ /* Go ahead and restore the backup. */
+ copyPositions( backup, current );
+ if( ( ( current[toPtr].Note == NOTE_ATTACK ) ||
+ ( current[toPtr].Note == NOTE_ENPASSANT ) ) &&
+ ( chessman[manPtr].Type == Pawn ) )
+ {
+ SANambig = TRUE;
+ }
+ /* Write SAN Notation */
+ if( current[toPtr].Note == NOTE_CASTLE )
+ {
+ if( chessMove.toFile == 6 ) SAN = "O-O";
+ if( chessMove.toFile == 2 ) SAN = "O-O-O";
+ }
+ else
+ {
+ switch( chessman[manPtr].Type )
+ {
+ case King:
+ SAN += 'K';
+ break;
+ case Queen:
+ SAN += 'Q';
+ break;
+ case Bishop:
+ SAN += 'B';
+ break;
+ case Knight:
+ SAN += 'N';
+ break;
+ case Rook:
+ SAN += 'R';
+ break;
+ case Pawn:
+// if( SANambig2 ) SAN += 'P';
+ break;
+ default:
+ break;
+ }
+ if( SANambig == TRUE )
+ {
+ SAN += char( chessMove.fromFile + 97 );
+ if( SANambig2 ) SAN += char( chessMove.fromRank + 49 );
+ }
+ if( ( current[toPtr].Note == NOTE_ATTACK ) ||
+ ( current[toPtr].Note == NOTE_ENPASSANT ) )
+ SAN += 'x';
+ SAN += char( chessMove.toFile + 97 );
+ SAN += char( chessMove.toRank + 49 );
+ switch( chessMove.Promote )
+ {
+ case 'q':
+ chessman[manPtr].Type = Queen;
+ SAN += "=Q";
+ break;
+ case 'b':
+ chessman[manPtr].Type = Bishop;
+ SAN += "=B";
+ break;
+ case 'n':
+ chessman[manPtr].Type = Knight;
+ SAN += "=N";
+ break;
+ case 'r':
+ chessman[manPtr].Type = Rook;
+ SAN += "=R";
+ break;
+ default:
+ break;
+ }
+ }
+ strcpy( chessMove.SAN, SAN.latin1() );
+}
+///////////////////////////////////////
+//
+// logic::board
+//
+///////////////////////////////////////
+QString logic::board( void )
+{
+ QString output;
+ register int tmp(0), tmpMan(0), cR(7), cF(0);
+
+ while( tmp != 64 )
+ {
+ tmpMan = current[ Pointer( cF, cR ) ].ManPtr;
+ if( tmpMan == Null )
+ output += '-';
+ else
+ {
+ switch( chessman[ tmpMan ].Type )
+ {
+ case King:
+ if( chessman[ tmpMan ].Army == WHITE )
+ output += 'K';
+ else
+ output += 'k';
+ break;
+ case Queen:
+ if( chessman[ tmpMan ].Army == WHITE )
+ output += 'Q';
+ else
+ output += 'q';
+ break;
+ case Bishop:
+ if( chessman[ tmpMan ].Army == WHITE )
+ output += 'B';
+ else
+ output += 'b';
+ break;
+ case Knight:
+ if( chessman[ tmpMan ].Army == WHITE )
+ output += 'N';
+ else
+ output += 'n';
+ break;
+ case Rook:
+ if( chessman[ tmpMan ].Army == WHITE )
+ output += 'R';
+ else
+ output += 'r';
+ break;
+ case Pawn: // Fall through
+ default:
+ if( chessman[ tmpMan ].Army == WHITE )
+ output += 'P';
+ else
+ output += 'p';
+ break;
+ }
+ }
+ cF++;
+ tmp++;
+ if( cF == 8 )
+ {
+ cF = 0;
+ cR--;
+ }
+ }
+
+ if( CastleFlag[WHITE] & ( CF_King | CF_RookK ) )
+ output += '1';
+ else
+ output += '0';
+ if( CastleFlag[WHITE] & ( CF_King | CF_RookQ ) )
+ output += '1';
+ else
+ output += '0';
+ if( CastleFlag[BLACK] & ( CF_King | CF_RookK ) )
+ output += '1';
+ else
+ output += '0';
+ if( CastleFlag[BLACK] & ( CF_King | CF_RookQ ) )
+ output += '1';
+ else
+ output += '0';
+
+ return output;
+}
+///////////////////////////////////////
+//
+// logic::setBoard
+//
+///////////////////////////////////////
+void logic::setBoard( const QString &board, const short ppf )
+{
+ QChar piece;
+ int tmp(0), tmp2(0), cR(7), cF(0);
+
+ clearBoard();
+ if( board.length() < 64 )
+ {
+ kdWarning() << "logic::setBoard: Was passed a string that is less than 64 bytes long." << endl;
+ return;
+ }
+ while( tmp != 64 )
+ {
+ piece = board.at(tmp++);
+ switch( piece.lower() )
+ {
+ case 'k':
+ if( piece == 'K' ) chessman[tmp2].Army = WHITE;
+ else chessman[tmp2].Army = BLACK;
+ chessman[tmp2].Type = King;
+ break;
+ case 'q':
+ if( piece == 'Q' ) chessman[tmp2].Army = WHITE;
+ else chessman[tmp2].Army = BLACK;
+ chessman[tmp2].Type = Queen;
+ break;
+ case 'b':
+ if( piece == 'B' ) chessman[tmp2].Army = WHITE;
+ else chessman[tmp2].Army = BLACK;
+ chessman[tmp2].Type = Bishop;
+ break;
+ case 'n':
+ if( piece == 'N' ) chessman[tmp2].Army = WHITE;
+ else chessman[tmp2].Army = BLACK;
+ chessman[tmp2].Type = Knight;
+ break;
+ case 'r':
+ if( piece == 'R' ) chessman[tmp2].Army = WHITE;
+ else chessman[tmp2].Army = BLACK;
+ chessman[tmp2].Type = Rook;
+ break;
+ case 'p':
+ if( piece == 'P' ) chessman[tmp2].Army = WHITE;
+ else chessman[tmp2].Army = BLACK;
+ chessman[tmp2].Type = Pawn;
+ break;
+ default:
+ break;
+ }
+ if( piece != '-' )
+ {
+ chessman[tmp2].Rank = cR;
+ chessman[tmp2].File = cF;
+ current[ Pointer( cF, cR ) ].ManPtr = tmp2;
+ tmp2++;
+ }
+ cF++;
+ if( cF == 8 )
+ {
+ cF = 0;
+ cR--;
+ }
+ }
+ CastleFlag[WHITE] = 0;
+ CastleFlag[BLACK] = 0;
+ if( board.at(64) == '1' ) CastleFlag[WHITE] += CF_RookK;
+ if( board.at(65) == '1' ) CastleFlag[WHITE] += CF_RookQ;
+ if( board.at(66) == '1' ) CastleFlag[BLACK] += CF_RookK;
+ if( board.at(67) == '1' ) CastleFlag[BLACK] += CF_RookQ;
+ if( CastleFlag[WHITE] ) CastleFlag[WHITE] += CF_King;
+ if( CastleFlag[BLACK] ) CastleFlag[BLACK] += CF_King;
+ /* Update enpassant record */
+ if( ppf != -2 )
+ {
+ enPassant[ !OnMove ] = Null;
+ if( ppf != -1 )
+ enPassant[ OnMove ] = ppf + 24 + ( ( OnMove == BLACK ) << 3 );
+ }
+}
+///////////////////////////////////////
+//
+// logic::getKing
+//
+///////////////////////////////////////
+int logic::getKing( const bool Army )
+{
+ register int tmp;
+ for( tmp = 0; tmp < 64; tmp++ )
+ {
+ if( ( chessman[tmp].Army == Army ) && ( chessman[tmp].Type == King ) )
+ if( isChessman( tmp ) )
+ {
+ return Pointer( chessman[tmp].File, chessman[tmp].Rank );
+ }
+ }
+ return Null;
+}
+///////////////////////////////////////
+//
+// logic::isCheck
+//
+///////////////////////////////////////
+bool logic::isCheck( const bool Army )
+{
+ register char tmp(0), currentKing( getKing(Army) );
+
+ for( tmp = 0; tmp < 64; tmp++ )
+ {
+ if( chessman[tmp].Army != Army )
+ if( isChessman( tmp ) )
+ {
+ HashLegal( tmp );
+ if( current[ currentKing ].Note == NOTE_ATTACK ) return TRUE;
+ }
+ }
+ return FALSE;
+}
+///////////////////////////////////////
+//
+// logic::isLegal
+//
+///////////////////////////////////////
+bool logic::isLegal( const bool Army )
+{
+ register int tmp(0), tmp2(0), count(0);
+
+ for( tmp2 = 0; tmp2 < 64; tmp2++ )
+ {
+ if( chessman[tmp2].Army == Army )
+ if( isChessman( tmp2 ) )
+ {
+ ManPtr = tmp2;
+ _HashLegal();
+ count = 0;
+ tmp = 0;
+ while( tmp < 64 ) count += ( current[tmp++].Note >= NOTE_MOVE );
+ if( count ) return TRUE;
+ }
+ }
+ return FALSE;
+}
+///////////////////////////////////////
+//
+// logic::isDraw
+//
+///////////////////////////////////////
+bool logic::isDraw( const bool Army )
+{
+ bool haveBishop(FALSE);
+ bool haveBishopDiag(FALSE);
+ bool haveKnight(FALSE);
+ bool EnemyBishop(FALSE);
+ bool EnemyBishopDiag(TRUE);
+ bool EnemyKnight(FALSE);
+ int tmp(0);
+
+ if( !isLegal( Army ) ) return TRUE;
+ for( tmp = 0; tmp < 64; tmp++ )
+ {
+ if( !isChessman( tmp ) ) continue;
+ if( chessman[tmp].Type == Queen ) return FALSE;
+ if( chessman[tmp].Type == Pawn ) return FALSE;
+ if( chessman[tmp].Type == Rook ) return FALSE;
+ /* Enemy guys */
+ if( chessman[tmp].Army != Army )
+ {
+ if( chessman[tmp].Type == Bishop )
+ {
+ if( EnemyBishop == TRUE ) return FALSE;
+ EnemyBishopDiag = abs( ( current[tmp].Rank % 2 ) - ( current[tmp].File % 2 ) );
+ EnemyBishop = TRUE;
+ }
+ if( chessman[tmp].Type == Knight )
+ {
+ if( EnemyKnight == TRUE ) return FALSE;
+ EnemyKnight = TRUE;
+ }
+ continue;
+ }
+ /* Our guys */
+ if( chessman[tmp].Type == Bishop )
+ {
+ if( haveBishop == TRUE ) return FALSE;
+ haveBishopDiag = abs( ( current[tmp].Rank % 2 ) - ( current[tmp].File % 2 ) );
+ haveBishop = TRUE;
+ }
+ if( chessman[tmp].Type == Knight )
+ {
+ if( haveKnight == TRUE ) return FALSE;
+ haveKnight = TRUE;
+ }
+ }
+ if( haveKnight && EnemyKnight ) return FALSE;
+ if( haveBishop && EnemyKnight ) return FALSE;
+ if( haveKnight && EnemyBishop ) return FALSE;
+ if( haveKnight && haveBishop ) return FALSE;
+ if( EnemyKnight && EnemyBishop ) return FALSE;
+ if( ( haveBishop && EnemyBishop ) && ( haveBishopDiag != EnemyBishopDiag ) ) return FALSE;
+ return TRUE;
+}
+///////////////////////////////////////
+//
+// logic::setBoardFromFen
+//
+///////////////////////////////////////
+void logic::setBoardFromFen(const QString &fen)
+{
+ clearBoard();
+ int j = 0; //position in string
+ int r = 7; //rank
+ int f = 0; //file
+ int p = 63; //chessman number
+ QChar c; //current letter
+
+ for (j=0;j<120 && p>=0 ;j++) {
+ c = fen[j];
+
+ if (c.isLetter()) {
+ //describing a piece
+ if (c == 'r') {
+ chessman[p].Army = BLACK;
+ chessman[p].Type = Rook;
+
+ }
+ if (c=='q') {
+ chessman[p].Army = BLACK;
+ chessman[p].Type = Queen;
+ }
+ if (c=='k') {
+ chessman[p].Army = BLACK;
+ chessman[p].Type = King;
+ }
+ if (c=='p') {
+ chessman[p].Army = BLACK;
+ chessman[p].Type = Pawn;
+ }
+ if (c=='n') {
+ chessman[p].Army = BLACK;
+ chessman[p].Type = Knight;
+ }
+ if (c=='b') {
+ chessman[p].Army = BLACK;
+ chessman[p].Type = Bishop;
+ }
+ //black pieces
+ if (c == 'R') {
+ chessman[p].Army = WHITE;
+ chessman[p].Type = Rook;
+
+ }
+ if (c=='Q') {
+ chessman[p].Army = WHITE;
+ chessman[p].Type = Queen;
+ }
+ if (c=='K') {
+ chessman[p].Army = WHITE;
+ chessman[p].Type = King;
+ }
+ if (c=='P') {
+ chessman[p].Army = WHITE;
+ chessman[p].Type = Pawn;
+ }
+ if (c=='N') {
+ chessman[p].Army = WHITE;
+ chessman[p].Type = Knight;
+ }
+ if (c=='B') {
+ chessman[p].Army = WHITE;
+ chessman[p].Type = Bishop;
+ }
+ chessman[p].Rank = r;
+ chessman[p].File = f;
+ current[ Pointer( chessman[p].File, chessman[p].Rank ) ].ManPtr = p;
+ p--;
+ f++;
+ }
+ if (c.isNumber()) {
+ //describing blank squares
+
+ p = p - c.digitValue();
+ f = f + c.digitValue();
+ }
+
+ if (c == '/') {
+ //describing new rank
+ r--;
+ f=0;
+ }
+
+ }
+
+ do {
+ j++;
+ c = fen[j];
+ } while (c == '/' || c == ' ');
+ if (c=='w')
+ OnMove = WHITE;
+ if (c=='b')
+ OnMove = BLACK;
+
+}
+///////////////////////////////////////
+//
+// logic::Move
+//
+///////////////////////////////////////
+bool logic::Move( void )
+{
+ dlg_promote *ProDlg;
+ int tmp;
+ int fromPtr, toPtr, manPtr;
+
+ fromPtr = Pointer( chessMove.fromFile, chessMove.fromRank );
+ toPtr = Pointer( chessMove.toFile, chessMove.toRank );
+ if( ( fromPtr == Null ) || ( toPtr == Null ) )
+ return FALSE;
+ manPtr = current[fromPtr].ManPtr;
+ if( manPtr == Null )
+ return FALSE;
+
+ HashLegal( manPtr );
+ /* Only proceed if this is a move */
+ if( current[toPtr].Note < NOTE_MOVE )
+ return FALSE; // This depends on all moves being higher value than NOTE_MOVE,
+ // while all non-moves are less.
+
+ /* Take care of moving the rook in a caste */
+ if( current[toPtr].Note == NOTE_CASTLE )
+ {
+ if( chessMove.toFile == 6 )
+ {
+ for( tmp = 0; tmp < 64; tmp++ )
+ {
+ if( ( chessman[tmp].Army == chessman[manPtr].Army ) &&
+ ( chessman[tmp].Type == Rook ) &&
+ ( chessman[tmp].File == 7 ) )
+ {
+ chessman[tmp].File = 5;
+ current[ Pointer( 7, ( 7 * ( chessman[tmp].Army == BLACK ) ) ) ].ManPtr = Null;
+ current[ Pointer( 5, ( 7 * ( chessman[tmp].Army == BLACK ) ) ) ].ManPtr = tmp;
+ break;
+ }
+ }
+ }
+ if( chessMove.toFile == 2 )
+ {
+ for( tmp = 0; tmp < 64; tmp++ )
+ {
+ if( ( chessman[tmp].Army == chessman[manPtr].Army ) &&
+ ( chessman[tmp].Type == Rook ) &&
+ ( chessman[tmp].File == 0 ) )
+ {
+ chessman[tmp].File = 3;
+ current[ Pointer( 0, ( 7 * ( chessman[tmp].Army == BLACK ) ) ) ].ManPtr = Null;
+ current[ Pointer( 3, ( 7 * ( chessman[tmp].Army == BLACK ) ) ) ].ManPtr = tmp;
+ break;
+ }
+ }
+ }
+ }
+ /* Handle the 50 Move Rule */
+ MoveCounter++;
+ if( chessman[manPtr].Type == Pawn ) MoveCounter = 0;
+ if( current[ toPtr ].ManPtr != Null )
+ {
+ MoveCounter = 0;
+ chessMove.ManTaken = current[ toPtr ].ManPtr;
+ }
+ /* Check for Pawn Promotion */
+ if( ( chessMove.toRank == ( 7 * ( chessman[manPtr].Army == WHITE ) ) ) &&
+ ( chessman[manPtr].Type == Pawn ) )
+ {
+ if( ( ( OnMove == WHITE ) && ( Param->type(WHITE) == PLAYERLOCAL ) ) ||
+ ( ( OnMove == BLACK ) && ( Param->type(BLACK) == PLAYERLOCAL ) ) )
+ {
+ if( Resource->OPTION_Auto_Queen == TRUE ) chessMove.Promote = 'q';
+ else
+ {
+ /* Prompt user for promotion */
+ ProDlg = new dlg_promote( 0, "promotedialog", Resource );
+ ProDlg->Init( OnMove );
+ chessMove.Promote = ProDlg->exec();
+ delete ProDlg;
+ /* Default to Queen if the user quit the dialog without choosing */
+ if( ( chessMove.Promote != 'q' ) &&
+ ( chessMove.Promote != 'b' ) &&
+ ( chessMove.Promote != 'n' ) &&
+ ( chessMove.Promote != 'r' ) ) chessMove.Promote = 'q';
+ }
+ }
+ }
+ /* Write CAN & SAN Notation for this move */
+ writeCAN();
+ writeSAN();
+ /* Make the move */
+ chessman[manPtr].File = chessMove.toFile;
+ chessman[manPtr].Rank = chessMove.toRank;
+ current[fromPtr].ManPtr = Null;
+ current[toPtr].ManPtr = manPtr;
+ /* Remove pawns taken en passant */
+ if( current[toPtr].Note == NOTE_ENPASSANT )
+ {
+ MoveCounter = 0;
+ chessMove.ManTaken = current[ enPassant[ 1 - chessman[manPtr].Army ] ].ManPtr;
+ current[ enPassant[ 1 - chessman[manPtr].Army ] ].ManPtr = Null;
+ }
+ /* Take care of en passant data */
+ if( current[toPtr].Note == NOTE_PAWN_DOUBLE )
+ enPassant[ chessman[manPtr].Army ] = toPtr;
+ enPassant[ 1 - chessman[manPtr].Army ] = Null;
+ /* Handle castle flags */
+ if( chessman[manPtr].Type == King )
+ CastleFlag[ chessman[manPtr].Army ] = 0;
+ if( ( chessman[manPtr].Type == Rook ) && ( chessMove.fromFile == 0 ) )
+ CastleFlag[ chessman[manPtr].Army ] -= CF_RookQ;
+ if( ( chessman[manPtr].Type == Rook ) && ( chessMove.fromFile == 7 ) )
+ CastleFlag[ chessman[manPtr].Army ] -= CF_RookK;
+ return TRUE;
+}
+///////////////////////////////////////
+//
+// logic::HashLegal
+//
+///////////////////////////////////////
+void logic::HashLegal( const char Man, const bool Recursion )
+{
+ char tmp;
+ tmp = ManPtr;
+ ManPtr = Man;
+ _HashLegal( Recursion );
+ ManPtr = tmp;
+}
+void logic::_HashLegal( const bool Recursion )
+{
+ /* Used for loops and positions */
+ register int Ptr(0), tmp(0), tmp2(0);
+
+ /* Used to calculate a position relative to a given position */
+ int dirF(0), dirR(0);
+
+ /* Used to monitor the King inside the Monster */
+ int currentKing(0), _castleFlag(0);
+
+ if( !isChessman(ManPtr) )
+ return;
+
+ copyPositions( current, hash );
+
+ while( tmp < 64 )
+ hash[tmp++].Note = NOTE_NONE;
+
+ switch( chessman[ManPtr].Type )
+ {
+ /* ROOK & QUEEN */
+ case Rook:
+ case Queen:
+ /* Positive Rank Movement */
+ for( tmp = 1; tmp < 8; tmp++ )
+ {
+ Ptr = CalcPointer( 0, tmp );
+ if( Ptr == Null ) break;
+ if( hash[Ptr].ManPtr == Null )
+ {
+ hash[Ptr].Note = NOTE_MOVE;
+ continue;
+ }
+ if( chessman[hash[Ptr].ManPtr].Army != chessman[ManPtr].Army )
+ {
+ hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ if( Recursion == TRUE ) hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ /* Negitive Rank Movement */
+ for( tmp = -1; tmp > -8; tmp-- )
+ {
+ Ptr = CalcPointer( 0, tmp );
+ if( Ptr == Null ) break;
+ if( hash[Ptr].ManPtr == Null )
+ {
+ hash[Ptr].Note = NOTE_MOVE;
+ continue;
+ }
+ if( chessman[hash[Ptr].ManPtr].Army != chessman[ManPtr].Army )
+ {
+ hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ if( Recursion == TRUE ) hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ /* Positive File Movement */
+ for( tmp = 1; tmp < 8; tmp++ )
+ {
+ Ptr = CalcPointer( tmp, 0 );
+ if( Ptr == Null ) break;
+ if( hash[Ptr].ManPtr == Null )
+ {
+ hash[Ptr].Note = NOTE_MOVE;
+ continue;
+ }
+ if( chessman[hash[Ptr].ManPtr].Army != chessman[ManPtr].Army )
+ {
+ hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ if( Recursion == TRUE ) hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ /* Negative File Movement */
+ for( tmp = -1; tmp > -8; tmp-- )
+ {
+ Ptr = CalcPointer( tmp, 0 );
+ if( Ptr == Null ) break;
+ if( hash[Ptr].ManPtr == Null )
+ {
+ hash[Ptr].Note = NOTE_MOVE;
+ continue;
+ }
+ if( chessman[hash[Ptr].ManPtr].Army != chessman[ManPtr].Army )
+ {
+ hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ if( Recursion == TRUE ) hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ if( chessman[ManPtr].Type == Rook ) break;
+ /* Bishop & Queen */
+ case Bishop:
+ /* NE Movement */
+ for( tmp = 1; tmp < 8; tmp++ )
+ {
+ Ptr = CalcPointer( tmp, tmp );
+ if( Ptr == Null ) break;
+ if( hash[Ptr].ManPtr == Null )
+ {
+ hash[Ptr].Note = NOTE_MOVE;
+ continue;
+ }
+ if( chessman[hash[Ptr].ManPtr].Army != chessman[ManPtr].Army )
+ {
+ hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ if( Recursion == TRUE ) hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ /* NW Movement */
+ for( tmp = -1; tmp > -8; tmp-- )
+ {
+ Ptr = CalcPointer( tmp, abs(tmp) );
+ if( Ptr == Null ) break;
+ if( hash[Ptr].ManPtr == Null )
+ {
+ hash[Ptr].Note = NOTE_MOVE;
+ continue;
+ }
+ if( chessman[hash[Ptr].ManPtr].Army != chessman[ManPtr].Army )
+ {
+ hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ if( Recursion == TRUE ) hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ /* SW Movement */
+ for( tmp = -1; tmp > -8; tmp-- )
+ {
+ Ptr = CalcPointer( tmp, tmp );
+ if( Ptr == Null ) break;
+ if( hash[Ptr].ManPtr == Null )
+ {
+ hash[Ptr].Note = NOTE_MOVE;
+ continue;
+ }
+ if( chessman[hash[Ptr].ManPtr].Army != chessman[ManPtr].Army )
+ {
+ hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ if( Recursion == TRUE ) hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ /* SE Movement */
+ for( tmp = -1; tmp > -8; tmp-- )
+ {
+ Ptr = CalcPointer( abs(tmp), tmp );
+ if( Ptr == Null ) break;
+ if( hash[Ptr].ManPtr == Null )
+ {
+ hash[Ptr].Note = NOTE_MOVE;
+ continue;
+ }
+ if( chessman[hash[Ptr].ManPtr].Army != chessman[ManPtr].Army )
+ {
+ hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ if( Recursion == TRUE ) hash[Ptr].Note = NOTE_ATTACK;
+ break;
+ }
+ break;
+ /* Knight */
+ case Knight:
+ for( tmp = 0; tmp < 8; tmp++ )
+ {
+ switch( tmp )
+ {
+ case 0:
+ Ptr = CalcPointer( -1, 2 );
+ break;
+ case 1:
+ Ptr = CalcPointer( 1, 2 );
+ break;
+ case 2:
+ Ptr = CalcPointer( 2, 1 );
+ break;
+ case 3:
+ Ptr = CalcPointer( 2, -1 );
+ break;
+ case 4:
+ Ptr = CalcPointer( 1, -2 );
+ break;
+ case 5:
+ Ptr = CalcPointer( -1, -2 );
+ break;
+ case 6:
+ Ptr = CalcPointer( -2, -1 );
+ break;
+ case 7:
+ Ptr = CalcPointer( -2, 1 );
+ break;
+ default:
+ break;
+ }
+ if( Ptr != Null )
+ {
+ if( hash[Ptr].ManPtr == Null )
+ hash[Ptr].Note = NOTE_MOVE;
+ else
+ {
+ if( Recursion == TRUE )
+ hash[Ptr].Note = NOTE_ATTACK;
+ if( chessman[hash[Ptr].ManPtr].Army != chessman[ManPtr].Army )
+ hash[Ptr].Note = NOTE_ATTACK;
+ }
+ }
+ }
+ break;
+ /* King */
+ case King:
+ dirF = -1;
+ dirR = 1;
+ while(1)
+ {
+ Ptr = CalcPointer( dirF, dirR );
+ if( Ptr != Null )
+ {
+ if( hash[Ptr].ManPtr == Null ) hash[Ptr].Note = NOTE_MOVE;
+ else
+ {
+ if( Recursion == TRUE ) hash[Ptr].Note = NOTE_ATTACK;
+ if( chessman[hash[Ptr].ManPtr].Army != chessman[ManPtr].Army ) hash[Ptr].Note = NOTE_ATTACK;
+ }
+ }
+ dirF++;
+ if( dirF == 2 )
+ {
+ dirF = -1;
+ dirR--;
+ }
+ if( dirR == -2 ) break;
+ if( ( dirR == 0 ) && ( dirF == 0 ) ) dirF++;
+ }
+ /* Check for castles */
+ if( Recursion == FALSE )
+ {
+ /* Can the King castle at all? */
+ if( CastleFlag[ chessman[ ManPtr ].Army ] & CF_King )
+ {
+ dirR = 0;
+ /* How about with the Queen's Rook? */
+ if( CastleFlag[ chessman[ ManPtr ].Army ] & CF_RookQ )
+ {
+ if( hash[ CalcPointer( -1, dirR ) ].ManPtr == Null )
+ {
+ if( hash[ CalcPointer( -2, dirR ) ].ManPtr == Null )
+ {
+ if( hash[ CalcPointer( -3, dirR ) ].ManPtr == Null )
+ {
+ hash[ CalcPointer( -2, dirR ) ].Note = NOTE_CASTLE;
+ _castleFlag |= CF_RookQ;
+ }
+ }
+ }
+ }
+ /* King's Rook? */
+ if( CastleFlag[ chessman[ ManPtr ].Army ] & CF_RookK )
+ {
+ if( hash[ CalcPointer( 1, dirR ) ].ManPtr == Null )
+ {
+ if( hash[ CalcPointer( 2, dirR ) ].ManPtr == Null )
+ {
+ hash[ CalcPointer( 2, dirR ) ].Note = NOTE_CASTLE;
+ _castleFlag |= CF_RookK;
+ }
+ }
+ }
+ }
+ }
+ break;
+ /* PAWN */
+ default:
+ /* Get direction of movement */
+ if( chessman[ManPtr].Army == WHITE ) dirR = 1;
+ else dirR = -1;
+ if( Recursion == FALSE )
+ {
+ /* Forward 1 square */
+ Ptr = CalcPointer( 0, dirR );
+ if( ( Ptr != Null ) && ( hash[Ptr].ManPtr == Null ) )
+ {
+ hash[Ptr].Note = NOTE_MOVE;
+ tmp = 1 + ( 5 * ( chessman[ManPtr].Army == BLACK ) );
+ if( chessman[ManPtr].Rank == tmp )
+ {
+ /* Forward 2 squares */
+ dirR = dirR << 1;
+ Ptr = CalcPointer( 0, dirR );
+ if( ( Ptr != Null ) && ( hash[Ptr].ManPtr == Null ) ) hash[Ptr].Note = NOTE_PAWN_DOUBLE;
+ dirR = dirR >> 1;
+ }
+ }
+ }
+ if( Recursion == TRUE )
+ {
+ /* Attack Left */
+ Ptr = CalcPointer( -1, dirR );
+ if( Ptr != Null ) hash[Ptr].Note = NOTE_ATTACK;
+ /* Attack Right */
+ Ptr = CalcPointer( 1, dirR );
+ if( Ptr != Null ) hash[Ptr].Note = NOTE_ATTACK;
+ }
+ else
+ {
+ /* Attack Left */
+ Ptr = CalcPointer( -1, dirR );
+ if( ( Ptr != Null ) && ( hash[Ptr].ManPtr != Null ) )
+ {
+ if( chessman[hash[Ptr].ManPtr].Army != chessman[ManPtr].Army ) hash[Ptr].Note = NOTE_ATTACK;
+ }
+ /* Attack Right */
+ Ptr = CalcPointer( 1, dirR );
+ if( ( Ptr != Null ) && ( hash[Ptr].ManPtr != Null ) )
+ {
+ if( chessman[hash[Ptr].ManPtr].Army != chessman[ManPtr].Army ) hash[Ptr].Note = NOTE_ATTACK;
+ }
+ /* Attack en Passant Left */
+ Ptr = CalcPointer( -1, 0 );
+ if( ( Ptr != Null ) && ( enPassant[ 1 - chessman[ManPtr].Army ] == Ptr ) )
+ {
+ Ptr = CalcPointer( -1, dirR );
+ hash[Ptr].Note = NOTE_ENPASSANT;
+ }
+ /* Attack en Passant Right */
+ Ptr = CalcPointer( 1, 0 );
+ if( ( Ptr != Null ) && ( enPassant[ 1 - chessman[ManPtr].Army ] == Ptr ) )
+ {
+ Ptr = CalcPointer( 1, dirR );
+ hash[Ptr].Note = NOTE_ENPASSANT;
+ }
+ }
+ break;
+ }
+ /* THE MONSTER */
+ /* Remove all possible moves that would either put your */
+ /* king into check or wouldn't stop a check in progress */
+ if( Recursion == FALSE )
+ {
+ /* Make Backups */
+ copyPositions( hash, hashBackup );
+ copyChessmen( chessman, chessmanBackup );
+
+ /* Find the King's Position */
+ currentKing = getKing( chessman[ManPtr].Army );
+
+ /* Remove castles under specific conditions */
+ if( _castleFlag )
+ {
+ for( tmp = 0; tmp < 64; tmp++ )
+ {
+ if( !isChessman( tmp ) ) continue;
+ if( ( chessman[tmp].Army != chessman[ManPtr].Army ) && ( chessman[tmp].Type != Null ) )
+ {
+ HashLegal( tmp, TRUE );
+ /* Is a check in progress? */
+ if( hash[ currentKing ].Note == NOTE_ATTACK )
+ {
+ for( tmp2 = 0; tmp2 < 64; tmp2++ )
+ if( hashBackup[tmp2].Note == NOTE_CASTLE ) hashBackup[tmp2].Note = NOTE_NONE;
+ break;
+ }
+ else
+ {
+ /* Store ManPtr in dirF so we can use ManPtr */
+ dirF = ManPtr;
+ ManPtr = hashBackup[ currentKing ].ManPtr;
+ /* Is the path to Queenside in check? */
+ if( _castleFlag & CF_RookQ )
+ {
+ if( ( hash[ CalcPointer( -1, 0 ) ].Note == NOTE_MOVE ) ||
+ ( hash[ CalcPointer( -2, 0 ) ].Note == NOTE_MOVE ) )
+ {
+ hashBackup[ CalcPointer( -2, 0 ) ].Note = NOTE_NONE;
+ _castleFlag -= CF_RookQ;
+ }
+ }
+ /* Is the path to Kingside in check? */
+ if( _castleFlag & CF_RookK )
+ {
+ if( ( hash[ CalcPointer( 1, 0 ) ].Note == NOTE_MOVE ) ||
+ ( hash[ CalcPointer( 2, 0 ) ].Note == NOTE_MOVE ) )
+ {
+ hashBackup[ CalcPointer( 2, 0 ) ].Note = NOTE_NONE;
+ _castleFlag -= CF_RookK;
+ }
+ }
+ /* Restore ManPtr */
+ ManPtr = dirF;
+ }
+ }
+ }
+ } // <- End Castle Checks
+
+ /* Check all possible moves */
+ for( tmp = 0; tmp < 64; tmp++ )
+ {
+ /* Only proceed if this is a move */
+ if( hashBackup[tmp].Note < NOTE_MOVE )
+ continue; // This depends on all moves being higher value than NOTE_MOVE,
+ // while all non-moves are less.
+
+ /* Pretend we moved here... what would happen? */
+ current[ Pointer( chessman[ManPtr].File, chessman[ManPtr].Rank ) ].ManPtr = Null;
+ chessman[ManPtr].File = hashBackup[tmp].File;
+ chessman[ManPtr].Rank = hashBackup[tmp].Rank;
+ current[tmp].ManPtr = ManPtr;
+ if( current[tmp].Note == NOTE_ENPASSANT )
+ {
+ current[ enPassant[ 1 - chessman[ManPtr].Army ] ].ManPtr = Null;
+ }
+
+ /* Recalc King pos, as we may have just moved him */
+ currentKing = getKing( chessman[ManPtr].Army );
+
+ /* Rehash in new position. If King is now under check, then */
+ /* we can't use this move and it's removed from contention */
+ for( tmp2 = 0; tmp2 < 64; tmp2++ )
+ {
+ if( chessman[tmp2].Army != chessman[ManPtr].Army )
+ if( isChessman( tmp2 ) )
+ {
+ HashLegal( tmp2, TRUE );
+ if( hash[ currentKing ].Note == NOTE_ATTACK )
+ {
+ hashBackup[tmp].Note = NOTE_NONE;
+ }
+ }
+ }
+
+ /* Restore the playground */
+ copyPositions( hashBackup, current );
+ copyChessmen( chessmanBackup, chessman );
+ } // <- End of 'Check All Moves' loop
+
+ copyPositions( hashBackup, current );
+ copyPositions( hashBackup, hash );
+ copyChessmen( chessmanBackup, chessman );
+ }
+}