public Boolean InCheck(int sideToMove) { int kingsq = King[sideToMove].BitScanForward(); int xside = sideToMove ^ 1; if ((MoveGenerator.BishopAttacks(this, kingsq) & (Bishops[xside] | Queens[xside])) > 0) return true; else if ((MoveGenerator.RookAttacks(this, kingsq) & (Rooks[xside] | Queens[xside])) > 0) return true; else if ((MoveGenerator.PawnAttacks[sideToMove, kingsq] & Pawns[xside]) > 0) return true; else if ((MoveGenerator.KnightMoves[kingsq] & Knights[xside]) > 0) return true; else if ((MoveGenerator.KingMoves[kingsq] & King[xside]) > 0) return true; return false; }
public string ToAlegbraicNotation(Board b) { //find Piece String output = String.Empty; MoveBits bits = 0; if ((b.Knights[b.SideToMove] & BitMask.Mask[From]) > 0) { bits = MoveBits.Knight; } else if ((b.Bishops[b.SideToMove] & BitMask.Mask[From]) > 0) { bits = MoveBits.Bishop; } else if ((b.Rooks[b.SideToMove] & BitMask.Mask[From]) > 0) { bits = MoveBits.Rook; } else if ((b.Queens[b.SideToMove] & BitMask.Mask[From]) > 0) { bits = MoveBits.Queen; } else if ((b.Pawns[b.SideToMove] & BitMask.Mask[From]) > 0) { bits = MoveBits.Pawn; } else if ((b.King[b.SideToMove] & BitMask.Mask[From]) > 0) { bits = MoveBits.King; } if (bits == MoveBits.Pawn) { if ((Bits & (byte)MoveBits.Capture) > 0) { output += outputFiles[From.File()]; } } else if (bits == MoveBits.Knight) { output += 'N'; var sqs = MoveGenerator.KnightMoves[To] & b.Knights[b.SideToMove]; if ((sqs).Count() > 1) { output += FileOrRank(b, bits); } } else if (bits == MoveBits.Bishop) { output += 'B'; var sqs = MoveGenerator.BishopAttacks(b, To) & b.Bishops[b.SideToMove]; if (sqs.Count() > 1) { output += FileOrRank(b, bits); } } else if (bits == MoveBits.Rook) { output += 'R'; var sqs = MoveGenerator.RookAttacks(b, To) & b.Rooks[b.SideToMove]; if (sqs.Count() > 1) { output += FileOrRank(b, bits); } } else if (bits == MoveBits.Queen) { var sqs = MoveGenerator.QueenAttacks(b, To) & b.Queens[b.SideToMove]; output += 'Q'; if (sqs.Count() > 1) { output += FileOrRank(b, bits); } } else if (bits == MoveBits.King) { //if we are castling if (Math.Abs(To.File() - From.File()) > 1) { if (To == 6 || To == 62) { return("O-O"); } else { return("O-O-O"); } } output += 'K'; } else { output = Board.SquareNames[From]; } if ((Bits & (byte)MoveBits.Capture) > 0) { output += 'x'; } output += Board.SquareNames[To]; if (Promotion > 0) { output += "="; switch ((Piece)Promotion) { case Piece.Knight: output += "N"; break; case Piece.Bishop: output += "B"; break; case Piece.Rook: output += "R"; break; case Piece.Queen: output += "Q"; break; } } b.MakeMove(this); if (b.InCheck(b.SideToMove)) { output += "+"; } b.UnMakeMove(); return(output); }
//evaluates exchanges on a square initiated by stm public static int Eval(Board b, Move m, int stm) { ulong[] attackers = new ulong[2]; int score = 0; var sq = m.To; var pieceVal = Evaluator.PieceValueOnSquare(b, sq); var attacks = MoveGenerator.Attacks(b, sq); var mystm = stm ^ 1; attackers[mystm] = attacks & b.Pieces[mystm]; attackers[stm] = attacks & b.Pieces[stm]; //change the pieceVal to be the new piece //if there is a promotion, then stm is already up material if (m.Promotion > 0) { pieceVal = Evaluator.PieceValues[m.Promotion]; score = pieceVal - 100; //lose the initial pawn } else { pieceVal = Evaluator.PieceValues[(int)Move.GetPiece((MoveBits)m.Bits)]; } //add in any material taken on the first capture if ((m.Bits & (byte)MoveBits.Capture) > 0) { score += Evaluator.PieceValueOnSquare(b, m.To); } //remove the first Move, unless this was a straight pawn push if (!((m.Bits & (byte)MoveBits.Pawn) > 0 && Math.Abs(m.From - m.To) == 8)) { attackers[stm] ^= BitMask.Mask[m.From]; } while (attackers[mystm] > 0) { var tempAttackers = attackers[mystm]; var leastValuable = int.MaxValue; int leastValSq = -1; bool promote, promoting = false; //make a pass over the attackers to find the lowest valued piece while (tempAttackers > 0) { promote = false; var attack_sq = tempAttackers.BitScanForward(); tempAttackers ^= BitMask.Mask[attack_sq]; var attackerVal = Evaluator.PieceValueOnSquare(b, attack_sq); //if we found a pawn capturing onto the 8th rank, we need to consider promotion if (attackerVal == 100 && (sq.Rank() == 0 || sq.Rank() == 7)) { //we will treat this attacker as if it were a queen attackerVal = Evaluator.PieceValues[(int)Piece.Queen]; promote = true; } if (attackerVal < leastValuable) { promoting = promote; leastValSq = attack_sq; leastValuable = attackerVal; } } //now we have the least valuable attacker //remove whatever value is on the square if (mystm == stm) { score += pieceVal; if (promoting) { score += leastValuable - 100;//lose the promoting pawn, add in queen } } else { score -= pieceVal; if (promoting) { score -= leastValuable + 100;//lose the promoting pawn, add in queen } } //update the attacked piece pieceVal = leastValuable; //remove the attacker attackers[mystm] ^= BitMask.Mask[leastValSq]; //now we check for x-ray attacks //the idea here is that if any rooks, queens, or bishops attack the temporary //square from the same direction that the temporary square is attacking the target //then we have an xray attacker var direction = MoveGenerator.Directions[leastValSq, sq]; ulong xrayAttacks = 0; switch (Math.Abs(direction)) { case 1: case 8: if (((b.Rooks[mystm] | b.Queens[mystm]) & Board.FileMask[sq.File()]) > 0) { xrayAttacks = MoveGenerator.RookAttacks(b, leastValSq) & (b.Rooks[mystm] | b.Queens[mystm]) & attackers[mystm]; } break; case 7: case 9: xrayAttacks = MoveGenerator.BishopAttacks(b, leastValSq) & (b.Bishops[mystm] | b.Queens[mystm]) & attackers[mystm]; break; } while (xrayAttacks > 0) { var xraySq = xrayAttacks.BitScanForward(); xrayAttacks ^= BitMask.Mask[xraySq]; if (MoveGenerator.Directions[xraySq, sq] == direction) { //put this piece in main attackers bitboard attackers[mystm] |= BitMask.Mask[xraySq]; } } //switch stm mystm ^= 1; } return(score); }
static int EvaluatePieces(Evaluation e) { //evaluate things like material imbalance, //bishop pair, knights supported by pawns, etc. int[] eval = new int[2]; for (int side = 0; side < 2; side++) { int xside = side ^ 1; //evaluate material imbalances // a rook+pawn for two pieces is not good //if side has only one rook and opponent has two if (e.Board.Rooks[side] > 0 && e.Board.Rooks[xside] > 0 && e.Board.Rooks[side].Count() == 1 && e.Board.Rooks[xside].Count() == 2) { //if opposite side has two less minors then we get a bonus if (e.Board.Minors(side).Count() - e.Board.Minors(xside).Count() == 2) { eval[side] += MinorMaterialInbalanceBonus; } } //bishop pair bonus eval[side] += (e.Board.Bishops[side].Count() == 2) ? BishopPairBonus : 0; //increase the value of rooks as pawns come off the board int totalPawns = e.Board.Pawns[0].Count() + e.Board.Pawns[1].Count(); eval[side] += RookBonusPawnCount[totalPawns]; //rooks var rooks = e.Board.Rooks[side]; while (rooks > 0) { int sq = rooks.BitScanForward(); rooks ^= BitMask.Mask[sq]; //open file bonus if (e.PawnScore.Files[side, sq.File()] == 0) { eval[side] += RookOnOpenFileBonus / 2; if (e.PawnScore.Files[xside, sq.File()] == 0) { eval[side] = RookOnOpenFileBonus; } } //rooks on the seventh (or eigth) if (side == 0 && sq.Rank() <= 1) { eval[0] += RookOnSeventhBonus; } else if (side == 1 && sq.Rank() >= 6) { eval[1] += RookOnSeventhBonus; } } //knights var knights = e.Board.Knights[side]; while (knights > 0) { int sq = knights.BitScanForward(); knights ^= BitMask.Mask[sq]; //only looking for forward knights if (side == 0 && sq.Rank() > 3) { continue; } else if (side == 1 && sq.Rank() < 3) { continue; } //look for knights on outposts if ((MoveGenerator.PawnAttacks[xside, sq] & e.Board.Pawns[side]) > 0) { //knight is defended by a pawn //use the passed pawn lookup - minus the file to see if //we have an ouput if ((PassedPawnMask[side, sq] & ~Board.FileMask[sq.File()] & e.Board.Pawns[xside]) == 0) { eval[side] += KnightOnOutpostBonus; } } EvalTrappedKnights(e, eval, side, sq); } var bishops = e.Board.Bishops[side]; while (bishops > 0) { int sq = bishops.BitScanForward(); bishops ^= BitMask.Mask[sq]; //evaluate trapped bishops if (side == 0) { if (sq == 23 && //white bishop on h6 (e.Board.Pawns[1] & BitMask.Mask[30]) > 0 && (e.Board.Pawns[1] & BitMask.Mask[21]) > 0) { eval[side] -= PieceValues[(int)Piece.Bishop] / 3; } else if (sq == 16 && //white bishop on a6 (e.Board.Pawns[1] & BitMask.Mask[25]) > 0 && (e.Board.Pawns[1] & BitMask.Mask[18]) > 0) { eval[side] -= PieceValues[(int)Piece.Bishop] / 3; } } else { if (sq == 47 && //blackbishop on h3 (e.Board.Pawns[0] & BitMask.Mask[38]) > 0 && (e.Board.Pawns[0] & BitMask.Mask[47]) > 0) { eval[side] -= PieceValues[(int)Piece.Bishop] / 3; } else if (sq == 40 && //black bishop on a3 (e.Board.Pawns[0] & BitMask.Mask[33]) > 0 && (e.Board.Pawns[0] & BitMask.Mask[42]) > 0) { eval[side] -= PieceValues[(int)Piece.Bishop] / 3; } } //mobility score var mobilitySquares = MoveGenerator.BishopAttacks(e.Board, sq); eval[side] += mobilitySquares.Count(); } } return(eval[e.Board.SideToMove] - eval[e.Board.SideToMove ^ 1]); }