void ttWrite(const Pos *pos, Depth ply, Depth depth, Move move, Score score, Bound bound) { // Sanity checks. assert(depthIsValid(ply)); assert(depthIsValid(depth)); assert(moveIsValid(move) || move==MoveNone); assert(scoreIsValid(score)); assert(bound!=BoundNone); uint64_t key=posGetKey(pos); // Grab cluster. HTableKey hTableKey=ttHTableKeyFromPos(pos); TTCluster *cluster=htableGrab(tt, hTableKey); // Find entry to overwrite. TTEntry *entry, *replace=cluster->entries; unsigned int i, replaceScore=0; // Worst possible score. for(i=0,entry=cluster->entries;i<ttClusterSize;++i,++entry) { // If we find an exact match, simply reuse this entry. // We can also be certain that if this entry is unused, we will not find an // exact match in a later entry (otherwise said later entry would have // instead been written to this unused entry). if (ttEntryMatch(pos, entry) || ttEntryUnused(entry)) { // Set key (in case entry was previously unused). entry->keyUpper=(key>>48); // Update entry date (to reset age to 0). entry->date=searchGetDate(); // Update move if we have one and it is from a deeper search (or no move already stored). if (!moveIsValid(entry->move) || (moveIsValid(move) && depth>=entry->depth)) entry->move=move; // Update score, depth and bound if search was at least as deep as the entry depth. if (depth>=entry->depth) { entry->score=ttScoreIn(score, ply); entry->depth=depth; entry->bound=bound; } htableRelease(tt, hTableKey); return; } // Otherwise check if entry is better to use than replace. unsigned int entryScore=ttEntryFitness(searchDateToAge(entry->date), entry->depth, entry->bound==BoundExact); if (entryScore>replaceScore) { replace=entry; replaceScore=entryScore; } }
void posUndoMove(Pos *pos) { Move move=pos->data->lastMove; assert(moveIsValid(move) || move==MoveNone); // Update generic fields. pos->stm=colourSwap(pos->stm); pos->fullMoveNumber-=(pos->stm==ColourBlack); if (move!=MoveNone) { Sq fromSq=moveGetFromSq(move); Sq toSq=moveGetToSq(move); Piece toPiece=moveGetToPiece(move); // Move piece back. if (toPiece!=pos->data->movePiece) { assert(pieceGetType(pos->data->movePiece)==PieceTypePawn); posPieceMoveChange(pos, toSq, fromSq, pos->data->movePiece); } else posPieceMove(pos, toSq, fromSq); // Replace any captured piece. if (pos->data->capPiece!=PieceNone) posPieceAdd(pos, pos->data->capPiece, pos->data->capSq); // If castling replace the rook. if (pieceGetType(toPiece)==PieceTypeKing) { if (toSq==fromSq+2) posPieceMove(pos, toSq-1, toSq+1); // Kingside. else if (toSq==fromSq-2) posPieceMove(pos, toSq+1, toSq-2); // Queenside. } } // Discard data. --pos->data; assert(posIsConsistent(pos)); }
bool posMakeMove(Pos *pos, Move move) { assert(moveIsValid(move) || move==MoveNone); # ifndef NDEBUG bool canMakeMoveResult=posCanMakeMove(pos, move); # endif // Use next data entry. if (pos->data+1>=pos->dataEnd) { // We need more space. size_t size=2*(pos->dataEnd-pos->dataStart); PosData *ptr=realloc(pos->dataStart, size*sizeof(PosData)); if (ptr==NULL) return false; unsigned int dataOffset=pos->data-pos->dataStart; pos->dataStart=ptr; pos->dataEnd=ptr+size; pos->data=ptr+dataOffset; } ++pos->data; // Update generic fields. Sq fromSq=moveGetFromSq(move); Sq toSq=moveGetToSq(move); pos->data->lastMove=move; pos->data->halfMoveNumber=(pos->data-1)->halfMoveNumber+1; pos->data->epSq=SqInvalid; pos->data->key=(pos->data-1)->key^posKeySTM^posKeyEP[(pos->data-1)->epSq]; pos->data->cast=(pos->data-1)->cast; pos->data->movePiece=PieceNone; pos->data->capPiece=posGetPieceOnSq(pos, toSq); pos->data->capSq=toSq; pos->fullMoveNumber+=(pos->stm==ColourBlack); // Inc after black's move. pos->stm=colourSwap(pos->stm); if (move!=MoveNone) { Piece fromPiece=posGetPieceOnSq(pos, fromSq); pos->data->movePiece=fromPiece; // Update castling rights pos->data->cast&=posCastlingUpdate[fromSq] & posCastlingUpdate[toSq]; switch(pieceGetType(fromPiece)) { case PieceTypePawn: { // Pawns are complicated so deserve a special case. // En-passent capture? bool isEP=(sqFile(fromSq)!=sqFile(toSq) && pos->data->capPiece==PieceNone); if (isEP) { pos->data->capSq^=8; pos->data->capPiece=pieceMake(PieceTypePawn, pos->stm); assert(posGetPieceOnSq(pos, pos->data->capSq)==pos->data->capPiece); } // Capture? if (pos->data->capPiece!=PieceNone) // Remove piece. posPieceRemove(pos, pos->data->capSq); // Move the pawn, potentially promoting. Piece toPiece=moveGetToPiece(move); if (toPiece!=fromPiece) posPieceMoveChange(pos, fromSq, toSq, toPiece); else posPieceMove(pos, fromSq, toSq); // Pawn moves reset 50 move counter. pos->data->halfMoveNumber=0; // If double pawn move check set EP capture square (for next move). if (abs(sqRank(toSq)-sqRank(fromSq))==2) { Sq epSq=toSq^8; if (posIsEPCap(pos, epSq)) pos->data->epSq=epSq; } } break; case PieceTypeKing: // Castling. if (sqFile(toSq)==sqFile(fromSq)+2) posPieceMove(pos, toSq+1, toSq-1); // Kingside. else if (sqFile(toSq)==sqFile(fromSq)-2) posPieceMove(pos, toSq-2, toSq+1); // Queenside. // Fall through to move king. default: // Capture? if (pos->data->capPiece!=PieceNone) { // Remove piece. posPieceRemove(pos, toSq); // Captures reset 50 move counter. pos->data->halfMoveNumber=0; } // Move non-pawn piece (i.e. no promotion to worry about). posPieceMove(pos, fromSq, toSq); break; } // Does move leave STM in check? if (posIsXSTMInCheck(pos)) { posUndoMove(pos); assert(!canMakeMoveResult); return false; } // Update key. pos->data->key^=posKeyCastling[pos->data->cast^(pos->data-1)->cast]^posKeyEP[pos->data->epSq]; } assert(posIsConsistent(pos)); assert(canMakeMoveResult); return true; }
bool posCanMakeMove(const Pos *pos, Move move) { // Sanity checks and special case. assert(moveIsValid(move) || move==MoveNone); if (move==MoveNone) return true; // Use local variables to simulate having made the move. Colour stm=moveGetColour(move); assert(stm==posGetSTM(pos)); Colour xstm=colourSwap(stm); BB occ=posGetBBAll(pos); BB opp=posGetBBColour(pos, xstm); Sq fromSq=moveGetFromSq(move); Sq toSq=moveGetToSq(move); BB fromBB=bbSq(fromSq); BB toBB=bbSq(toSq); Sq kingSq=posGetKingSq(pos, stm); if (fromSq==kingSq) kingSq=toSq; // King move. occ&=~fromBB; // Move piece. occ|=toBB; opp&=~toBB; // Potentially capture opp piece (so it cannot attack us later). if (moveGetToPieceType(move)==PieceTypePawn && sqFile(fromSq)!=sqFile(toSq) && posGetPieceOnSq(pos, toSq)==PieceNone) { // En-passent capture. assert(pos->data->epSq==toSq); occ^=bbSq(toSq^8); opp^=bbSq(toSq^8); } // Make a list of squares we need to ensure are unattacked. BB checkSquares=bbSq(kingSq); if (moveIsCastling(move)) checkSquares|=fromBB|bbSq((toSq+fromSq)/2); // Test for attacks to any of checkSquares. // Pawns are done setwise. BB oppPawns=(posGetBBPiece(pos, pieceMake(PieceTypePawn, xstm)) & opp); if (bbForwardOne(bbWingify(oppPawns), xstm) & checkSquares) return false; // Pieces are checked for each square in checkSquares (which usually only has a single bit set anyway). while(checkSquares) { Sq sq=bbScanReset(&checkSquares); // Knights. if (attacksKnight(sq) & opp & posGetBBPiece(pos, pieceMake(PieceTypeKnight, xstm))) return false; // Bishops and diagonal queen moves. if (attacksBishop(sq, occ) & opp & (posGetBBPiece(pos, pieceMake(PieceTypeBishopL, xstm)) | posGetBBPiece(pos, pieceMake(PieceTypeBishopD, xstm)) | posGetBBPiece(pos, pieceMake(PieceTypeQueen, xstm)))) return false; // Rooks and orthogonal queen moves. if (attacksRook(sq, occ) & opp & (posGetBBPiece(pos, pieceMake(PieceTypeRook, xstm)) | posGetBBPiece(pos, pieceMake(PieceTypeQueen, xstm)))) return false; // King. if (attacksKing(sq) & opp & posGetBBPiece(pos, pieceMake(PieceTypeKing, xstm))) return false; } return true; }
void movesRewind(Moves *moves, Move ttMove) { moves->stage=MovesStageTT; moves->next=moves->list; moves->ttMove=((moveIsValid(ttMove) && (posMoveGetType(moves->pos, ttMove)&moves->allowed)) ? ttMove : MoveInvalid); }
bool moveIsDP(Move move) { assert(moveIsValid(move)); int toRank=sqRank(moveGetToSqRaw(move)); int fromRank=sqRank(moveGetFromSq(move)); return (moveGetToPieceType(move)==PieceTypePawn && abs(toRank-fromRank)==2); }
Colour moveGetColour(Move move) { assert(moveIsValid(move)); return pieceGetColour(moveGetToPiece(move)); }
PieceType moveGetToPieceType(Move move) { assert(moveIsValid(move)); return pieceGetType(moveGetToPiece(move)); }
Piece moveGetToPiece(Move move) { assert(moveIsValid(move)); return move>>MoveShiftToPiece; }