31 static const int Infinity = 32000;
32 static const int KingValue = 10000;
33 static const int QueenValue = 900;
34 static const int RookValue = 500;
35 static const int BishopValue = 300;
36 static const int KnightValue = 300;
37 static const int PawnValue = 100;
46 static const int EndgameValue = 2400;
47 static const int MiddlegameValue = 4000;
51 static const int RookHalfOpenFile = 8;
52 static const int RookOpenFile = 20;
53 static const int RookPasserFile = 25;
54 static const int RookOnSeventh = 25;
55 static const int DoubledRooks = 20;
56 static const int RookEyesKing = 12;
57 static const int KingTrapsRook = 35;
58 static const int DoubledPawn = 8;
59 static const int IsolatedPawn = 16;
60 static const int BackwardPawn = 10;
62 static const int BlockedHomePawn = 15;
63 static const int BishopPair = 25;
64 static const int BishopEyesKing = 12;
65 static const int BishopTrapped = 120;
66 static const int KnightOutpost = 15;
67 static const int KnightBadEndgame = 30;
68 static const int BadPieceTrade = 80;
69 static const int CanCastle = 10;
70 static const int Development = 8;
71 static const int CentralPawnPair = 15;
72 static const int CoverPawn = 12;
73 static const int PassedPawnRank[8] = {
75 0, 10, 15, 25, 50, 80, 120, 0
79 static const int BishopMobility[16] = {
81 -20, -15, -10, -6, -3, 0, 3, 6, 9, 12, 15, 15, 15, 15, 15, 15
83 static const int RookEndgameMobility[16] = {
85 -25, -20, -15, -10, -5, 2, 0, 2, 4, 6, 8, 8, 8, 8, 8, 8
89 static const int KnightKingDist [8] = { 0, 10, 14, 10, 5, 2, 0, 0 };
90 static const int BishopKingDist [8] = { 0, 8, 6, 4, 2, 1, 0, 0 };
91 static const int RookKingDist [8] = { 0, 8, 6, 4, 2, 1, 0, 0 };
92 static const int QueenKingDist [8] = { 0, 15, 12, 9, 6, 3, 0, 0 };
99 static const int LazyEvalMargin = 250;
100 static const int LazyEvalEndingMargin = 400;
101 static const int LazyEvalPawnEndingMargin = 800;
105 static const int NullMoveReduction = 2;
110 static const int AspirationWindow = 35;
116 0, 0, 0, 0, 0, 0, 0, 0,
117 4, 8, 12, 16, 16, 12, 8, 4,
118 4, 8, 12, 16, 16, 12, 8, 4,
119 3, 6, 9, 12, 12, 9, 6, 3,
120 2, 4, 6, 8, 8, 6, 4, 2,
121 1, 2, 3, 4, 4, 3, 2, 1,
122 0, 0, 0, -4, -4, 0, 0, 0,
123 0, 0, 0, 0, 0, 0, 0, 0
133 0, 0, 0, 0, 0, 0, 0, 0,
134 0, 0, 0, 0, 2, 2, 2, 2,
135 0, 0, 0, 0, 4, 2, 2, 2,
136 0, 0, 0, 4, 6, 0, 0, 0,
137 4, 4, 4, 4, 4, -4, -4, -4,
138 8, 8, 8, 0, 0, -8, -8, -8,
139 12, 12, 12, 0, 0, -12, -12, -12,
140 0, 0, 0, 0, 0, 0, 0, 0
146 KnightSquare [64] = {
147 -24, -12, -6, -6, -6, -6, -12, -24,
148 -8, 0, 0, 0, 0, 0, 0, -8,
149 -6, 5, 10, 10, 10, 10, 5, -6,
150 -6, 0, 10, 10, 10, 10, 0, -6,
151 -6, 0, 5, 8, 8, 5, 0, -6,
152 -6, 0, 5, 5, 5, 5, 0, -6,
153 -6, 0, 0, 0, 0, 0, 0, -8,
154 -10, -8, -5, -6, -6, -6, -6, -10
160 BishopSquare [64] = {
161 -10, -5, 0, 0, 0, 0, -5, -10,
162 -5, 8, 0, 5, 5, 0, 8, -5,
163 0, 0, 5, 5, 5, 5, 0, 0,
164 0, 5, 10, 5, 5, 10, 5, 0,
165 0, 5, 10, 5, 5, 10, 5, 0,
166 0, 0, 5, 5, 5, 5, 0, 0,
167 -5, 8, 0, 5, 5, 0, 8, -5,
168 -10, -5, -2, -2, -2, -2, -5, -10
174 RookFile [8] = { 0, 0, 4, 8, 8, 4, 0, 0 };
180 -5, 0, 0, 0, 0, 0, 0, -5,
181 -5, 0, 3, 3, 3, 3, 0, -5,
182 0, 3, 6, 9, 9, 6, 3, 0,
183 0, 3, 9, 12, 12, 9, 3, 0,
184 -5, 3, 9, 12, 12, 9, 3, -5,
185 -5, 3, 6, 9, 9, 6, 3, -5,
186 -5, 0, 3, 3, 3, 3, 0, -5,
187 -10, -5, 0, 0, 0, 0, -5, -10
194 -50, -50, -50, -50, -50, -50, -50, -50,
195 -50, -50, -50, -50, -50, -50, -50, -50,
196 -50, -50, -50, -50, -50, -50, -50, -50,
197 -50, -50, -50, -60, -60, -50, -50, -50,
198 -40, -40, -40, -60, -60, -40, -40, -40,
199 -15, -15, -15, -20, -20, -15, -15, -15,
200 5, 5, 0, 0, 0, 0, 5, 5,
201 20, 20, 15, 5, 5, 5, 20, 20
209 KingEndgameSquare [64] = {
210 -10, -5, 0, 5, 5, 0, -5, -10,
211 -5, 0, 5, 10, 10, 5, 0, -5,
212 0, 5, 10, 15, 15, 10, 5, 0,
213 5, 10, 15, 20, 20, 15, 10, 5,
214 5, 10, 15, 20, 20, 15, 10, 5,
215 0, 5, 10, 15, 15, 10, 5, 0,
216 -5, 0, 5, 10, 10, 5, 0, -5,
217 -10, -5, 0, 5, 5, 0, -5, -10
251 if (color ==
WHITE) {
252 if (rank < RANK_4 || rank >
RANK_6) {
return false; }
262 if (rank < RANK_3 || rank >
RANK_5) {
return false; }
274 for (
uint i=0; i < squares.
Size(); i++) {
275 if (board[squares.
Get(i)] == enemyPawn) {
return false; }
291 return Score (-Infinity, Infinity);
294 static uint nScoreCalls = 0;
295 static uint nScoreFull = 0;
298 Engine::ScoreWhiteMaterial (
void)
301 return pieceCount[
WQ] * QueenValue + pieceCount[
WR] * RookValue
302 + pieceCount[
WB] * BishopValue + pieceCount[
WN] * KnightValue
303 + pieceCount[
WP] * PawnValue;
307 Engine::ScoreBlackMaterial (
void)
310 return pieceCount[
BQ] * QueenValue + pieceCount[
BR] * RookValue
311 + pieceCount[
BB] * BishopValue + pieceCount[
BN] * KnightValue
312 + pieceCount[
BP] * PawnValue;
318 int score = ScoreWhiteMaterial() - ScoreBlackMaterial();
336 int materialScore[2] = {0, 0};
337 int allscore[2] = {0, 0};
338 int endscore[2] = {0, 0};
339 int midscore[2] = {0, 0};
340 int nNonPawns[2] = {0, 0};
348 allscore[
WHITE] = materialScore[
WHITE] = ScoreWhiteMaterial();
349 allscore[
BLACK] = materialScore[
BLACK] = ScoreBlackMaterial();
351 int pieceMaterial = (materialScore[
WHITE] - pieceCount[
WP] * PawnValue)
352 + (materialScore[
BLACK] - pieceCount[
BP] * PawnValue);
353 bool inEndgame =
false;
354 bool inMiddlegame =
false;
355 if (pieceMaterial <= EndgameValue) { inEndgame =
true; }
356 if (pieceMaterial >= MiddlegameValue) { inMiddlegame =
true; }
361 if (pieceCount[
WP] > 0 && pieceCount[
BP] > 0) {
362 uint wminors = pieceCount[
WB] + pieceCount[
WN];
363 uint bminors = pieceCount[
BB] + pieceCount[
BN];
364 uint wmajors = pieceCount[
WR] + (2 * pieceCount[
WQ]);
365 uint bmajors = pieceCount[
BR] + (2 * pieceCount[
BQ]);
366 if (wmajors == bmajors) {
367 if (wminors < bminors) { allscore[
WHITE] -= BadPieceTrade; }
368 if (wminors > bminors) { allscore[
BLACK] -= BadPieceTrade; }
369 }
else if (wminors == bminors) {
370 if (wmajors < bmajors) { allscore[
WHITE] -= BadPieceTrade; }
371 if (wmajors > bmajors) { allscore[
BLACK] -= BadPieceTrade; }
376 if (pieceCount[
WB] >= 2) { allscore[
WHITE] += BishopPair; }
377 if (pieceCount[
BB] >= 2) { allscore[
BLACK] += BishopPair; }
381 if (pieceCount[
WP] + pieceCount[
BP] == 0) {
382 int materialDiff = materialScore[
WHITE] - materialScore[
BLACK];
383 if (materialDiff < 0) { materialDiff = -materialDiff; }
384 if (materialDiff == BishopValue || materialDiff == KnightValue) {
385 allscore[
WHITE] /= 4;
386 allscore[
BLACK] /= 4;
392 if (board[
A7] ==
WB && board[
B6] ==
BP) { allscore[
WHITE] -= BishopTrapped; }
393 if (board[
H7] ==
WB && board[
G6] ==
BP) { allscore[
WHITE] -= BishopTrapped; }
396 if (board[
A2] ==
BB && board[
B3] ==
WP) { allscore[
BLACK] -= BishopTrapped; }
397 if (board[
H2] ==
BB && board[
G6] ==
WP) { allscore[
BLACK] -= BishopTrapped; }
405 int lazyMargin = LazyEvalMargin;
406 if (inEndgame) { lazyMargin = LazyEvalEndingMargin; }
407 if (inPawnEndgame) { lazyMargin = LazyEvalPawnEndingMargin; }
409 int fastScore = allscore[
WHITE] - allscore[
BLACK];
410 if (toMove ==
BLACK) { fastScore = -fastScore; }
411 if (fastScore - lazyMargin > beta) {
return fastScore; }
412 if (fastScore + lazyMargin < alpha) {
return fastScore; }
416 ScorePawnStructure (&pawnEntry);
419 if (board[
D2] ==
WP && board[
D3] !=
EMPTY) { allscore[
WHITE] -= BlockedHomePawn; }
420 if (board[
E2] ==
WP && board[
E3] !=
EMPTY) { allscore[
WHITE] -= BlockedHomePawn; }
421 if (board[
D7] ==
BP && board[
D6] !=
EMPTY) { allscore[
BLACK] -= BlockedHomePawn; }
422 if (board[
E7] ==
BP && board[
E6] !=
EMPTY) { allscore[
BLACK] -= BlockedHomePawn; }
426 if (materialScore[
WHITE] > materialScore[
BLACK]) {
427 int bonus = (5 - nNonPawns[
BLACK]) * 5;
428 allscore[
WHITE] += bonus;
429 }
else if (materialScore[BLACK] > materialScore[
WHITE]) {
430 int bonus = (5 - nNonPawns[
WHITE]) * 5;
431 allscore[
BLACK] += bonus;
438 if (toMove == BLACK) { fastScore = -fastScore; }
439 if (fastScore > beta + 200) {
return fastScore; }
440 if (fastScore < alpha - 200) {
return fastScore; }
453 if (wkFyle <= C_FYLE && bkFyle >=
F_FYLE) {
472 for (
uint i = 0; i < npieces; i++) {
492 }
else if (ptype ==
ROOK) {
495 ascore += RookOnSeventh;
497 bool kingOn8th = (p ==
WR) ? (bk >=
A8) : (wk <=
H1);
498 if (kingOn8th) { ascore += RookOnSeventh; }
505 escore += RookEndgameMobility [mobility];
507 }
else if (ptype ==
KING) {
510 ascore += 5 * KingEndgameSquare[bonusSq] - 150;
512 mscore += KingSquare[bonusSq];
513 escore += KingEndgameSquare[bonusSq];
515 }
else if (ptype ==
BISHOP) {
516 ascore += BishopSquare[bonusSq];
526 if ((leftdiff >= -2 && leftdiff <= 2)
527 || (rightdiff >= -2 && rightdiff <= 2)) {
528 mscore += BishopEyesKing;
531 }
else if (ptype ==
KNIGHT) {
532 ascore += KnightSquare[bonusSq];
537 && isOutpost(board, sq, c)) {
538 mscore += KnightOutpost;
551 if (ksidePawns > 0 && qsidePawns > 0) {
552 escore -= KnightBadEndgame;
557 ascore += QueenSquare[bonusSq];
561 allscore[c] += ascore;
562 midscore[c] += mscore;
563 endscore[c] += escore;
567 byte passedPawnFyles =
569 for (
colorT color = WHITE; color <=
BLACK; color++) {
571 if (pieceCount[rook] == 0) {
continue; }
580 if (nRooks == 0) {
continue; }
581 if (nRooks > 1) { bonus += DoubledRooks; }
582 uint passedPawnsOnFyle = passedPawnFyles & (1 << fyle);
583 if (passedPawnsOnFyle != 0) {
586 bonus += RookPasserFile;
587 }
else if (Pos.
FyleCount (ownPawn, fyle) == 0) {
589 if (Pos.
FyleCount (enemyPawn, fyle) == 0) {
590 bonus += RookOpenFile;
592 bonus += RookHalfOpenFile;
596 int fdiff = (int)fyle - (
int)enemyKingFyle;
597 if (fdiff >= -1 && fdiff < 1) { bonus += RookEyesKing; }
600 allscore[
color] += bonus;
605 if (pieceCount[
BQ] > 0) {
609 if (pieceCount[
WQ] > 0) {
616 uint nCoverPawns = 0;
618 if (p ==
WP || p ==
WB) { nCoverPawns++; }
620 if (p ==
WP || p ==
WB) { nCoverPawns++; }
622 if (p ==
WP || p ==
WB) { nCoverPawns++; }
623 midscore[
WHITE] += CoverPawn * nCoverPawns;
624 if ((wk ==
F1 || wk ==
G1)
625 && (board[
G1] ==
WR || board[
H1] ==
WR || board[
H2] ==
WR)) {
626 midscore[
WHITE] -= KingTrapsRook;
628 if ((wk ==
C1 || wk ==
B1)
629 && (board[
B1] ==
WR || board[
A1] ==
WR || board[
A2] ==
WR)) {
630 midscore[
WHITE] -= KingTrapsRook;
634 uint nCoverPawns = 0;
636 if (p ==
BP || p ==
BB) { nCoverPawns++; }
638 if (p ==
BP || p ==
BB) { nCoverPawns++; }
640 if (p ==
BP || p ==
BB) { nCoverPawns++; }
641 midscore[
BLACK] += CoverPawn * nCoverPawns;
642 if ((bk ==
F8 || bk ==
G8)
643 && (board[
G8] ==
BR || board[
H8] ==
BR || board[
H7] ==
BR)) {
644 midscore[
BLACK] -= KingTrapsRook;
646 if ((bk ==
C8 || bk ==
B8)
647 && (board[
B8] ==
BR || board[
A8] ==
BR || board[
A7] ==
BR)) {
648 midscore[
BLACK] -= KingTrapsRook;
653 if ((board[
D4] ==
WP || board[
D5] ==
WP)
654 && (board[
E4] ==
WP || board[
E5] ==
WP)) {
655 midscore[
WHITE] += CentralPawnPair;
657 if ((board[
D4] ==
BP || board[
D5] ==
BP)
658 && (board[
E4] ==
BP || board[
E5] ==
BP)) {
659 midscore[
BLACK] += CentralPawnPair;
663 if (board[
B1] !=
WN) { midscore[
WHITE] += Development; }
664 if (board[
C1] !=
WB) { midscore[
WHITE] += Development; }
665 if (board[
F1] !=
WB) { midscore[
WHITE] += Development; }
666 if (board[
G1] !=
WN) { midscore[
WHITE] += Development; }
667 if (board[
B8] !=
BN) { midscore[
BLACK] += Development; }
668 if (board[
C8] !=
BB) { midscore[
BLACK] += Development; }
669 if (board[
F8] !=
BB) { midscore[
BLACK] += Development; }
670 if (board[
G8] !=
BN) { midscore[
BLACK] += Development; }
675 int baseScore = allscore[
WHITE] - allscore[
BLACK];
676 int mgScore = baseScore + midscore[
WHITE] - midscore[
BLACK];
677 int egScore = baseScore + endscore[
WHITE] - endscore[
BLACK];
678 mgScore += pawnEntry.
score;
679 egScore += (pawnEntry.
score * 5) / 4;
683 if (pieceCount[
WB] == 1 && pieceCount[
BB] == 1) {
685 if (pieceCount[
WQ] == pieceCount[
BQ]
686 && pieceCount[
WR] == pieceCount[
BR]
687 && pieceCount[
WN] == pieceCount[
BN]) {
688 egScore = egScore * 5 / 8;
694 if (toMove == BLACK) {
702 finalScore = mgScore;
703 }
else if (inEndgame) {
704 finalScore = egScore;
707 int midpart = (pieceMaterial - EndgameValue) * mgScore;
708 int endpart = (MiddlegameValue - pieceMaterial) * egScore;
709 finalScore = (endpart + midpart) / (MiddlegameValue - EndgameValue);
714 static uint nPawnHashProbes = 0;
715 static uint nPawnHashHits = 0;
733 pawnEntry->
sig = sig;
742 if (!inPawnEndgame) {
743 uint hashSlot = pawnhash % PawnTableSize;
744 hashEntry = &(PawnTable[hashSlot]);
745 if (pawnhash == hashEntry->
pawnhash && sig == hashEntry->
sig) {
747 *pawnEntry = *hashEntry;
756 uint pawnFiles[2][10] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
757 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
759 uint firstRank[2][10] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
760 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
762 uint lastRank[2][10] = { {7, 7, 7, 7, 7, 7, 7, 7, 7, 7},
763 {7, 7, 7, 7, 7, 7, 7, 7, 7, 7} };
765 int pawnScore[2] = {0, 0};
766 int longVsShortScore[2] = {0, 0};
767 int shortVsLongScore[2] = {0, 0};
780 for (
uint i = 0; i < npawns; i++) {
784 pawnScore[c] += PawnSquare[bonusSq];
785 longVsShortScore[c] += PawnStorm[bonusSq];
789 if (rank > firstRank[c][fyle]) {
790 firstRank[c][fyle] = rank;
792 if (rank < lastRank[c][fyle]) {
793 lastRank[c][fyle] = rank;
798 byte fyleHasPassers[2] = {0, 0};
804 for (
uint fyle=1; fyle <= 8; fyle++) {
806 if (pawnCount == 0) {
continue; }
811 pawnScore[
color] -= DoubledPawn * pawnCount;
815 bool isolated =
false;
816 if (pawnFiles[color][fyle-1] == 0
817 && pawnFiles[color][fyle+1] == 0) {
819 pawnScore[
color] -= IsolatedPawn * pawnCount;
821 if (pawnFiles[enemy][fyle] == 0) {
822 pawnScore[
color] -= IsolatedPawn * pawnCount / 2;
824 }
else if (lastRank[color][fyle-1] > lastRank[color][fyle]
825 && lastRank[color][fyle+1] > lastRank[color][fyle]) {
827 pawnScore[
color] -= BackwardPawn;
829 if (pawnFiles[enemy][fyle] == 0) {
830 pawnScore[
color] -= BackwardPawn;
835 if (pawnRank >= 7 - lastRank[enemy][fyle]
836 && pawnRank >= 7 - lastRank[enemy][fyle-1]
837 && pawnRank >= 7 - lastRank[enemy][fyle+1]) {
838 int bonus = PassedPawnRank[pawnRank];
840 if (fyle == 1 || fyle == 8 || isolated) {
841 bonus = bonus * 3 / 4;
845 if (pawnRank == firstRank[color][fyle-1] + 1
846 || pawnRank == firstRank[color][fyle+1] + 1) {
847 bonus = (bonus * 3) / 2;
850 pawnScore[
color] += bonus;
852 fyleHasPassers[
color] |= (1 << (fyle-1));
856 if (pawnRank >= RANK_6 && pawnFiles[color][fyle-1] > 0
857 && firstRank[color][fyle-1] >= RANK_6) {
867 if (color ==
BLACK) {
873 if (color != Pos.
GetToMove()) { pawnDist++; }
874 if (pawnDist < kingDist) {
875 bestRacingPawn[
color] = pawnRank;
882 int score = pawnScore[
WHITE] - pawnScore[
BLACK];
883 pawnEntry->
score = score;
890 if (!inPawnEndgame) {
891 *hashEntry = *pawnEntry;
901 if (bestRacingPawn[
WHITE] > bestRacingPawn[
BLACK] + 1) {
902 pawnEntry->
score += RookValue;
903 }
else if (bestRacingPawn[
BLACK] > bestRacingPawn[
WHITE] + 1) {
904 pawnEntry->
score -= RookValue;
912 Engine::IsMatingScore (
int score)
921 Engine::IsGettingMatedScore (
int score)
931 PushRepeat(&RootPos);
940 GameMoves[NumGameMoves] = newMove;
952 if (NumGameMoves == 0) {
return; }
958 my_Tcl_Free((
char *)GameMoves);
960 delete GameMoves[NumGameMoves];
991 repeatT * rep = &(RepStack[RepStackSize]);
1003 Engine::PopRepeat (
void)
1005 ASSERT (RepStackSize > 0);
1019 if (npieces <= 2) {
return true; }
1022 if (material[
WB] == 1 || material[
WN] == 1) {
return true; }
1023 if (material[
BB] == 1 || material[
BN] == 1) {
return true; }
1035 if (RepStackSize < 100) {
return false; }
1042 for (
uint i = RepStackSize; i > 0; i--) {
1043 repeatT * rep = &(RepStack[i-1]);
1045 if (npieces != rep->
npieces) {
break; }
1046 if (pawnhash != rep->
pawnhash) {
break; }
1049 if (plycount >= 100) {
return true; }
1068 for (
uint i = RepStackSize; i > 0; i--) {
1069 repeatT * rep = &(RepStack[i-1]);
1071 if (npieces != rep->
npieces) {
break; }
1072 if (pawnhash != rep->
pawnhash) {
break; }
1074 if (hash == rep->
hash && stm == rep->
stm) { ntimes++; }
1086 uint bytes = size * 1024;
1090 if ((TranTableSize % 2) == 1) { TranTableSize--; }
1092 if (TranTable != NULL) { my_Tcl_Free((
char *) TranTable); }
1095 if (TranTable != NULL) {
delete[] TranTable; }
1109 uint bytes = size * 1024;
1114 if (PawnTable != NULL) { my_Tcl_Free((
char *) PawnTable); }
1117 if (PawnTable != NULL) {
delete[] PawnTable; }
1130 for (
uint i = 0; i < TranTableSize; i++) {
1142 for (
uint i = 0; i < PawnTableSize; i++) {
1153 { tte->
flags = (castling << 4) | (stm << 3) | (isOnlyMove ? 4 : 0) | sflag; }
1156 {
return (tte->
flags & 7); }
1159 {
return ((tte->
flags >> 3) & 1); }
1162 {
return (tte->
flags >> 4); }
1165 {
return (((tte->
flags >> 2) & 1) == 1); }
1171 bm <<= 6; bm |= bestMove->
to;
1172 bm <<= 4; bm |= bestMove->
promote;
1179 bestMove->
promote = bm & 15; bm >>= 4;
1180 bestMove->
to = bm & 63; bm >>= 6;
1181 bestMove->
from = bm & 63;
1188 Engine::StoreHash (
int depth,
scoreFlagT ttFlag,
int score,
1191 if (TranTableSize == 0) {
return; }
1197 if (stm ==
BLACK) { hash = ~hash; }
1203 uint ttSlot = (hash % TranTableSize) & 0xFFFFFFFEU;
1204 ASSERT (ttSlot < TranTableSize - 1);
1207 bool replacingSameEntry =
false;
1210 if (ttEntry1->
hash == hash && ttEntry1->
pawnhash == pawnhash) {
1212 replacingSameEntry =
true;
1213 }
else if (ttEntry2->
hash == hash && ttEntry2->
pawnhash == pawnhash) {
1215 replacingSameEntry =
true;
1226 ttDeeper = ttEntry2;
1227 ttShallower = ttEntry1;
1229 if (ttShallower->
sequence != TranTableSequence) {
1230 ttEntry = ttShallower;
1231 }
else if (ttDeeper->
sequence != TranTableSequence) {
1234 ttEntry = ttShallower;
1238 if (replacingSameEntry) {
1239 if (depth < ttEntry->depth) {
1242 if (ttEntry->
bestMove == 0 && bestMove != NULL) {
1247 if (depth == ttEntry->
depth) {
1257 if (IsMatingScore(score)) { score += Ply; }
1258 if (IsGettingMatedScore(score)) { score -= Ply; }
1261 ttEntry->
hash = hash;
1263 ttEntry->
depth = depth;
1264 ttEntry->
score = score;
1266 ttEntry->
sequence = TranTableSequence;
1268 if (bestMove != NULL) {
1282 Engine::ProbeHash (
int depth,
int * score,
simpleMoveT * bestMove,
bool * isOnlyMove)
1287 if (TranTableSize == 0) {
return SCORE_NONE; }
1291 if (stm ==
BLACK) { hash = ~hash; }
1294 uint ttSlot = (hash % TranTableSize) & 0xFFFFFFFEU;
1295 ASSERT (ttSlot+1 < TranTableSize);
1297 if (ttEntry->
hash != hash) { ttEntry++; }
1308 if (bestMove != NULL && ttEntry->
bestMove != 0) {
1313 if (isOnlyMove != NULL) {
1319 if (score != NULL) {
1320 *score = ttEntry->
score;
1322 if (IsMatingScore(*score)) { *score -= Ply; }
1323 if (IsGettingMatedScore(*score)) { *score += Ply; }
1328 static uint nFailHigh = 0;
1329 static uint nFailHighFirstMove = 0;
1339 for (
uint i=0; i < NumGameMoves; i++) {
1341 my_Tcl_Free((
char *) GameMoves[i]);
1343 delete GameMoves[i];
1349 if (newpos == NULL) {
1365 TranTableSequence++;
1385 IsOutOfTime =
false;
1392 ClearHistoryValues();
1396 if (mlist == NULL) {
1397 mlist = &tmpMoveList;
1402 if (mlist->
Size() == 0) {
1408 for (
uint i=0; i < mlist->
Size(); i++) {
1411 sm->
score = -Quiesce (-Infinity, Infinity);
1418 if (mlist->
Size() > 1) {
1420 if (margin > (2 * PawnValue)) {
1426 int bestScore = -Infinity;
1430 for (
uint depth = 1; depth <= MaxDepth; depth++) {
1438 if (depth > MinDepthCheckTime) {
1439 double used = (double)Elapsed.
MilliSecs() / (double)SearchTime;
1440 if (used > 0.7) {
break; }
1446 int alpha = -Infinity - 1;
1447 int beta = Infinity + 1;
1449 alpha = bestScore - AspirationWindow;
1450 beta = bestScore + AspirationWindow;
1453 int score = SearchRoot (depth, alpha, beta, mlist);
1454 if (OutOfTime()) {
break; }
1455 if (score >= beta) {
1457 PrintPV (depth, score,
"++");
1459 beta = Infinity + 1;
1460 score = SearchRoot (depth, alpha, beta, mlist);
1461 }
else if (score <= alpha) {
1463 PrintPV (depth, score,
"--");
1466 alpha = -Infinity - 1;
1468 score = SearchRoot (depth, alpha, beta, mlist);
1470 if (OutOfTime()) {
break; }
1473 if (score < alpha || score > beta) {
1478 score = SearchRoot (depth, alpha, beta, mlist);
1481 if (OutOfTime()) {
break; }
1483 PrintPV (depth, bestScore,
">>>");
1486 if (mlist->
Size() <= depth || (depth >= 5 && IsMatingScore(bestScore))) {
break; }
1500 Engine::SearchRoot (
int depth,
int alpha,
int beta,
MoveList * mlist)
1506 if (mlist == NULL) {
1507 mlist = &tmpMoveList;
1513 if (mlist->
Size() == 0) {
1517 bool isOnlyMove = (mlist->
Size() == 1);
1518 int bestScore = -Infinity - 1;
1520 for (
uint movenum=0; movenum < mlist->
Size(); movenum++) {
1522 uint oldNodeCount = NodeCount;
1530 score = -Search (depth - 1, -beta, -alpha,
true);
1535 score = -Search (depth - 1, -alpha - 1, -alpha,
true);
1536 if (score > alpha && score < beta) {
1539 score = -Search (depth - 1, -beta, -score,
true);
1543 int score = -Search (depth - 1, -beta, -alpha,
true);
1546 if (OutOfTime()) {
break; }
1551 sm->
score = NodeCount - oldNodeCount;
1556 if (movenum == 0 || score > bestScore) {
1560 PrintPV (depth, bestScore);
1561 StoreHash (depth,
SCORE_EXACT, score, sm, isOnlyMove);
1562 std::rotate(mlist->
begin(), mlist->
begin() + movenum,
1563 mlist->
begin() + movenum + 1);
1564 if (movenum > 0) { EasyMove =
false; }
1575 Engine::Search (
int depth,
int alpha,
int beta,
bool tryNullMove)
1580 if (depth <= 0) {
return Quiesce (alpha, beta); }
1589 if (repeats >= 3 || (repeats == 2 && Ply > 2)) {
return 0; }
1595 if (OutOfTime()) {
return alpha; }
1606 if (rscore >= beta) {
return rscore; }
1607 if (rscore < alpha) { alpha = rscore; }
1609 if (rscore <= alpha) {
return rscore; }
1610 if (rscore > beta) { beta = rscore; }
1615 int hashscore = alpha;
1617 bool isOnlyMove = 0;
1618 scoreFlagT hashflag = ProbeHash (depth, &hashscore, &hashmove, &isOnlyMove);
1624 if (hashscore >= beta) {
return hashscore; }
1625 if (hashscore > alpha) { alpha = hashscore; }
1628 if (hashscore <= alpha) {
return hashscore; }
1629 if (hashscore < beta) { beta = hashscore; }
1632 if (hashscore > alpha && hashscore < beta) {
1633 UpdatePV (&hashmove);
1638 int baseExtensions = 0;
1639 bool inCheck = InCheck[Ply];
1651 if (inCheck || depth < 2 || Pos.
NumNonPawns(toMove) < 3) {
1652 tryNullMove =
false;
1663 int nulldepth = depth - NullMoveReduction;
1667 int nullscore = -Search (nulldepth - 1, -beta, -beta + 1,
false);
1673 if (nullscore >= beta) {
1680 if (IsGettingMatedScore (nullscore)) { baseExtensions++; }
1684 if (inCheck) { baseExtensions++; }
1702 gotHashMove =
false;
1704 ScoreMoves (&mlist);
1705 isOnlyMove = (mlist.
Size() == 1);
1709 if (isOnlyMove) { baseExtensions++; }
1712 int oldAlpha = alpha;
1713 int bestMoveIndex = -1;
1716 for (
uint movenum = 0; movenum < mlist.
Size(); movenum++) {
1719 std::iter_swap(mlist.
begin() + movenum, sm);
1722 int extensions = baseExtensions;
1727 if (rank <= RANK_2 || rank >=
RANK_7) { extensions++; }
1731 if (extensions > 0 && (
int)Ply >= depth + depth) { extensions /= 2; }
1734 if (extensions > 1 ) { extensions = 1; }
1750 if (Pruning && extensions == 0 && Ply > 2 && depth <= 2
1751 && !InCheck[Ply] && !IsMatingScore (alpha) && !isOnlyMove
1754 bool futile =
false;
1757 futile = ((mscore + (PawnValue * 2)) < alpha);
1758 }
else if (depth == 2) {
1760 futile = ((mscore + RookValue) < alpha);
1775 score = -Search (depth + extensions - 1, -beta, -alpha,
true);
1777 score = -Search (depth + extensions - 1, -alpha - 1, -alpha,
true);
1778 if (score > alpha && score < beta) {
1781 score = -Search (depth + extensions - 1, -beta, -score,
true);
1786 int score = -Search (depth + extensions - 1, -beta, -alpha,
true);
1793 if (score >= beta) {
1794 IncHistoryValue (sm, depth * depth);
1796 StoreHash (depth,
SCORE_LOWER, score, sm, isOnlyMove);
1799 if (movenum == 0) { nFailHighFirstMove++; }
1806 if (score > alpha) {
1808 bestMoveIndex = movenum;
1818 if (movenum == 0 && gotHashMove && !isOnlyMove) {
1821 ScoreMoves (&mlist);
1823 if (hm != mlist.
end()) {
1824 std::iter_swap(mlist.
begin(), hm);
1828 Output (
"# Yikes! Hash table move not in move list! Bug?\n");
1833 if (mlist.
Size() == 0) {
1835 return (InCheck[Ply] ? (-Infinity + Ply) : 0);
1842 if (alpha == oldAlpha) {
1843 ASSERT (bestMoveIndex < 0);
1844 StoreHash (depth,
SCORE_UPPER, alpha, NULL, isOnlyMove);
1847 ASSERT (bestMoveIndex >= 0);
1849 IncHistoryValue (bestMove, depth * depth);
1853 AddKillerMove (bestMove);
1854 StoreHash (depth,
SCORE_EXACT, alpha, bestMove, isOnlyMove);
1864 Engine::Quiesce (
int alpha,
int beta)
1874 if (OutOfTime()) {
return alpha; }
1885 if (rscore >= beta) {
return rscore; }
1886 if (rscore < alpha) { alpha = rscore; }
1888 if (rscore <= alpha) {
return rscore; }
1889 if (rscore > beta) { beta = rscore; }
1895 int staticScore =
Score (alpha, beta);
1896 if (staticScore >= beta) {
return beta; }
1897 if (staticScore > alpha) { alpha = staticScore; }
1901 int margin = PawnValue;
1902 if (staticScore + QueenValue + margin < alpha) {
return alpha; }
1907 for (
uint m=0; m < mlist.
Size(); m++) {
1915 for (
uint i = 0; i < mlist.
Size(); i++) {
1918 std::iter_swap(mlist.
begin() + i, sm);
1922 if (promote !=
EMPTY && promote !=
QUEEN) {
continue; }
1926 if (sm->
score < 0) {
break; }
1927 if ((sm->
score + staticScore + margin) < alpha) {
break; }
1931 int score = -Quiesce (-beta, -alpha);
1935 if (score >= beta) {
return score; }
1938 if (score > alpha) {
1961 #define SEE_ADD(c,sq) attackers[(c)].Add(sq) 1967 if (mover ==
KING) {
return PieceValue(board[target]); }
1970 int fastResult = PieceValue(board[target]) - PieceValue(mover);
1975 if (fastResult > KnightValue && mover !=
ROOK) {
return fastResult; }
1979 if (board[pawnSq] ==
WP && pawnSq != from) {
SEE_ADD (
WHITE, pawnSq); }
1981 if (board[pawnSq] ==
WP && pawnSq != from) {
SEE_ADD (
WHITE, pawnSq); }
1983 if (board[pawnSq] ==
BP && pawnSq != from) {
SEE_ADD (
BLACK, pawnSq); }
1985 if (board[pawnSq] ==
BP && pawnSq != from) {
SEE_ADD (
BLACK, pawnSq); }
1989 if (fastResult < -PawnValue && attackers[
color_Flip(stm)].Size() > 0) {
1998 if (nEligibleKnights > 0) {
2006 if (dest == from) {
continue; }
2009 if (fastResult < -KnightValue && knightColor != stm) {
2010 return fastResult + KnightValue / 2;
2054 if (rankCount > 0) {
2055 sliderDir[nDirs++] =
LEFT;
2056 sliderDir[nDirs++] =
RIGHT;
2058 if (fyleCount > 0) {
2059 sliderDir[nDirs++] =
UP;
2060 sliderDir[nDirs++] =
DOWN;
2062 if (upLeftCount > 0) {
2066 if (upRightCount > 0) {
2073 for (
uint dirIndex = 0; dirIndex < nDirs; dirIndex++) {
2080 while (dest != last) {
2084 if (p ==
EMPTY) {
continue; }
2085 if (dest == from) {
continue; }
2087 if (ptype ==
PAWN) {
2089 if (distance != 1) {
break; }
2103 if (fastResult < -BishopValue && ptype ==
BISHOP) {
2104 if (c != stm) {
return fastResult + BishopValue / 2; }
2105 }
else if (fastResult < -RookValue && ptype ==
ROOK) {
2106 if (c != stm) {
return fastResult + RookValue / 2; }
2118 if (wk != from && bk != from) {
2121 if (wkAttacks && !bkAttacks) {
2123 }
else if (bkAttacks && !wkAttacks) {
2131 bool targetIsPromoSquare = (target <= H1 || target >=
A8);
2134 swaplist[0] = PieceValue (board[target]);
2135 int attackedVal = PieceValue (mover);
2138 if (targetIsPromoSquare && attackedVal == PawnValue) {
2139 swaplist[0] += QueenValue - PawnValue;
2140 attackedVal = QueenValue;
2149 uint attackCount = attackList->
Size();
2152 if (attackCount == 0) {
break; }
2157 int attackValue = PieceValue(board[attackSquare]);
2158 for (
uint i = 1; i < attackCount; i++) {
2159 if (attackValue == PawnValue) {
break; }
2161 int newValue = PieceValue(board[newSquare]);
2162 if (newValue < attackValue) {
2163 attackSquare = newSquare;
2164 attackValue = newValue;
2171 swaplist[nswaps] = -swaplist[nswaps-1] + attackedVal;
2173 attackedVal = attackValue;
2176 if (targetIsPromoSquare && attackValue == PawnValue) {
2177 swaplist[nswaps-1] += QueenValue - PawnValue;
2178 attackedVal = QueenValue;
2182 attackList->
Remove(bestIndex);
2192 while (dest != last) {
2195 if (p ==
EMPTY) {
continue; }
2210 while (nswaps > 0) {
2211 uint prev = nswaps - 1;
2212 if (swaplist[nswaps] > -swaplist[prev]) {
2213 swaplist[prev] = -swaplist[nswaps];
2233 Engine::ScoreMoves (
MoveList * mlist)
2235 for (
uint i = 0; i < mlist->
Size(); i++) {
2238 int see = SEE (sm->
from, sm->
to);
2246 sm->
score = GetHistoryValue (sm);
2247 if (IsKillerMove (sm)) {
2259 Engine::Output (
const char * format, ...)
2262 va_start (ap, format);
2263 vprintf (format, ap);
2264 if (LogFile != NULL) {
2265 vfprintf (LogFile, format, ap);
2273 Engine::PrintPV (
uint depth,
int score,
const char * note)
2275 if (! PostInfo) {
return; }
2277 if (XBoardMode && ms < 50 && Ply < 6) {
return; }
2280 Output (
" %2u %6d %5u %9u ", depth, score, ms / 10, NodeCount);
2282 Output (
" %2u %-3s %+6d %5u %9u ", depth, note, score, ms, NodeCount);
2293 for (i = 0; i < pv->
length; i++) {
2299 Output (
" <illegal>");
2302 if (i > 0) { Output (
" "); }
2313 for (; i > 0; i--) {
2323 Engine::OutOfTime ()
2325 if (IsOutOfTime) {
return true; }
2328 if ((NodeCount & 1023) != 0) {
return false; }
2333 IsOutOfTime = (ms > MinSearchTime);
2334 }
else if (HardMove) {
2335 IsOutOfTime = (ms > MaxSearchTime);
2337 IsOutOfTime = (ms > SearchTime);
2340 if (!IsOutOfTime && CallbackFunction != NULL) {
2341 IsOutOfTime = CallbackFunction (
this, CallbackData);
2353 if (depth <= 0) {
return 1; }
2357 for (
uint i = 0; i < mlist.
Size(); i++) {
squareT square_FlipRank(squareT sq)
uint square_Distance(squareT from, squareT to)
long long MilliSecs(void) const
pieceT piece_Type(pieceT p)
void MakeSANString(simpleMoveT *sm, char *s, sanFlagT flag)
int Recognize(Position *pos)
colorT square_Color(squareT sq)
simpleMoveT * Get(size_t index)
const squareT NULL_SQUARE
uint FyleCount(pieceT p, fyleT f) const
constexpr squareT square_Move(squareT sq, directionT dir)
squareT GetEPTarget() const
uint RightDiagCount(pieceT p, rightDiagT diag)
void ClearHashTable(void)
squareT GetKingSquare(colorT c)
void tte_SetBestMove(transTableEntryT *tte, simpleMoveT *bestMove)
const uint ENGINE_MAX_PLY
const scoreFlagT SCORE_LOWER
int Think(MoveList *mlist)
bool tte_IsOnlyMove(transTableEntryT *tte)
void DoSimpleMove(simpleMoveT *sm)
const int ENGINE_MAX_HISTORY
rankT square_Rank(squareT sq)
constexpr uint MaxPieces()
bool IsLegalMove(simpleMoveT *sm)
const squareT * GetList(colorT c) const
colorT color_Flip(colorT c)
void CopyFrom(Position *src)
uint NumNonPawns(colorT c)
scoreFlagT recogFlag(int value)
void SetPosition(Position *pos)
byte PieceCount(pieceT p)
squareT square_Make(fyleT f, rankT r)
int find(const char *filename)
find() - search for a database.
simpleMoveT move[ENGINE_MAX_PLY]
uint GetSquares(pieceT p, SquareList *sqlist)
const directionT UP_RIGHT
const pieceT * GetBoard() const
const int ENGINE_HASH_SCORE
void UndoSimpleMove(simpleMoveT *sm)
ushort GetFullMoveCount() const
void tte_GetBestMove(transTableEntryT *tte, simpleMoveT *bestMove)
uint RepeatedPosition(void)
int direction_Delta(directionT dir)
uint LeftDiagCount(pieceT p, leftDiagT diag)
rightDiagT square_RightDiag(squareT sq)
squareT square_FlipFyle(squareT sq)
void tte_SetFlags(transTableEntryT *tte, scoreFlagT sflag, colorT stm, byte castling, bool isOnlyMove)
bool NoMatingMaterial(void)
void PlayMove(simpleMoveT *move)
scoreFlagT tte_ScoreFlag(transTableEntryT *tte)
void GenerateMoves(MoveList *mlist, pieceT mask, genMovesT genType, bool maybeInCheck)
uint Mobility(pieceT p, colorT color, squareT from)
void SetEPTarget(squareT s)
const directionT NULL_DIR
colorT tte_SideToMove(transTableEntryT *tte)
bool square_IsEdgeSquare(squareT sq)
leftDiagT square_LeftDiag(squareT sq)
const scoreFlagT SCORE_NONE
const genMovesT GEN_CAPTURES
const genMovesT GEN_ALL_MOVES
colorT piece_Color(pieceT p)
const scoreFlagT SCORE_EXACT
const squareT knightAttacks[66][9]
uint RankCount(pieceT p, rankT r) const
uint SquareColorCount(pieceT p, colorT sqColor)
const scoreFlagT SCORE_UPPER
colorT piece_Color_NotEmpty(pieceT p)
bool direction_IsDiagonal(directionT dir)
const byte * GetMaterial() const
byte tte_Castling(transTableEntryT *tte)
constexpr squareT square_Last(squareT sq, directionT dir)
int recogScore(int value)
bool square_Adjacent(squareT from, squareT to)
const directionT DOWN_RIGHT
void SetHashTableKilobytes(uint sizeKB)
void SetPawnTableKilobytes(uint sizeKB)
uint PerfTest(uint depth)
void push_back(const simpleMoveT &sm)
pieceT piece_Make(colorT c, pieceT p)
uint GetCount(colorT c) const
const directionT DOWN_LEFT
bool GetCastling(colorT c, castleDirT dir) const
const sanFlagT SAN_MATETEST
void ClearPawnTable(void)
fyleT square_Fyle(squareT sq)
bool piece_IsSlider(pieceT p)