Code: Select all
/********************************************************/
/* this is the position solved by the first SEE */
8 . . . . . b k .
7 . . . . q p . .
6 . . R . . . p .
5 . . r . p . N p
4 . . p . N . . .
3 . r . . . . . P
2 . . . . . P P .
1 . . Q . . . K .
a b c d e f g h
FEN 5bk1/4qp2/2R3p1/2r1p1Np/2p1N3/1r5P/5PP1/2Q3K1 b - -
1. 0000 BLACK, Castle = 0, Ep = -1, Fifty = 0, Ev = 390, Ph = 17, Ch = F,
H = 0x095786bccec27f94, PH = 0x4b7f411ac2454bbe, MH = 0x8df84a0c65cd6c2c
8 _ _ _ _ _ _ _ _
7 _ _ _ _ _ _ _ _
6 _ _ _ _ _ _ _ _
5 _ _ 1 _ _ _ _ _
4 _ _ _ _ 1 _ _ _
3 _ 1 _ _ _ _ _ _
2 _ _ _ _ _ _ _ _
1 _ _ 1 _ _ _ _ _
a b c d e f g h
move = c4c3
from = 26, pc = 1, slist[0] = 0, dir = 8, lastvalue = 100
lsb = 28, pc = 2, slist[1] = 100, dir = 0, lastvalue = 325
lsb = 17, pc = 4, slist[2] = 225, dir = -1, lastvalue = 500
lsb = 2, pc = 5, slist[3] = 275, dir = -8, lastvalue = 975
lsb = 34, pc = 4, slist[4] = 700, dir = 8, lastvalue = 500
lsb = 42, pc = 4, slist[5] = -200, dir = 8, lastvalue = 500
slist[5] = -200, -slist[4] = -700
slist[4] = 200, -slist[3] = -275
slist[3] = -200, -slist[2] = -225
slist[2] = 200, -slist[1] = -100
slist[1] = -200, -slist[0] = 0
slist[0] = 0
/********************************************************/
/* this is the flipped position solved by the first SEE */
8 . . q . . . k .
7 . . . . . p p .
6 . R . . . . . p
5 . . P . n . . .
4 . . R . P . n P
3 . . r . . . P .
2 . . . . Q P . .
1 . . . . . B K .
a b c d e f g h
FEN 2q3k1/5pp1/1R5p/2P1n3/2R1P1nP/2r3P1/4QP2/5BK1 w - -
0. ..0000 WHITE, Castle = 0, Ep = -1, Fifty = 0, Ev = 385, Ph = 17, Ch = F,
H = 0x24f8156e7adc9be5, PH = 0x7844c95a8db575be, MH = 0x4e9f270cd0c76f2c
8 _ _ 1 _ _ _ _ _
7 _ _ _ _ _ _ _ _
6 _ 1 _ _ _ _ _ _
5 _ _ _ _ 1 _ _ _
4 _ _ 1 _ _ _ _ _
3 _ _ _ _ _ _ _ _
2 _ _ _ _ _ _ _ _
1 _ _ _ _ _ _ _ _
a b c d e f g h
move = c5c6
from = 34, pc = 1, slist[0] = 0, dir = -8, lastvalue = 100
lsb = 36, pc = 2, slist[1] = 100, dir = 0, lastvalue = 325
lsb = 26, pc = 4, slist[2] = 225, dir = -8, lastvalue = 500
lsb = 18, pc = 4, slist[3] = 275, dir = -8, lastvalue = 500
lsb = 41, pc = 4, slist[4] = 225, dir = -1, lastvalue = 500
lsb = 58, pc = 5, slist[5] = 275, dir = 8, lastvalue = 975
slist[5] = 275, -slist[4] = -225
slist[4] = -275, -slist[3] = -275
slist[3] = 275, -slist[2] = -225
slist[2] = -275, -slist[1] = -100
slist[1] = 100, -slist[0] = 0
slist[0] = -100
/********************************************************/
/* this is the position solved by the second SEE */
8 . . . . . b k .
7 . . . . q p . .
6 . . R . . . p .
5 . . r . p . N p
4 . . p . N . . .
3 . r . . . . . P
2 . . . . . P P .
1 . . Q . . . K .
a b c d e f g h
FEN 5bk1/4qp2/2R3p1/2r1p1Np/2p1N3/1r5P/5PP1/2Q3K1 b - -
1. 0000 BLACK, Castle = 0, Ep = -1, Fifty = 0, Ev = 390, Ph = 17, Ch = F,
H = 0x095786bccec27f94, PH = 0x4b7f411ac2454bbe, MH = 0x8df84a0c65cd6c2c
from = 26, to = 18, pc = 1, capt = 0
8 _ _ _ _ _ _ _ _
7 _ _ _ _ _ _ _ _
6 _ _ _ _ _ _ _ _
5 _ _ 1 _ _ _ _ _
4 _ _ _ _ 1 _ _ _
3 _ 1 _ _ _ _ _ _
2 _ _ _ _ _ _ _ _
1 _ _ 1 _ _ _ _ _
a b c d e f g h
move = c4c3
see 0: sq = c4, capval = 0, lastval = 100
see 1: sq = e4, capval = 100, lastval = 325
see 2: sq = b3, capval = 225, lastval = 500
see 3: sq = c1, capval = 275, lastval = 975
see 4: sq = c5, capval = 700, lastval = 500
see 5: sq = c6, capval = -200, lastval = 500
value 5 = 200, bestvalue = 700
value 4 = -200, bestvalue = 275
value 3 = 200, bestvalue = 225
value 2 = -200, bestvalue = 100
see 2: sq = c5, capval = 225, lastval = 500
see 3: sq = c6, capval = 275, lastval = 500
see 4: sq = b3, capval = 225, lastval = 500
see 5: sq = c1, capval = 275, lastval = 975
value 5 = -275, bestvalue = 225
value 4 = 275, bestvalue = 275
value 3 = -275, bestvalue = 225
value 2 = 275, bestvalue = -200
value 1 = 200, bestvalue = 0
final see value = 0
/********************************************************/
/* this is the flipped position solved by the second SEE */
8 . . q . . . k .
7 . . . . . p p .
6 . R . . . . . p
5 . . P . n . . .
4 . . R . P . n P
3 . . r . . . P .
2 . . . . Q P . .
1 . . . . . B K .
a b c d e f g h
FEN 2q3k1/5pp1/1R5p/2P1n3/2R1P1nP/2r3P1/4QP2/5BK1 w - -
0. ..0000 WHITE, Castle = 0, Ep = -1, Fifty = 0, Ev = 385, Ph = 17, Ch = F,
H = 0x24f8156e7adc9be5, PH = 0x7844c95a8db575be, MH = 0x4e9f270cd0c76f2c
from = 34, to = 42, pc = 1, capt = 0
8 _ _ 1 _ _ _ _ _
7 _ _ _ _ _ _ _ _
6 _ 1 _ _ _ _ _ _
5 _ _ _ _ 1 _ _ _
4 _ _ 1 _ _ _ _ _
3 _ _ _ _ _ _ _ _
2 _ _ _ _ _ _ _ _
1 _ _ _ _ _ _ _ _
a b c d e f g h
move = c5c6
see 0: sq = c5, capval = 0, lastval = 100
see 1: sq = e5, capval = 100, lastval = 325
see 2: sq = c4, capval = 225, lastval = 500
see 3: sq = c3, capval = 275, lastval = 500
see 4: sq = b6, capval = 225, lastval = 500
see 5: sq = c8, capval = 275, lastval = 975
value 5 = -275, bestvalue = 225
value 4 = 275, bestvalue = 275
value 3 = -275, bestvalue = 225
value 2 = 275, bestvalue = 100
see 2: sq = b6, capval = 225, lastval = 500
see 3: sq = c8, capval = 275, lastval = 975
see 4: sq = c4, capval = 700, lastval = 500
see 5: sq = c3, capval = -200, lastval = 500
value 5 = 200, bestvalue = 700
value 4 = -200, bestvalue = 275
value 3 = 200, bestvalue = 225
value 2 = -200, bestvalue = 100
value 1 = 200, bestvalue = 0
final see value = 0
Code: Select all
/* this returns the bitboard of all pieces attacking a certain square */
u64 attackingPiecesAll(const position_t *pos, u32 sq){
u64 attackers = 0;
ASSERT(pos != NULL);
ASSERT(squareIsOk(sq));
attackers |= PawnCaps[sq][BLACK] & pos->pawns & pos->color[WHITE];
attackers |= PawnCaps[sq][WHITE] & pos->pawns & pos->color[BLACK];
attackers |= KnightMoves[sq] & pos->knights;
attackers |= KingMoves[sq] & pos->kings;
attackers |= bishopAttacksBB(sq, pos->occupied) & (pos->bishops | pos->queens);
attackers |= rookAttacksBB(sq, pos->occupied) & (pos->rooks | pos->queens);
return attackers;
}
/* this returns the bitboard of sliding pieces attacking in a direction
behind the piece attacker */
u64 behindFigure(u64 QR, u64 QB, u64 occupied, u32 from, int dir){
ASSERT(squareIsOk(from));
switch(dir){
case -9: return diagonalAttacks(occupied, from) & QB & DirA[0][from];
case -1: return rankAttacks(occupied, from) & QR & DirA[1][from];
case 7: return antiDiagAttacks(occupied, from) & QB & DirA[2][from];
case 8: return fileAttacks(occupied, from) & QR & DirA[3][from];
case 9: return diagonalAttacks(occupied, from) & QB & DirA[4][from];
case 1: return rankAttacks(occupied, from) & QR & DirA[5][from];
case -7: return antiDiagAttacks(occupied, from) & QB & DirA[6][from];
case -8: return fileAttacks(occupied, from) & QR & DirA[7][from];
default: return 0;
}
}
/* this is the first SEE routine */
int swapdebug(const position_t *pos, u32 m){
static const u32 pcval[] = {0, 100, 325, 325, 500, 975, 10000};
u32 to = moveTo(m);
u32 from = moveFrom(m);
u32 pc = movePiece(m);
u32 lastvalue = pcval[pc];
u32 n = 1;
u32 lsb;
u32 c = pos->side^1;
int dir = Direction[to][from];
int slist[32];
u32 kpos[2];
u64 attack;
ASSERT(pos != NULL);
ASSERT(moveIsOk(m));
kpos[WHITE] = getFirstBit(pos->kings & pos->color[WHITE]);
kpos[BLACK] = getFirstBit(pos->kings & pos->color[BLACK]);
attack = attackingPiecesAll(pos, to);
if(!(pc == PAWN && moveCapture(m) == EMPTY)){
attack ^= BitMask[from];
}
slist[0] = pcval[moveCapture(m)];
if(pc == PAWN && PAWN_RANK(from, pos->side) == Rank7)
lastvalue = pcval[QUEEN] - pcval[PAWN];
if(dir && pc != KING){
attack |= behindFigure((pos->queens|pos->rooks), (pos->queens|pos->bishops),
pos->occupied, from, dir);
}
if(isEnPassant(m)){
attack |= behindFigure((pos->queens|pos->rooks), (pos->queens|pos->bishops),
pos->occupied, to, Direction[to][to + ((pos->side == WHITE) ? -8 : 8)]);
}
displayBit(attack, 8);
Print(8, "from = %d, pc = %d, slist[0] = %d, dir = %d, lastvalue = %d\n",
from, pc, slist[0], dir, lastvalue);
while(attack){
if(attack & pos->pawns & pos->color[c]){
lsb = getFirstBit(attack & pos->pawns & pos->color[c]);
pc = PAWN;
}else if(attack & pos->knights & pos->color[c]){
lsb = getFirstBit(attack & pos->knights & pos->color[c]);
pc = KNIGHT;
}else if(attack & pos->bishops & pos->color[c]){
lsb = getFirstBit(attack & pos->bishops & pos->color[c]);
pc = BISHOP;
}else if(attack & pos->rooks & pos->color[c]){
lsb = getFirstBit(attack & pos->rooks & pos->color[c]);
pc = ROOK;
}else if(attack & pos->queens & pos->color[c]){
lsb = getFirstBit(attack & pos->queens & pos->color[c]);
pc = QUEEN;
}else if(attack & pos->kings & pos->color[c]){
lsb = getFirstBit(attack & pos->kings & pos->color[c]);
pc = KING;
}else break;
slist[n] = -slist[n-1] + lastvalue;
if(pc == PAWN && PAWN_RANK(lsb, c) == Rank7)
lastvalue = pcval[QUEEN] - pcval[PAWN];
else lastvalue = pcval[pc];
dir = Direction[to][lsb];
Print(8, "lsb = %d, pc = %d, slist[%d] = %d, dir = %d, lastvalue = %d\n",
lsb, pc, n, slist[n], dir, lastvalue);
if(dir && pc != KING)
attack |= behindFigure((pos->queens|pos->rooks), (pos->queens|pos->bishops),
pos->occupied, lsb, dir);
attack ^= BitMask[lsb];
n++;
c ^= 1;
}
while(--n){
Print(8, "slist[%d] = %d, -slist[%d] = %d\n", n, slist[n], n-1, -slist[n-1]);
if(slist[n] > -slist[n-1])
slist[n-1] = -slist[n];
}
Print(8, "slist[0] = %d\n", slist[0]);
return slist[0];
}
Code: Select all
/* this is the second SEE */
int see(const position_t *pos, u32 move){
int from = moveFrom(move);
int to = moveTo(move);
int pc = movePiece(move);
int capt = moveCapture(move);
int lastval = PcVal[pc];
int capval = PcVal[capt];
u64 attacks = attackingPiecesAll(pos, to);
u64 attackers, defenders;
int temp;
if(!(pc == PAWN && capt == EMPTY)){
attacks ^= BitMask[from];
}
if(pc == PAWN && PAWN_RANK(from, pos->side) == Rank7)
lastval = PcVal[QUEEN] - PcVal[PAWN];
if(Direction[to][from] && pc != KING){
attacks |= behindFigure((pos->queens|pos->rooks), (pos->queens|pos->bishops),
pos->occupied, from, Direction[to][from]);
}
if(isEnPassant(move)){
attacks |= behindFigure((pos->queens|pos->rooks), (pos->queens|pos->bishops),
pos->occupied, to, Direction[to][to + ((pos->side == WHITE) ? -8 : 8)]);
}
Print(8, "from = %d, to = %d, pc = %d, capt = %d\n",
from, to, pc, capt);
displayBit(attacks, 8);
attackers = attacks & pos->color[pos->side];
defenders = attacks & ~attackers;
Print(8, "see %d: sq = %s, capval = %d, lastval = %d\n", 0, sq2Str(from),
capval, lastval);
temp = newswap(pos, attackers, defenders, capval, lastval, to, pos->side^1, 1);
Print(8, "final see value = %d\n\n", temp);
return temp;
}
int newswap(const position_t *pos, u64 dfndrs, u64 atkrs, int capval,
int lastval, int to, int side, int ply){
int pc, value, sq, tempvalue, lastpiece = EMPTY, bestvalue = capval,
hasbehind = FALSE;
u64 atkrsclone = atkrs;
u64 temp;
while(atkrsclone){
sq = getLeastAtkr(pos, &pc, &atkrsclone);
if(pc == PAWN && PAWN_RANK(sq, side) == Rank7)
lastval = PcVal[QUEEN] - PcVal[PAWN];
temp = 0;
if(Direction[to][sq] && pc != KING){
temp = behindFigure((pos->queens|pos->rooks), (pos->queens|pos->bishops),
pos->occupied, sq, Direction[to][sq]);
hasbehind = TRUE;
}
if(lastpiece != EMPTY){
if(pc != lastpiece) return bestvalue;
if(!hasbehind) continue;
}
lastpiece = pc;
tempvalue = -capval + lastval;
Print(8, "see %d: sq = %s, capval = %d, lastval = %d\n",
ply, sq2Str(sq), tempvalue, PcVal[pc]);
value = -newswap(pos, ((atkrs & ~BitMask[sq]) | temp & pos->color[side]),
(dfndrs | temp & pos->color[side^1]), tempvalue, PcVal[pc],
to, side^1, ply+1);
Print(8, "value %d = %d, bestvalue = %d\n", ply, value, bestvalue);
if(value < bestvalue) bestvalue = value;
}
return bestvalue;
}
int getLeastAtkr(const position_t *pos, int *pc, u64 *atkrs){
int sq;
u64 x;
if(x = pos->pawns & *atkrs){
*pc = PAWN;
}else if(x = (pos->knights|pos->bishops) & *atkrs){
*pc = KNIGHT;
}else if(x = pos->rooks & *atkrs){
*pc = ROOK;
}else if(x = pos->queens & *atkrs){
*pc = QUEEN;
}else if(x = pos->kings & *atkrs){
*pc = KING;
}else{
ASSERT(FALSE);
}
sq = getFirstBit(x);
*atkrs ^= BitMask[sq];
return sq;
}
Note that in my engine I uses a1 = 0, ..., h8 = 63, pawn = 1, ..., king = 6.
Notice that the value of the first SEE on the position is 0 while the value of the first SEE on the flipped position is -100. This is where I failed in my Eval Symmetry test.
I think that 0 is the correct value.
In the value of the second SEE for the position and its flipped counterpart, it returns 0 for both sides.
I have not tested this much though. I don't know if the added accuracy can compensate for the little speed loss.
By the way, the routine I wrote is just the first working version so it might have bugs and it can still be optimized. It is also possible that it can include checks someday, or it could develop into a Super SOMA type of routine and maybe replace the quiescent search altogether. Just my crazy ideas.
