}
}
sqr2file[CK_DOUBLE] = sqr2file[CK_NONE] = 13; // for decoding hashed checker
-#define CASTLE(R,F,RT,KT,RF) toDecode[R*22+F] = RT; dropType[R*22+F] = KT; zoneTab[R*22+F] = RF; promoInc[R*22+F] = 3-31; sqr2file[R*22+F] = 11;
+#define CASTLE(R,F,RT,KT,RF) toDecode[R*22+F] = RT; dropType[R*22+F] = KT; zoneTab[R*22+F] = RF; promoInc[R*22+F] = 0; sqr2file[R*22+F] = 11;
if(v == 0) for(f=0; f<11; f++) { // In Chess we re-assign other ranks to under-promotions in zone
for(r=1; r<7; r++) toDecode[r*22+11+f] = f + (r < 4 ? 0 : 7*22); // redirect to last rank
promoInc[1*22+11+f] = promoInc[6*22+11+f] += 1;
CASTLE(8, 21, 3, 2, 0) // Q-side
CASTLE(9, 21, 7*22+3, 7*22+2, 7*22+0)
spoiler[0*22+0] = 4; // initial King and Rook squares marked as castling-right spoilers
- spoiler[0*22+0] = 5;
+ spoiler[0*22+4] = 5;
spoiler[0*22+7] = 1;
spoiler[7*22+0] = 8;
spoiler[7*22+4] = 10;
int drops; // index of first quiet drop
int stage; // stage of move generation (0=hash/capt/prom, 1=killer/noncapt, 2=check-drops, 3=quiet drops)
int late; // start of late moves
+ int castlings; // end of list of board moves without castlings
int epSqr;
int checker;
} MoveStack;
{int i; printf("%s\n",s); for(i=0; i<ply; i++) printf(" {%x} %s", deprec[i], MoveToText(path[i])); PrintDBoard("board", board, " ", 11); exit(1); }
int
-MoveGen (int stm, MoveStack *m)
+MoveGen (int stm, MoveStack *m, int castle)
{ // generate all board moves, return 1 if King capture found amongst those
int r, f;
m->firstMove = m->nonCapts = m->late = moveSP; m->stage = 0;
}
m->unsorted = m->firstMove; m->drops = moveSP;
+ r = location[stm+31]; m->castlings = moveSP; f = 0;
+ if(!(stm >> 5 & castle)) { // K-side castling
+ f++;
+ if(board[r+1] == 0 && board[r+2] == 0) f += 2, moveStack[moveSP++] = r << 8 | 8*22+10 + 22*(stm == BLACK);
+ }
+ if(!(stm >> 3 & castle)) { // Q-side castling
+ f++;
+ if(board[r-1] == 0 && board[r-2] == 0 && board[r-3] == 0) f += 2, moveStack[moveSP++] = r << 8 | 8*22+21 + 22*(stm == BLACK);
+ }
+
return 0;
}
f->fromPiece = board[f->fromSqr]; // occupant or (for drops) complemented holdings count
if(f->checker != CK_NONE && NonEvade(f)) return 0; // abort if move did not evade existing check
f->mutation = (f->fromPiece >> 7) | f->fromPiece; // occupant or (for drops) -1
- f->toPiece = f->mutation + promoInc[to] + dropType[f->fromSqr]; // (possibly promoted) occupant or (for drops) piece to drop
- f->savePiece = board[f->toSqr]; // replacement victim
+ f->toPiece = f->mutation + dropType[f->fromSqr] | promoInc[to]; // (possibly promoted) occupant or (for drops) piece to drop
+ f->victim = board[f->captSqr]; // for now this is the replacement victim
f->newEval = f->pstEval; f->newKey = f->hashKey; // start building new key and eval
f->epSqr = 255;
f->rookSqr = sqr2file[f->toSqr] + (pawnCount - board); // normally (i.e. when not castling) use for pawnCount
f->rook = board[f->rookSqr]; // save and update Pawn occupancy
- board[f->rookSqr] = f->rook + pawnBulk[f->toPiece] - pawnBulk[f->mutation] - pawnBulk[f->savePiece]; // assumes all on same file!
+ board[f->rookSqr] = f->rook + pawnBulk[f->toPiece] - pawnBulk[f->mutation] - pawnBulk[f->victim]; // assumes all on same file!
//printf("f=%02x t=%02x fp=%02x tp=%02x sp=%02x mut=%02x ep=%02x\n", f->fromSqr, f->toSqr, f->fromPiece, f->toPiece, f->savePiece, f->mutation, f->epSqr);
if(to >= specials) { // treat special moves for Chess
if(sqr2file[to] > 11) { // e.p. capture, shift capture square
//printf("# e.p. %02x\n", to);
f->captSqr = toDecode[to-11]; // use to-codes from double pushes, which happen to be what we need
f->victim = board[f->captSqr];
+ f->savePiece = board[f->toSqr];
board[f->captSqr] = 0; // e.p. is only case with toSqr != captSqr where we have to clear captSqr
} else if(sqr2file[to] < 8) { // double push
int xpawn = f->toPiece ^ COLOR; // enemy Pawn
board[f->toSqr - 1] == xpawn ) {
f->epSqr = (f->fromSqr + f->toSqr) >> 1; // set e.p. rights
}
- f->victim = 0; // for key and pst update
} else { // castling. at this point we are set up to 'promote' a King to Rook (so the check tests sees the Rook, and UnMake restores location[K])
f->rookSqr = zoneTab[to]; // Rook from-square
f->rook = board[f->rookSqr]; // arrange Rook to be put back on UnMake (pawnCount is never modified in chess)
board[f->rookSqr] = 0; // and remove it
- f->newEval -= PST[f->toPiece][f->rookSqr];
- f->newKey -= KEY(f->toPiece, f->rookSqr);
+ f->newEval -= PST[f->rook][f->rookSqr];
+ f->newKey -= KEY(f->rook, f->rookSqr);
f->captSqr = dropType[to]; // this tabulates to-square of the King
- f->victim = board[f->captSqr]; // should be 0, but who knows?
+ f->savePiece = f->victim; // now toSqr and captSqr are different, make sure the piece that was on toSqr goes back there in UnMake
+ f->victim = board[f->captSqr]; // should be 0, but who knows?
+ f->toPiece = f->rook; // make sure Rook (or whatever was in corner) will be placed on toSqr
board[f->captSqr] = f->mutation; // place the King
- f->newEval += PST[f->mutation][f->captSqr];
+ f->newEval += PST[f->mutation][f->captSqr] + 50; // add 50 cP castling bonus
f->newKey += KEY(f->mutation, f->captSqr);
location[f->mutation] = f->captSqr; // be sure King location stays known
}
- } else f->victim = f->savePiece; // for normal moves replacement victim counts
+ }
board[f->fromSqr] = f->fromPiece - f->mutation; // 0 or (for drops) decremented count
board[f->toSqr] = f->toPiece;
board[handSlot[f->victim]]--; // put victim in holdings
UnMake (StackFrame *f)
{
board[f->rookSqr] = f->rook; // restore either pawnCount or (after castling) Rook from-square
- board[f->captSqr] = f->victim; // differs from toSqr on e.p. (Pawn to-square) and castling, (King to-square) and should be cleared then
board[f->toSqr] = f->savePiece; // put back the regularly captured piece (for castling that captured by Rook)
+ board[f->captSqr] = f->victim; // differs from toSqr on e.p. (Pawn to-square) and castling, (King to-square) and should be cleared then
board[f->fromSqr] = f->fromPiece; // and the mover
board[handSlot[f->victim]]++;
location[f->fromPiece] = f->fromSqr;
if(PATH)printf("%d:%d Hash Probe %016llx\n",ply,depth,f.hashKey);
// hash probe
hashKeyH = f.hashKey >> 32;
- entry = hashTable + (f.hashKey + (stm + 9849)*(m.epSqr + 51451) & hashMask);
+ entry = hashTable + (f.hashKey + (stm + 9849 + f.rights)*(m.epSqr + 51451) & hashMask);
if(entry->lock == hashKeyH || (++entry)->lock == hashKeyH || (++entry)->lock == hashKeyH || (++entry)->lock == hashKeyH) { // 4 possible entries
int score = entry->score, d = entry->depth;
f.checker = entry->checker; f.checkDist = 0;
} else hit = hashMove = 0, f.checker = CK_UNKNOWN;
moveSP += 48; // create space for non-captures
- if(earlyGen) { // last moved piece was King
- if(MoveGen(stm, &m)) { moveSP = oldSP; return INF; } // make sure we detect if he moved into check
+ if(earlyGen) { // last moved piece was King, e.p. capture or castling
+ int kingCapt;
+ if(!ff->victim) board[ff->toSqr] = stm + 31 ^ COLOR; // kludge: after castling we temporarily make Rook a second King to catch passing through check
+ kingCapt = MoveGen(stm, &m, f.rights);
+ board[ff->toSqr] = ff->toPiece; // undo kludge damage
+ if(kingCapt) { moveSP = oldSP; ff->depth = MAXPLY; return INF; } // make sure we detect if he moved into check
}
if((++nodeCount & 0xFFF) == 0) abortFlag |= TimeIsUp(3); // check time limit every 4K nodes
}
// move generation
- if(!earlyGen) MoveGen(stm, &m); // generate moves if we had not done so yet
+ if(!earlyGen) MoveGen(stm, &m, f.rights); // generate moves if we had not done so yet
if(hashMove) moveStack[--m.firstMove] = hashMove; // put hash move in front of list (duplicat!)
+ if(f.checker != CK_NONE) moveSP = m.drops = m.castlings; // clip off castlings when in check
do { // IID loop
int curMove, highDepth;
int
Setup (char *fen)
{ // very flaky FEN parser
- static char castle[] = "QqKk-", startFEN[200];
+ static char castle[] = "KkQq-", startFEN[200];
int pstEval, rights, stm = WHITE, i, p, sqr = 22*(nrRanks-1); // upper-left corner
ClearBoard();
if(!fen) fen = startFEN; else strcpy(startFEN, fen); // remember start position, or use remembered one if not given
{
static char buf[20], pieceID[] = "+nbrq";
int promo = '\0', from = move >> 8 & 0xFF, to = move & 0xFF;
- int inc = promoInc[to];
+ int inc = promoInc[to], castle = (nrFiles < 11 && to%11 == 10);
to = toDecode[to];
if(inc > 0) promo = pieceID[inc - 16]; // move is promotion
- else if(inc < 0) to = 2*to - from; // move is castling, and 'to' indicates Rook; calculate King to-square
+ else if(castle) to = 2*to - from; // move is castling, and 'to' indicates Rook; calculate King to-square
if(promo == '+' && promoCode[WHITE] & Z_FIDE) promo = 'q';
if(from%22 > 10) sprintf(buf, "%c@%c%d", pieces[dropType[from]-1&~COLOR], 'a'+(to%22), 1+(to/22)); // move is drop
else sprintf(buf, "%c%d%c%d%c", 'a'+(from%22), 1+(from/22), 'a'+(to%22), 1+(to/22), promo);