int __generateSimpleMove(ChessMoveGenerator* self, ChessPiece* piece, int dRank, int dFile, int validate){ //returns 1 if the move was succesfull, //0 if it failed because of check, //and -1 if it failed because it was out of bounds/blocked ChessPiece* capture; int rank, file; location_t to; move_t move; rank = GET_RANK(piece->location)+dRank; file = GET_FILE(piece->location)+dFile; //if the move is in the board (0<=rank<8)&&(0<=file<8) if(((rank&7)==rank) && ((file&7)==file)){ to = RANK_FILE(rank,file); move = NEW_MOVE(piece->location, to); capture = self->board->squares[to]; if((capture!=NULL) && ((capture->color) != (self->toPlay))) move|=CAPTURE_MOVE_FLAG; else if(capture!=NULL) return -1; //the same color ChessBoard_makeMove(self->board, move); if(__finalizeAndUndo(self, validate)) return 1; else return 0; } return -1; }
char __getChar(ChessBoard* self, location_t loc){ assert(self!=NULL); assert(0<=loc); assert(loc<64); ChessPiece* piece = self->squares[loc]; if(piece==NULL) return ((GET_RANK(loc)^GET_FILE(loc))%2)?' ':'+'; return __getPieceChar(piece); }
void __generatePawnMoves(ChessMoveGenerator* self){ int i, rank, file; assert(self!=NULL); assert(self->curSet!=NULL); int size = self->curSet->piecesCounts[PAWN_INDEX]; int pawnDirection = self->toPlay==WHITE?1:-1; int pawnHomeRank = self->toPlay==WHITE?1:6; int lastRank = self->toPlay==WHITE?6:1; ChessPiece* pawn; move_t move; location_t to; //since the order of the pawns might change in the set //durring operations, we must store a local copy ChessPiece** pawns = (ChessPiece**)malloc( sizeof(ChessPiece*)*size); memcpy(pawns, self->curSet->piecesByType[PAWN_INDEX], sizeof(ChessPiece*)*size); for(i=0;i<size;i++){ pawn = pawns[i]; rank = GET_RANK(pawn->location); file = GET_FILE(pawn->location); //try to move forward to = RANK_FILE(rank+pawnDirection, file); if(self->board->squares[to]==NULL){ move = NEW_MOVE(pawn->location,to); if(rank==lastRank){ //generate promotions __generatePawnPromotions(self, move); } else{ //generate regular forward push ChessBoard_makeMove(self->board, move); if((__finalizeAndUndo(self, 1)||self->inCheck) && pawnHomeRank==rank){ to = RANK_FILE(rank+pawnDirection*2, file); if(self->board->squares[to]==NULL){ move = NEW_MOVE(pawn->location,to); move|=DOUBLE_PAWN_PUSH_MOVE; ChessBoard_makeMove(self->board, move); __finalizeAndUndo(self, self->inCheck); } } } } if(file>0){//try to capture left __generatePawnCapture(self, rank, file, pawnDirection, -1, lastRank); } if(file<7){//try to capture right __generatePawnCapture(self, rank, file, pawnDirection, 1, lastRank); } }//end for free(pawns); }
//Initializes pawn eval masks void Init_Pawn_Masks(void) { int index,rank,file,rank_index,file_index; //Clear all masks; for (index = 0; index < 64; index++) { white_passed_masks[index] = 0; black_passed_masks[index] = 0; isolated_masks[index] = 0; doubled_masks[index] = 0; } //For each square on the board for (index = 0; index < 64; index++) { rank = GET_RANK(index); file = GET_FILE(index); for (rank_index = RANK_1; rank_index <= RANK_8; rank_index++) { for (file_index = FILE_A; file_index <= FILE_H; file_index++) { //white passed mask //If file is neighboring and space is above index if (abs(file - file_index) <= 1 && rank_index > rank) { SET_BIT(white_passed_masks[index], RANK_FILE_TO_SQUARE(rank_index, file_index)); } //black passed mask //If file is neighboring and space is below index if (abs(file - file_index) <= 1 && rank_index < rank) { SET_BIT(black_passed_masks[index], RANK_FILE_TO_SQUARE(rank_index, file_index)); } //isolated mask //If file is neighboring and space is not equal to index if (abs(file - file_index) <= 1 && (file != file_index || rank != rank_index)) { SET_BIT(isolated_masks[index], RANK_FILE_TO_SQUARE(rank_index, file_index)); } //Doubled mask //If file is the same and rank is different if (file == file_index && rank != rank_index) { SET_BIT(doubled_masks[index], RANK_FILE_TO_SQUARE(rank_index, file_index)); } } } } }
void __generateDirectionalMoves(ChessMoveGenerator* self, ChessPiece* piece, int dRank, int dFile){ ChessPiece* capture; int rank, file; rank = GET_RANK(piece->location)+dRank; file = GET_FILE(piece->location)+dFile; int validated = 0; location_t to; move_t move; //while inside the board (0<=rank<8 && 0<=file<8) while(((rank&7)==rank) && ((file&7)==file)){ to = RANK_FILE(rank,file); capture = self->board->squares[to]; if(capture==NULL){ move = NEW_MOVE(piece->location, to); ChessBoard_makeMove(self->board, move); if(__finalizeAndUndo(self, (!validated)||self->inCheck)){ if(self->inCheck) break; //move blocks some directional check, //any further move in this direction //will not. validated = 1; } else if(!self->inCheck){ break; //move puts you in check, any move in //this direction will also put you in check } } else if(capture->color != self->toPlay){ move = NEW_MOVE(piece->location, to)|CAPTURE_MOVE_FLAG; ChessBoard_makeMove(self->board, move); __finalizeAndUndo(self, self->inCheck||(!validated)); break; } else break; //you hit your own piece rank+=dRank; file+=dFile; } }
void ChessBoard_makeMove(ChessBoard* self, move_t move){ //push the move onto the move stack GameInfo* info = (GameInfo*)self->extra; BoardBackup* backup = &(info->backups[info->movesCount]); backup->hash = self->hash; backup->flags = self->flags; backup->fiftyMoveCount = self->fiftyMoveCount; info->moves[info->movesCount++] = move; if(self->flags&TO_PLAY_FLAG) //black self->fiftyMoveCount++; __toggleToPlay(self); __clearEnPassantFlags(self); int meta = GET_META(move); location_t from = GET_FROM(move); location_t to = GET_TO(move); if((self->squares[from]->type==PAWN) || (meta&CAPTURE_MOVE_FLAG)) self->fiftyMoveCount=0; int rank, file; //do special moves switch(meta){ case DOUBLE_PAWN_PUSH_MOVE: __setEnPassantFlags(self, GET_FILE(to)); break; case KING_CASTLE_MOVE: case QUEEN_CASTLE_MOVE: rank = GET_RANK(from); if(meta==KING_CASTLE_MOVE) __movePieceByLoc(self, RANK_FILE(rank, 7), RANK_FILE(rank, 5)); else __movePieceByLoc(self, RANK_FILE(rank, 0), RANK_FILE(rank, 3)); if(rank==0){//white __unsetCastleFlag(self, WHITE_KING_CASTLE_FLAG); __unsetCastleFlag(self, WHITE_QUEEN_CASTLE_FLAG); } else{//black __unsetCastleFlag(self, BLACK_KING_CASTLE_FLAG); __unsetCastleFlag(self, BLACK_QUEEN_CASTLE_FLAG); } break; case EN_PASSANT_MOVE: rank = GET_RANK(from); file = GET_FILE(to); __capturePiece(self, self->squares[RANK_FILE(rank,file)]); break; default: if(meta&CAPTURE_MOVE_FLAG){ ChessPiece* captured = self->squares[to]; __capturePiece(self, captured); if(captured->type==ROOK){ switch(to){ case WHITE_QUEEN_ROOK_START: __unsetCastleFlag(self, WHITE_QUEEN_CASTLE_FLAG); break; case WHITE_KING_ROOK_START: __unsetCastleFlag(self, WHITE_KING_CASTLE_FLAG); break; case BLACK_QUEEN_ROOK_START: __unsetCastleFlag(self, BLACK_QUEEN_CASTLE_FLAG); break; case BLACK_KING_ROOK_START: __unsetCastleFlag(self, BLACK_KING_CASTLE_FLAG); break; } } } if(meta&PROMOTION_MOVE_FLAG){ ChessPiece* piece = self->squares[from]; __removePiece(self, piece); switch(meta&PROMOTION_MASK){ case QUEEN_PROMOTION: piece->type=QUEEN; break; case ROOK_PROMOTION: piece->type=ROOK; break; case KNIGHT_PROMOTION: piece->type=KNIGHT; break; case BISHOP_PROMOTION: piece->type=BISHOP; break; default: assert(0); } __addPiece(self, piece); } } if(meta==0 || meta==CAPTURE_MOVE_FLAG){ switch(from){ case WHITE_QUEEN_ROOK_START: __unsetCastleFlag(self, WHITE_QUEEN_CASTLE_FLAG); break; case WHITE_KING_ROOK_START: __unsetCastleFlag(self, WHITE_KING_CASTLE_FLAG); break; case WHITE_KING_START: __unsetCastleFlag(self, WHITE_QUEEN_CASTLE_FLAG); __unsetCastleFlag(self, WHITE_KING_CASTLE_FLAG); break; case BLACK_QUEEN_ROOK_START: __unsetCastleFlag(self, BLACK_QUEEN_CASTLE_FLAG); break; case BLACK_KING_ROOK_START: __unsetCastleFlag(self, BLACK_KING_CASTLE_FLAG); break; case BLACK_KING_START: __unsetCastleFlag(self, BLACK_QUEEN_CASTLE_FLAG); __unsetCastleFlag(self, BLACK_KING_CASTLE_FLAG); break; } } __movePieceByLoc(self, from, to); }
void toAlgebraicNotation(move_t move, ChessBoard* board, char* out, int* outSize){ location_t from = GET_FROM(move); location_t to = GET_TO(move); int meta = GET_META(move); int i = 0; ChessBoard_makeMove(board, move); int isInCheck = ChessBoard_testForCheck(board); ChessMoveGenerator* gen = ChessMoveGenerator_new(board); ChessMoveGenerator_generateMoves(gen, isInCheck, NULL); int isInCheckmate = isInCheck&&(gen->nextCount==0); ChessBoard_unmakeMove(board); ChessMoveGenerator_generateMoves(gen, ChessBoard_testForCheck(board), NULL); if(meta==KING_CASTLE_MOVE){ char* notation = "O-O"; for(i = 0; i < 3; i++) out[i] = notation[i]; } else if(meta==QUEEN_CASTLE_MOVE){ char* notation = "O-O-O"; for(i = 0; i < 5; i++) out[i] = notation[i]; } else{ //write piece indicator ChessPiece* piece = board->squares[from]; if(piece->type==KING) out[i++] = 'K'; else{ //for each other move, //check to see if there are multiple pieces //of this piece's type that can move to the 'to' square. int j; move_t otherMoves[20]; int otherMovesCount = 0; move_t otherMove; for(j = 0; j < gen->nextCount; j++){ otherMove = gen->next[j]; if((GET_TO(otherMove)==to) && (GET_FROM(otherMove)!=from) && (board->squares[GET_FROM(otherMove)]->type== piece->type)){ if(piece->type==PAWN && (move&CAPTURE_MOVE_FLAG)!= (otherMove&CAPTURE_MOVE_FLAG)) continue; if(otherMove==move) continue; otherMoves[otherMovesCount++] = otherMove; } } //note if there are multiple moves //from the same rank or file int sameRank = 0, sameFile = 0; for(j = 0; j < otherMovesCount; j++){ otherMove = otherMoves[j]; if(GET_RANK(from)==GET_RANK(GET_FROM(otherMove))) sameRank = 1; if(GET_FILE(from)==GET_FILE(GET_FROM(otherMove))) sameFile = 1; } if(piece->type!=PAWN) out[i++] = __pieceTypeToChar(piece->type); else if(meta&CAPTURE_MOVE_FLAG) out[i++] = __fileToChar(GET_FILE(from)); if(piece->type!=PAWN && otherMovesCount){ if(!sameFile) out[i++] = __fileToChar(GET_FILE(from)); else if(!sameRank) out[i++] = __rankToChar(GET_RANK(from)); else{ out[i++] = __fileToChar(GET_FILE(from)); out[i++] = __rankToChar(GET_RANK(from)); } } } //if capture if(meta&CAPTURE_MOVE_FLAG) out[i++] = 'x'; //write destination out[i++] = __fileToChar(GET_FILE(to)); out[i++] = __rankToChar(GET_RANK(to)); if(meta&PROMOTION_MOVE_FLAG){ out[i++] = '='; switch(meta&PROMOTION_MASK){ case KNIGHT_PROMOTION: out[i++] = 'N'; break; case BISHOP_PROMOTION: out[i++] = 'B'; break; case ROOK_PROMOTION: out[i++] = 'R'; break; case QUEEN_PROMOTION: out[i++] = 'Q'; break; default: assert(0); } } } if(isInCheckmate) out[i++] = '#'; else if(isInCheck) out[i++] = '+'; out[i] = '\0'; (*outSize) = i; ChessMoveGenerator_delete(gen); }
int __testForCheck(ChessBoard* board, color_e color){ GameInfo* info = (GameInfo*)board->extra; ChessPieceSet* pieces = info->pieceSets[color]; ChessPieceSet* opPieces = info->pieceSets[OTHER_COLOR(color)]; ChessPiece* king = pieces->piecesByType[TYPE_TO_INT(KING)][0]; int kingRank, kingFile; kingRank = GET_RANK(king->location); kingFile = GET_FILE(king->location); //test for check by a pawn if((color==WHITE && kingRank<6) || (color==BLACK && kingRank>1)){ int opPawnDirection = color==WHITE?-1:1; int pawnRank = kingRank-opPawnDirection; ChessPiece* pawn; if(kingFile>0){ pawn = board->squares[RANK_FILE(pawnRank, kingFile-1)]; if((pawn!=NULL) && (pawn->type==PAWN) && (pawn->color!=color)){ return 1; } } if(kingFile<7){ pawn = board->squares[RANK_FILE(pawnRank, kingFile+1)]; if((pawn!=NULL) && (pawn->type==PAWN) && (pawn->color!=color)){ return 1; } } } //test for check by knight int i, rankDelta, fileDelta, rank, file; int size = opPieces->piecesCounts[KNIGHT_INDEX]; ChessPiece* knight; for(i=0; i<size; i++){ knight = opPieces->piecesByType[KNIGHT_INDEX][i]; rankDelta = kingRank-GET_RANK(knight->location); fileDelta = kingFile-GET_FILE(knight->location); if((rankDelta*rankDelta+fileDelta*fileDelta)==5) return 1; } //test for check by bishop size = opPieces->piecesCounts[BISHOP_INDEX]; ChessPiece* bishop; for(i=0; i<size; i++){ bishop = opPieces->piecesByType[BISHOP_INDEX][i]; rankDelta = kingRank-GET_RANK(bishop->location); fileDelta = kingFile-GET_FILE(bishop->location); if(rankDelta*rankDelta == fileDelta*fileDelta){ //the king is on a diagonal with this opposing bishop //check every square inbetween to see if the bishop //is blocked assert(rankDelta!=0); rankDelta = rankDelta>0?1:-1; fileDelta = fileDelta>0?1:-1; rank = GET_RANK(bishop->location)+rankDelta; file = GET_FILE(bishop->location)+fileDelta; while(rank!=kingRank){ if(board->squares[RANK_FILE(rank,file)]!=NULL) break; rank+=rankDelta; file+=fileDelta; } if(rank==kingRank) return 1; } } //test for check by rook size = opPieces->piecesCounts[TYPE_TO_INT(ROOK)]; ChessPiece* rook; for(i=0; i<size; i++){ rook = opPieces->piecesByType[TYPE_TO_INT(ROOK)][i]; rankDelta = kingRank-GET_RANK(rook->location); fileDelta = kingFile-GET_FILE(rook->location); if((rankDelta == 0)||(fileDelta == 0)){ //the king is on a rank or a file with this opposing rook //check every square inbetween to see if the rook //is blocked if(fileDelta!=0) fileDelta = fileDelta>0?1:-1; if(rankDelta!=0) rankDelta = rankDelta>0?1:-1; rank = GET_RANK(rook->location)+rankDelta; file = GET_FILE(rook->location)+fileDelta; while(rank!=kingRank || file!=kingFile){ if(board->squares[RANK_FILE(rank,file)]!=NULL) break; rank+=rankDelta; file+=fileDelta; } if(rank==kingRank && file==kingFile){ return 1; } } } //test for check by queen size = opPieces->piecesCounts[TYPE_TO_INT(QUEEN)]; ChessPiece* queen; for(i=0; i<size; i++){ queen = opPieces->piecesByType[TYPE_TO_INT(QUEEN)][i]; rankDelta = kingRank-GET_RANK(queen->location); fileDelta = kingFile-GET_FILE(queen->location); if((rankDelta*rankDelta == fileDelta*fileDelta)|| (rankDelta == 0)||(fileDelta == 0)){ //the king is on a diagonal, rank or file with //this opposing queen, check every square //inbetween to see if the queen is blocked if(fileDelta!=0) fileDelta = fileDelta>0?1:-1; if(rankDelta!=0) rankDelta = rankDelta>0?1:-1; rank = GET_RANK(queen->location)+rankDelta; file = GET_FILE(queen->location)+fileDelta; while(rank!=kingRank || file!=kingFile){ if(board->squares[RANK_FILE(rank,file)]!=NULL){ break; } rank+=rankDelta; file+=fileDelta; } if(rank==kingRank && file==kingFile){ return 1; } } } //test for check by other king //for hypothetical moves that are blocked //by the opposing king ChessPiece* opKing = opPieces->piecesByType[TYPE_TO_INT(KING)][0]; rankDelta = kingRank-GET_RANK(opKing->location); fileDelta = kingFile-GET_FILE(opKing->location); if((rankDelta*rankDelta+fileDelta*fileDelta)<=2){ return 1; } //Otherwise, the king is not in check return 0; }
//Looks at pawn shielding around each king and returns white - black score int Get_King_Safety_Score(BOARD_STRUCT *board) { int white_score = 0; int black_score = 0; U64 temp = board->piece_bitboards[wK]; int white_king_square = pop_1st_bit(&temp); temp = board->piece_bitboards[bK]; int black_king_square = pop_1st_bit(&temp); //White king on kingside if (GET_FILE(white_king_square) > FILE_E && GET_RANK(white_king_square) == RANK_1) { if (board->board_array[F2] == wP) white_score += PAWN_SHIELD_SCORE; else if (board->board_array[F3] == wP) white_score += PAWN_SHIELD_SCORE / 2; if (board->board_array[G2] == wP) white_score += PAWN_SHIELD_SCORE; else if (board->board_array[G3] == wP) white_score += PAWN_SHIELD_SCORE / 2; if (board->board_array[H2] == wP) white_score += PAWN_SHIELD_SCORE; else if (board->board_array[H3] == wP) white_score += PAWN_SHIELD_SCORE / 2; } else if (GET_FILE(white_king_square) < FILE_D && GET_RANK(white_king_square) == RANK_1) { if (board->board_array[A2] == wP) white_score += PAWN_SHIELD_SCORE; else if (board->board_array[A3] == wP) white_score += PAWN_SHIELD_SCORE / 2; if (board->board_array[B2] == wP) white_score += PAWN_SHIELD_SCORE; else if (board->board_array[B3] == wP) white_score += PAWN_SHIELD_SCORE / 2; if (board->board_array[C2] == wP) white_score += PAWN_SHIELD_SCORE; else if (board->board_array[C3] == wP) white_score += PAWN_SHIELD_SCORE / 2; } //Black king on kingside if (GET_FILE(black_king_square) > FILE_E && GET_RANK(black_king_square) == RANK_8) { if (board->board_array[F7] == bP) black_score += PAWN_SHIELD_SCORE; else if (board->board_array[F6] == bP) black_score += PAWN_SHIELD_SCORE / 2; if (board->board_array[G7] == bP) black_score += PAWN_SHIELD_SCORE; else if (board->board_array[G6] == bP) black_score += PAWN_SHIELD_SCORE / 2; if (board->board_array[H7] == bP) black_score += PAWN_SHIELD_SCORE; else if (board->board_array[H6] == bP) black_score += PAWN_SHIELD_SCORE / 2; } else if (GET_FILE(black_king_square) < FILE_D && GET_RANK(black_king_square) == RANK_8) { if (board->board_array[A7] == bP) black_score += PAWN_SHIELD_SCORE; else if (board->board_array[A6] == bP) black_score += PAWN_SHIELD_SCORE / 2; if (board->board_array[B7] == bP) black_score += PAWN_SHIELD_SCORE; else if (board->board_array[B6] == bP) black_score += PAWN_SHIELD_SCORE / 2; if (board->board_array[C7] == bP) black_score += PAWN_SHIELD_SCORE; else if (board->board_array[C6] == bP) black_score += PAWN_SHIELD_SCORE / 2; } return white_score - black_score; }