4 Position::Position(MovementGenerator
*mg
) : generator(mg
), gameOver(false), isCheck(false), noisiness(0) {
7 mg
->getAllLegalMoves(&legalMoves
);
10 Position::Position(Position
*p
, int mv
) {
11 // Dampen the noisiness.
12 noisiness
= (int)(p
->getNoisiness() * 0.5f
);
14 legalMoves
.reserve(64);
16 p
->getBoard(&board
[0], &x
, &x
, &x
, &x
);
17 whiteToMove
= p
->isWhiteToMove();
18 generator
= p
->getMovementGenerator();
19 move(p
->getLegalMoves()->at(mv
),0);
20 gameOver
= testLeafNode();
23 Position::Position(MovementGenerator
*mg
, char b
[8][8], bool white
) : generator(mg
), whiteToMove(white
), noisiness(0) {
24 for (int i
= 0; i
< 8; ++i
) {
25 for (int j
= 0; j
< 8; ++j
) {
26 board
[i
][j
] = b
[i
][j
];
29 mg
->setPosition(this);
30 mg
->getAllLegalMoves(&legalMoves
);
31 isCheck
= !generator
->isKingSafe(0,0,0,0);
32 gameOver
= testLeafNode();
36 inline bool Position::testLeafNode() {
37 // Checkmate or stalemate
38 if (legalMoves
.empty()) {
41 for (int i
= 0; i
< 8; ++i
) {
42 for (int j
= 0; j
< 8; ++j
) {
50 // Game is still alive
56 // Nothing but kings on the board
60 inline char Position::translate(char piece
) {
78 inline int Position::pawnIsolationPenalty(int j
, bool white
) {
87 for (int i
= 0; i
< 8; ++i
) {
88 if (board
[i
][k
] == p
|| board
[i
][k
] == e
) {
95 for (int i
= 0; i
< 8; ++i
) {
96 if (board
[i
][k
] == p
|| board
[i
][k
] == e
) {
115 inline int Position::pawnBackwardPenalty(int i
, int j
, bool white
) {
126 if ((x1
>= 0 && (board
[i
][x1
] == p
|| board
[i
][x1
] == e
|| board
[y
][x1
] == p
|| board
[y
][x1
] == e
)) || (x2
< 8 && (board
[i
][x2
] == p
|| board
[i
][x2
] == e
|| board
[y
][x2
] == p
|| board
[y
][x2
] == e
))) {
130 // Check that the pawn isn't on a half-open lane (which will cause
131 // a higher penalty.)
133 for (int k
= i
- 1; k
>= 0; --k
) {
134 if (board
[k
][j
] == 'P' || board
[k
][j
] == 'E') {
140 for (int k
= i
+ 1; k
< 8; ++k
) {
141 if (board
[k
][j
] == 'p' || board
[k
][j
] == 'e') {
150 inline int Position::pawnAdvancementBonus(int i
, int j
, bool white
) {
158 // Penalty for unadvanced king & queen pawns
159 if (advancement
== 0 && (j
== 3 || j
== 4)) {
162 // Big fat bonus for pawn about to queen
163 if (advancement
== 5) {
166 if (advancement
== 4) {
169 // Bigger bonus for centre pawns
173 return advancement
* 2;
176 return advancement
* 4;
178 return advancement
* 3;
181 inline int Position::pawnProximityToKingBonus(int i
, int j
, bool white
) {
189 for (int y
= i
- 1; y
<= i
+ 1; ++y
) {
190 for (int x
= j
- 1; x
<= j
+ 1; ++x
) {
191 if (x
>= 0 && x
< 8 && y
>= 0 && y
< 8 && (board
[y
][x
] == p
|| board
[y
][x
] == e
)) {
196 // Having no pawns at all in the vincinity is bad. Penalty!
203 inline int Position::centreBonus(int x
) {
219 inline int Position::bishopControlBonus(int i
, int j
, bool white
) {
221 // Check upwards to the left
224 while (x
>= 0 && y
>= 0) {
225 switch(board
[y
][x
]) {
232 bonus
+= xrayControlBonus(y
,x
,white
);
239 // Check upwards to the right
242 while (x
< 8 && y
>= 0) {
243 switch(board
[y
][x
]) {
250 bonus
+= xrayControlBonus(y
,x
,white
);
256 // Check downwards to the left
259 while (x
>= 0 && y
< 8) {
260 switch(board
[y
][x
]) {
267 bonus
+= xrayControlBonus(y
,x
,white
);
273 // Check downwards to the right
276 while (x
< 8 && y
< 8) {
277 switch(board
[y
][x
]) {
284 bonus
+= xrayControlBonus(y
,x
,white
);
292 inline int Position::rookControlBonus(int i
, int j
, bool white
) {
297 switch(board
[i
][x
]) {
304 bonus
+= xrayControlBonus(i
,x
,white
);
309 // Check to the right
312 switch(board
[i
][x
]) {
319 bonus
+= xrayControlBonus(i
,x
,white
);
327 switch(board
[y
][j
]) {
334 bonus
+= xrayControlBonus(y
,j
,white
);
342 switch(board
[y
][j
]) {
349 bonus
+= xrayControlBonus(y
,j
,white
);
356 inline int Position::xrayControlBonus(int i
, int j
, bool white
) {
358 bool whiteSide
= true;
362 switch(board
[i
][j
]) {
370 // Threatening a valuable (r, q or k) piece even as an "x-ray" attack
372 if ((white
&& board
[i
][j
] < 'Z') || (!white
&& board
[i
][j
] > 'a')) {
376 // If white and whiteSide are the same, increment bonus by 1, otherwise by 2.
377 // (Control of the enemy's squares is more valuable.)
378 if (white
== whiteSide
) {
387 inline void Position::reset() {
390 for (int i
= 0; i
< 8; ++i
) {
391 for (int j
= 0; j
< 8; ++j
) {
411 for (int i
= 0; i
< 8; ++i
) {
417 inline void Position::move(int mv
, int promotion
) {
418 // If a piece is eaten by the move, the position isn't quiet
419 if (board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] != ' ') {
424 board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] = board
[UNPACK_I1(mv
)][UNPACK_J1(mv
)];
425 board
[UNPACK_I1(mv
)][UNPACK_J1(mv
)] = ' ';
426 // Check for castling
427 if (board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] == 'x') {
428 if (UNPACK_J1(mv
) - UNPACK_J2(mv
) == 2) {
432 else if (UNPACK_J1(mv
) - UNPACK_J2(mv
) == -2) {
437 if (board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] == 'X') {
438 if (UNPACK_J1(mv
) - UNPACK_J2(mv
) == 2) {
442 else if (UNPACK_J1(mv
) - UNPACK_J2(mv
) == -2) {
449 // Check for en passant
450 if (board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] == 'p' && board
[UNPACK_I2(mv
) + 1][UNPACK_J2(mv
)] == 'E') {
451 board
[UNPACK_I2(mv
) + 1][UNPACK_J2(mv
)] = ' ';
453 // The right to en passant is one-turn-only. Set all E's to P's.
454 for (int j
= 0; j
< 8; ++j
) {
455 if (board
[3][j
] == 'E') {
459 // Check for pawn promotion
460 if (UNPACK_I2(mv
) == 0 && board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] == 'p') {
463 board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] = 'r';
466 board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] = 'b';
469 board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] = 'n';
472 board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] = 'q';
477 // Same checks for black
478 if (board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] == 'P' && board
[UNPACK_I2(mv
) - 1][UNPACK_J2(mv
)] == 'e') {
479 board
[UNPACK_I2(mv
) - 1][UNPACK_J2(mv
)] = ' ';
482 for (int j
= 0; j
< 8; ++j
) {
483 if (board
[4][j
] == 'e') {
487 // Check for pawn promotion
488 if (UNPACK_I2(mv
) == 7 && board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] == 'P') {
491 board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] = 'R';
494 board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] = 'B';
497 board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] = 'N';
500 board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] = 'Q';
504 // Check whether a piece was moved that requires a change of status
505 // due to the movement
506 switch(board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)]) {
509 board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] -= 13; // X -> K, x -> k
513 board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] -= 2; // T -> R, t -> r
517 if (std::abs(UNPACK_I1(mv
) - UNPACK_I2(mv
)) > 1) {
518 board
[UNPACK_I2(mv
)][UNPACK_J2(mv
)] -= 11; // P -> E, p -> e
522 whiteToMove
= !whiteToMove
;
524 generator
->setPosition(this);
525 generator
->getAllLegalMoves(&legalMoves
);
526 isCheck
= !generator
->isKingSafe(0,0,0,0);
529 inline void Position::print() {
530 for (int i
= 0; i
< 8; ++i
) {
531 std::cout
<< " +---+---+---+---+---+---+---+---+" << std::endl
;
533 for (int j
= 0; j
< 8; ++j
) {
534 std::cout
<< " | " << translate(board
[i
][j
]);
536 std::cout
<< " |" << std::endl
;
538 std::cout
<< " +---+---+---+---+---+---+---+---+" << std::endl
;
539 std::cout
<< " A B C D E F G H" << std::endl
<< std::endl
;
542 inline void Position::getBoard(char b
[8][8], int *wkx
, int *wky
, int *bkx
, int *bky
) {
543 for (int i
= 0; i
< 8; ++i
) {
544 for (int j
= 0; j
< 8; ++j
) {
545 if (board
[i
][j
] == 'K' || board
[i
][j
] == 'X') {
549 if (board
[i
][j
] == 'k' || board
[i
][j
] == 'x') {
553 b
[i
][j
] = board
[i
][j
];
558 inline bool Position::isWhiteToMove() {
562 bool Position::isGameOver() {
566 int Position::evaluate() {
570 // White is checkmated
571 return std::numeric_limits
<int>::min();
574 // Black is checkmated
575 return std::numeric_limits
<int>::max();
579 // Stalemate or two kings butting heads
585 int wkx
= 0, wky
= 0, bkx
= 0, bky
= 0;
586 for (int i
= 0; i
< 8; ++i
) {
587 for (int j
= 0; j
< 8; ++j
) {
588 switch(board
[i
][j
]) {
592 black
+= rookControlBonus(i
,j
,false);
596 black
+= bishopControlBonus(i
,j
,false);
600 black
+= centreBonus(i
);
601 black
+= centreBonus(j
);
609 black
-= pawnIsolationPenalty(j
,false);
610 // black -= pawnBackwardPenalty(i,j,false);
611 black
+= pawnAdvancementBonus(i
,j
,false);
621 white
+= rookControlBonus(i
,j
,true);
625 white
+= bishopControlBonus(i
,j
,true);
629 white
+= centreBonus(i
);
630 white
+= centreBonus(j
);
638 white
-= pawnIsolationPenalty(j
,true);
639 // white -= pawnBackwardPenalty(i,j,true);
640 white
+= pawnAdvancementBonus(i
,j
,true);
650 // Before the endgame we don't want the king in the centre of the board
651 if (white
+ black
> 1700) {
652 black
-= centreBonus(bkx
);
653 black
-= centreBonus(bky
);
654 white
-= centreBonus(wkx
);
655 white
-= centreBonus(wky
);
656 black
+= pawnProximityToKingBonus(bky
,bkx
,false);
657 white
+= pawnProximityToKingBonus(wky
,wkx
,true);
659 // But during the endgame he's welcome.
661 black
+= centreBonus(bkx
);
662 black
+= centreBonus(bky
);
663 white
+= centreBonus(wkx
);
664 white
+= centreBonus(wky
);
666 return white
- black
;
669 inline std::vector
<int>* Position::getLegalMoves() {
673 inline MovementGenerator
* Position::getMovementGenerator() {
677 long Position::getHash() {
679 // Hash piece positions
680 for (int i
= 0; i
< 8; ++i
) {
681 for (int j
= 0; j
< 8; ++j
) {
682 switch (board
[i
][j
]) {
684 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 1;
687 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 2;
691 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 4;
694 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 8;
697 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 16;
700 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 32;
704 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 64;
707 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 128;
710 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 256;
714 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 512;
717 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 1024;
720 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 2048;
723 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 4096;
727 hash
= hash
^ (1 << (i
* 8 + j
)) ^ 8192;
732 // Hash castling rights
733 if (board
[0][4] == 'X') {
734 if (board
[0][0] == 'T') {
737 if (board
[0][7] == 'T') {
741 if (board
[7][4] == 'x') {
742 if (board
[7][0] == 't') {
745 if (board
[7][7] == 't') {
746 hash
= hash
^ 131072;
751 hash
= hash
^ 262144;