From: H.G.Muller Date: Wed, 28 Dec 2016 16:40:27 +0000 (+0100) Subject: Implement castling X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=188d3f8efde66d94b32eade3dc5063578afeb435;p=crazywa.git Implement castling MoveGen() now also generates castlings. Legality is tested by the kludge of replacing the Rook by a second King during the (early) move generation in the next ply. MakeMove() is refactored to make sure both King and Rook victim are saved. In addition promotion is now implemented by OR'ing the promoInc into the piece code,tomake the engine resistent to promoting an already-promoted piece (e.g. due to hash-move mixup). --- diff --git a/dropper.c b/dropper.c index 29f632c..0510ee8 100644 --- a/dropper.c +++ b/dropper.c @@ -474,7 +474,7 @@ printf("# variant %d: %s\n", v, variants[v].name); } } 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; @@ -496,7 +496,7 @@ printf("# variant %d: %s\n", v, variants[v].name); 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; @@ -678,6 +678,7 @@ typedef struct { // move stack sectioning 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; @@ -730,7 +731,7 @@ Dump (char *s) {int i; printf("%s\n",s); for(i=0; ifirstMove = m->nonCapts = m->late = moveSP; m->stage = 0; @@ -787,6 +788,16 @@ MoveGen (int stm, MoveStack *m) } 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; } @@ -913,19 +924,20 @@ MakeMove (StackFrame *f, int move) 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 @@ -933,21 +945,22 @@ MakeMove (StackFrame *f, int move) 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 @@ -965,8 +978,8 @@ void 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; @@ -1004,7 +1017,7 @@ if(ply > 90) Dump("maxply"); 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; @@ -1029,8 +1042,12 @@ if(hashMove && board[hashMove>>8&255] == 0) {char s[100];sprintf(s,"bad hash mov } 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 @@ -1069,8 +1086,9 @@ if(PATH)printf("%d:%d {%d,%d} max=%d eval=%d check=%02x,%d,%d\n",ply,depth,alp } // 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; @@ -1268,7 +1286,7 @@ StackFrame undoInfo; 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 @@ -1333,10 +1351,10 @@ MoveToText (int move) { 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);