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)); }
MoveType posMoveGetType(const Pos *pos, Move move){ // Standard capture? Sq toSq=moveGetToSq(move); Piece capPiece=posGetPieceOnSq(pos, toSq); if (capPiece!=PieceNone) return MoveTypeCapture; // Promotion? Sq fromSq=moveGetFromSq(move); Piece fromPiece=posGetPieceOnSq(pos, fromSq); Piece toPiece=moveGetToPiece(move); if (fromPiece!=toPiece) return MoveTypeCapture; // En-passent capture? assert(capPiece==PieceNone); if (pieceGetType(fromPiece)==PieceTypePawn && sqFile(fromSq)!=sqFile(toSq)) return MoveTypeCapture; // Otherwise must be quiet. return MoveTypeQuiet; }
bool posMoveIsPromotion(const Pos *pos, Move move) { Piece fromPiece=posGetPieceOnSq(pos, moveGetFromSq(move)); bool result=(fromPiece!=moveGetToPiece(move)); assert(!result || pieceGetType(fromPiece)==PieceTypePawn); return result; }
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; }
PieceType moveGetToPieceType(Move move) { assert(moveIsValid(move)); return pieceGetType(moveGetToPiece(move)); }