update
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
#include <iostream>
|
||||||
#include "BasicEngine.hpp"
|
#include "BasicEngine.hpp"
|
||||||
#include "Search.hpp"
|
#include "Search.hpp"
|
||||||
|
|
||||||
@@ -16,5 +17,6 @@ void BasicEngine::newGame() {
|
|||||||
PrincipalVariation BasicEngine::pv(const Board &board, const TimeInfo::Optional &timeInfo) {
|
PrincipalVariation BasicEngine::pv(const Board &board, const TimeInfo::Optional &timeInfo) {
|
||||||
(void)board;
|
(void)board;
|
||||||
(void)timeInfo;
|
(void)timeInfo;
|
||||||
return Search::start(board);
|
auto pv =Search::start(board);
|
||||||
|
return pv;
|
||||||
}
|
}
|
@@ -39,6 +39,9 @@ public:
|
|||||||
explicit constexpr operator bool() const {
|
explicit constexpr operator bool() const {
|
||||||
return mBoard != 0;
|
return mBoard != 0;
|
||||||
}
|
}
|
||||||
|
explicit constexpr operator unsigned int() const {
|
||||||
|
return mBoard;
|
||||||
|
}
|
||||||
explicit constexpr operator unsigned long() const {
|
explicit constexpr operator unsigned long() const {
|
||||||
return mBoard;
|
return mBoard;
|
||||||
}
|
}
|
||||||
@@ -125,6 +128,7 @@ public:
|
|||||||
// WARN: Check for 0!
|
// WARN: Check for 0!
|
||||||
unsigned lsb() const;
|
unsigned lsb() const;
|
||||||
unsigned pop();
|
unsigned pop();
|
||||||
|
constexpr int count() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
U64 mBoard = 0;
|
U64 mBoard = 0;
|
||||||
@@ -282,4 +286,9 @@ inline unsigned BitBoard::pop() {
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr int BitBoard::count() const {
|
||||||
|
return __builtin_popcountll(mBoard);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif //CHESS_ENGINE_BITBOARD_HPP
|
#endif //CHESS_ENGINE_BITBOARD_HPP
|
||||||
|
15
Board.cpp
15
Board.cpp
@@ -40,19 +40,18 @@ int Board::evaluate() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Board::evaluate(const PieceColor color) const {
|
int Board::evaluate(const PieceColor color) const {
|
||||||
// Pawns
|
|
||||||
int score = 0;
|
int score = 0;
|
||||||
|
|
||||||
BitBoard bb;
|
BitBoard bb;
|
||||||
BitBoard colorMask = mPieceBBs[toIndex(color)];
|
BitBoard colorMask = mPieceBBs[toIndex(color)];
|
||||||
for (int i = 2; i < 8; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
bb = mPieceBBs[i] & colorMask;
|
bb = mPieceBBs[i+2] & colorMask;
|
||||||
while (bb) {
|
score += Piece::PieceValue[i] * bb.count();
|
||||||
bb.pop();
|
|
||||||
score += mPieceValue[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BoardState bs = BoardState(&mPieceBBs, mOccupiedBB, mTurn, mCR, mEPS);
|
||||||
|
// score += round(mMobilityWeight * MoveGenerator::Mobility(bs, color));
|
||||||
|
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,8 +66,6 @@ bool Board::isCheckMate() const {
|
|||||||
auto attacked = MoveGenerator::generateAttackedSquares(bs, ~mOccupiedBB, !mTurn);
|
auto attacked = MoveGenerator::generateAttackedSquares(bs, ~mOccupiedBB, !mTurn);
|
||||||
|
|
||||||
return attacked & mPieceBBs[toIndex(PieceType::King)] & mPieceBBs[toIndex(mTurn)];
|
return attacked & mPieceBBs[toIndex(PieceType::King)] & mPieceBBs[toIndex(mTurn)];
|
||||||
|
|
||||||
return moves.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Board::setTurn(PieceColor turn) {
|
void Board::setTurn(PieceColor turn) {
|
||||||
|
@@ -57,7 +57,7 @@ private:
|
|||||||
CastlingRights mCR = CastlingRights::None;
|
CastlingRights mCR = CastlingRights::None;
|
||||||
std::optional<Square> mEPS;
|
std::optional<Square> mEPS;
|
||||||
|
|
||||||
constexpr static const int mPieceValue[8] = {0,0, 100, 350, 350, 525, 1000, 10000};
|
constexpr static const double mMobilityWeight = 0.1;
|
||||||
|
|
||||||
void handleCastlingRights(const Piece &piece, const BitBoard &bb);
|
void handleCastlingRights(const Piece &piece, const BitBoard &bb);
|
||||||
|
|
||||||
|
@@ -5,6 +5,8 @@
|
|||||||
#include "BitBoard.hpp"
|
#include "BitBoard.hpp"
|
||||||
#include "Board.hpp"
|
#include "Board.hpp"
|
||||||
|
|
||||||
|
#define BB_NUM 8
|
||||||
|
|
||||||
struct BoardState {
|
struct BoardState {
|
||||||
BoardState(const BitBoard (*const pieceBBs)[8],
|
BoardState(const BitBoard (*const pieceBBs)[8],
|
||||||
const BitBoard occupiedBB,
|
const BitBoard occupiedBB,
|
||||||
@@ -24,6 +26,17 @@ struct BoardState {
|
|||||||
const PieceColor turn;
|
const PieceColor turn;
|
||||||
const CastlingRights cr;
|
const CastlingRights cr;
|
||||||
const std::optional<Square> eps;
|
const std::optional<Square> eps;
|
||||||
|
|
||||||
|
inline PieceType pieceType(const BitBoard &mask) const {
|
||||||
|
for (int i = 2; i < BB_NUM; i++) {
|
||||||
|
if ((*pieceBBs)[i] & mask) {
|
||||||
|
return static_cast<PieceType>(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should not happen
|
||||||
|
return static_cast<PieceType>(0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //CHESS_ENGINE_BOARDSTATE_HPP
|
#endif //CHESS_ENGINE_BOARDSTATE_HPP
|
||||||
|
39
Move.cpp
39
Move.cpp
@@ -3,10 +3,21 @@
|
|||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
Move::Move(const Square &from, const Square &to, const std::optional<PieceType> &promotion)
|
|
||||||
: mFrom(from), mTo(to), mPromotion(promotion) {
|
Move::Move(const Square &from, const Square &to) : mFrom(from), mTo(to) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Move::Move(const Square &from, const Square &to, const std::optional<PieceType> &promotion, unsigned score)
|
||||||
|
: mFrom(from), mTo(to), mPromotion(promotion) {
|
||||||
|
mScore -= score;
|
||||||
|
}
|
||||||
|
|
||||||
|
Move::Move(const Square &from, const Square &to, unsigned int score) : mFrom(from), mTo(to) {
|
||||||
|
mScore -= score;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Move::Optional Move::fromUci(const std::string &uci) {
|
Move::Optional Move::fromUci(const std::string &uci) {
|
||||||
if (uci.length() < 4 || uci.length() > 5)
|
if (uci.length() < 4 || uci.length() > 5)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@@ -48,17 +59,31 @@ std::ostream &operator<<(std::ostream &os, const Move &move) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const Move &lhs, const Move &rhs) {
|
bool operator<(const Move &lhs, const Move &rhs) {
|
||||||
if (!(lhs.from() == rhs.from()))
|
if (lhs.mScore != rhs.mScore) {
|
||||||
return lhs.from() < rhs.from();
|
return lhs.mScore < rhs.mScore;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(lhs.to() == rhs.to()))
|
if (lhs.mFrom.index() != rhs.mFrom.index()) {
|
||||||
return lhs.to() < rhs.to();
|
return lhs.mFrom.index() < rhs.mFrom.index();
|
||||||
|
}
|
||||||
|
if (lhs.mTo.index() != rhs.mTo.index()) {
|
||||||
|
return lhs.mTo.index() < rhs.mTo.index();
|
||||||
|
}
|
||||||
|
|
||||||
return lhs.promotion() < rhs.promotion();
|
return lhs.promotion() < rhs.promotion();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const Move &lhs, const Move &rhs) {
|
bool operator==(const Move &lhs, const Move &rhs) {
|
||||||
return lhs.from() == rhs.from()
|
return lhs.score() == rhs.score()
|
||||||
|
&& lhs.from() == rhs.from()
|
||||||
&& lhs.to() == rhs.to()
|
&& lhs.to() == rhs.to()
|
||||||
&& lhs.promotion() == rhs.promotion();
|
&& lhs.promotion() == rhs.promotion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int Move::score() const {
|
||||||
|
return mScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Move::setScore(unsigned int score) {
|
||||||
|
mScore = score;
|
||||||
|
}
|
||||||
|
20
Move.hpp
20
Move.hpp
@@ -7,14 +7,17 @@
|
|||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
class Move {
|
class Move {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using Optional = std::optional<Move>;
|
using Optional = std::optional<Move>;
|
||||||
|
|
||||||
Move(const Square &from, const Square &to,
|
explicit Move(const Square &from, const Square &to);
|
||||||
const std::optional<PieceType> &promotion = std::nullopt);
|
explicit Move(const Square &from, const Square &to,
|
||||||
|
const std::optional<PieceType> &promotion, unsigned score = 0);
|
||||||
|
explicit Move(const Square &from, const Square &to, unsigned score);
|
||||||
|
|
||||||
static Optional fromUci(const std::string &uci);
|
static Optional fromUci(const std::string &uci);
|
||||||
|
|
||||||
@@ -22,16 +25,23 @@ public:
|
|||||||
Square to() const;
|
Square to() const;
|
||||||
std::optional<PieceType> promotion() const;
|
std::optional<PieceType> promotion() const;
|
||||||
|
|
||||||
|
|
||||||
|
friend bool operator<(const Move &lhs, const Move &rhs);
|
||||||
|
friend bool operator==(const Move &lhs, const Move &rhs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Square mFrom;
|
Square mFrom;
|
||||||
Square mTo;
|
Square mTo;
|
||||||
std::optional<PieceType> mPromotion;
|
std::optional<PieceType> mPromotion = std::nullopt;
|
||||||
|
unsigned mScore = std::numeric_limits<unsigned>::max();
|
||||||
|
public:
|
||||||
|
unsigned int score() const;
|
||||||
|
|
||||||
|
void setScore(unsigned int mScore);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &os, const Move &move);
|
std::ostream &operator<<(std::ostream &os, const Move &move);
|
||||||
|
|
||||||
// Needed for std::map, std::set
|
// Needed for std::map, std::set
|
||||||
bool operator<(const Move &lhs, const Move &rhs);
|
|
||||||
bool operator==(const Move &lhs, const Move &rhs);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -31,7 +31,7 @@ void MoveGenerator::generatePawnMoves(const BoardState &bs, const Square &from,
|
|||||||
if (isPromotion) {
|
if (isPromotion) {
|
||||||
generateMovesWithPromotion(bs, from, movesBB, moves);
|
generateMovesWithPromotion(bs, from, movesBB, moves);
|
||||||
} else {
|
} else {
|
||||||
generateMoves(bs, from, movesBB, moves);
|
generateMoves(bs, from, movesBB, PieceType::Pawn, moves);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,34 +39,42 @@ void MoveGenerator::generateBishopMoves(const BoardState &bs, const Square &from
|
|||||||
auto fromBB = BitBoard::fromIndex(from.index());
|
auto fromBB = BitBoard::fromIndex(from.index());
|
||||||
auto movesBB = BitBoard::bishopAttacks(fromBB, ~bs.occupiedBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)];
|
auto movesBB = BitBoard::bishopAttacks(fromBB, ~bs.occupiedBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)];
|
||||||
|
|
||||||
generateMoves(bs, from, movesBB, moves);
|
generateMoves(bs, from, movesBB, PieceType::Bishop, moves);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveGenerator::generateMoves(const BoardState &bs, const Square &from, BitBoard movesBB, MoveVec &moves) {
|
void
|
||||||
|
MoveGenerator::generateMoves(const BoardState &bs, const Square &from, BitBoard movesBB, PieceType pt, MoveVec &moves) {
|
||||||
auto fromBB = BitBoard::fromIndex(from.index());
|
auto fromBB = BitBoard::fromIndex(from.index());
|
||||||
while (movesBB) {
|
while (movesBB) {
|
||||||
auto to = Square(movesBB.pop());
|
auto to = Square(movesBB.pop());
|
||||||
if (isCheck(bs, fromBB, to)) {
|
auto toBB = BitBoard::fromIndex(to.index());
|
||||||
|
if (isCheck(bs, fromBB, toBB)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
moves.emplace_back(from, to);
|
|
||||||
|
moves.emplace_back(from, to, score(bs, toBB, pt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveGenerator::generateMovesWithPromotion(const BoardState &bs, const Square &from, BitBoard movesBB, MoveVec &moves) {
|
void
|
||||||
|
MoveGenerator::generateMovesWithPromotion(const BoardState &bs, const Square &from, BitBoard movesBB, MoveVec &moves) {
|
||||||
auto fromBB = BitBoard::fromIndex(from.index());
|
auto fromBB = BitBoard::fromIndex(from.index());
|
||||||
while (movesBB) {
|
while (movesBB) {
|
||||||
auto to = Square(movesBB.pop());
|
auto to = Square(movesBB.pop());
|
||||||
if (isCheck(bs, fromBB, to)) {
|
auto toBB = BitBoard::fromIndex(to.index());
|
||||||
|
if (isCheck(bs, fromBB, toBB)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &kItem: Piece::PromotionTypes) {
|
for (const auto &kItem: Piece::PromotionTypes) {
|
||||||
moves.emplace_back(from, to, static_cast<PieceType>(kItem));
|
|
||||||
|
unsigned s = Piece::PromotionScore[Board::toIndex(kItem) - 2] + score(bs, toBB, PieceType::Pawn);
|
||||||
|
moves.emplace_back(from, to, static_cast<PieceType>(kItem), s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveGenerator::generateKingMoves(const BoardState &bs, const Square &from, MoveGenerator::MoveVec &moves) {
|
void MoveGenerator::generateKingMoves(const BoardState &bs, const Square &from, MoveGenerator::MoveVec &moves) {
|
||||||
auto fromBB = BitBoard::fromIndex(from.index());
|
auto fromBB = BitBoard::fromIndex(from.index());
|
||||||
auto movesBB = BitBoard::kingMoves(fromBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)];
|
auto movesBB = BitBoard::kingMoves(fromBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)];
|
||||||
@@ -100,28 +108,28 @@ void MoveGenerator::generateKingMoves(const BoardState &bs, const Square &from,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
generateMoves(bs, from, movesBB, moves);
|
generateMoves(bs, from, movesBB, PieceType::King, moves);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveGenerator::generateRookMoves(const BoardState &bs, const Square &from, MoveVec &moves) {
|
void MoveGenerator::generateRookMoves(const BoardState &bs, const Square &from, MoveVec &moves) {
|
||||||
auto fromBB = BitBoard::fromIndex(from.index());
|
auto fromBB = BitBoard::fromIndex(from.index());
|
||||||
auto movesBB = BitBoard::rookAttacks(fromBB, ~bs.occupiedBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)];
|
auto movesBB = BitBoard::rookAttacks(fromBB, ~bs.occupiedBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)];
|
||||||
|
|
||||||
generateMoves(bs, from, movesBB, moves);
|
generateMoves(bs, from, movesBB, PieceType::Rook, moves);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveGenerator::generateQueenMoves(const BoardState &bs, const Square &from, MoveVec &moves) {
|
void MoveGenerator::generateQueenMoves(const BoardState &bs, const Square &from, MoveVec &moves) {
|
||||||
auto fromBB = BitBoard::fromIndex(from.index());
|
auto fromBB = BitBoard::fromIndex(from.index());
|
||||||
auto movesBB = BitBoard::queenAttacks(fromBB, ~bs.occupiedBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)];
|
auto movesBB = BitBoard::queenAttacks(fromBB, ~bs.occupiedBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)];
|
||||||
|
|
||||||
generateMoves(bs, from, movesBB, moves);
|
generateMoves(bs, from, movesBB, PieceType::Queen, moves);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveGenerator::generateKnightMoves(const BoardState &bs, const Square &from, MoveVec &moves) {
|
void MoveGenerator::generateKnightMoves(const BoardState &bs, const Square &from, MoveVec &moves) {
|
||||||
|
|
||||||
auto fromBB = BitBoard::fromIndex(from.index());
|
auto fromBB = BitBoard::fromIndex(from.index());
|
||||||
auto movesBB = BitBoard::knightMoves(fromBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)];
|
auto movesBB = BitBoard::knightMoves(fromBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)];
|
||||||
generateMoves(bs, from, movesBB, moves);
|
generateMoves(bs, from, movesBB, PieceType::Knight, moves);
|
||||||
}
|
}
|
||||||
|
|
||||||
BitBoard MoveGenerator::generateAttackedSquares(const BoardState &bs, BitBoard target, PieceColor opColor) {
|
BitBoard MoveGenerator::generateAttackedSquares(const BoardState &bs, BitBoard target, PieceColor opColor) {
|
||||||
@@ -152,16 +160,74 @@ BitBoard MoveGenerator::generateAttackedSquares(const BoardState &bs, BitBoard t
|
|||||||
|
|
||||||
return attacked;
|
return attacked;
|
||||||
}
|
}
|
||||||
inline bool MoveGenerator::isCheck(const BoardState &bs, const BitBoard &fromBB, const Square &to) {
|
|
||||||
|
inline bool MoveGenerator::isCheck(const BoardState &bs, const BitBoard &fromBB, const BitBoard &toBB) {
|
||||||
auto kingBB = (*bs.pieceBBs)[Board::toIndex(bs.turn)] & (*bs.pieceBBs)[Board::toIndex(PieceType::King)];
|
auto kingBB = (*bs.pieceBBs)[Board::toIndex(bs.turn)] & (*bs.pieceBBs)[Board::toIndex(PieceType::King)];
|
||||||
auto toBB = BitBoard::fromIndex(to.index());
|
|
||||||
auto changeBB = (fromBB ^ toBB);
|
auto changeBB = (fromBB ^ toBB);
|
||||||
auto target = bs.occupiedBB ^ changeBB;
|
auto target = bs.occupiedBB ^ changeBB;
|
||||||
auto attacked = generateAttackedSquares(bs, ~target, !bs.turn);
|
|
||||||
|
|
||||||
if (kingBB & fromBB) {
|
if (kingBB & fromBB) {
|
||||||
|
|
||||||
|
if (toBB & bs.occupiedBB) {
|
||||||
|
target ^= toBB;
|
||||||
|
}
|
||||||
|
if ((toBB & ~bs.occupiedBB)) {
|
||||||
kingBB ^= changeBB;
|
kingBB ^= changeBB;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto attacked = generateAttackedSquares(bs, ~target, !bs.turn);
|
||||||
|
|
||||||
return attacked & kingBB;
|
return attacked & kingBB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline unsigned MoveGenerator::score(const BoardState &bs, const BitBoard &toBB, const PieceType moved) {
|
||||||
|
|
||||||
|
unsigned score = 0;
|
||||||
|
auto opponentBB = bs.occupiedBB & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)];
|
||||||
|
|
||||||
|
|
||||||
|
// Check Capture
|
||||||
|
auto captureBB = toBB & opponentBB;
|
||||||
|
if (captureBB) {
|
||||||
|
auto captured = bs.pieceType(captureBB);
|
||||||
|
score = Piece::MVV_LVA[Board::toIndex(captured)][Board::toIndex(moved)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned MoveGenerator::Mobility(const BoardState &bs, PieceColor color) {
|
||||||
|
unsigned count = 0;
|
||||||
|
auto colorMask = (*bs.pieceBBs)[Board::toIndex(color)];
|
||||||
|
auto targets = (*bs.pieceBBs)[Board::toIndex(!color)];
|
||||||
|
|
||||||
|
// Pawns
|
||||||
|
auto pawnsBB = (*bs.pieceBBs)[Board::toIndex(PieceType::Pawn)] & colorMask;
|
||||||
|
if (color == PieceColor::White) {
|
||||||
|
auto movesBB = BitBoard::pawnNorthAttacks(pawnsBB, targets) & ~colorMask;
|
||||||
|
movesBB |= BitBoard::pawnNorthMoves(pawnsBB, ~bs.occupiedBB);
|
||||||
|
count += movesBB.count();
|
||||||
|
} else {
|
||||||
|
auto movesBB = BitBoard::pawnSouthAttacks(pawnsBB, targets) & ~colorMask;
|
||||||
|
movesBB |= BitBoard::pawnSouthMoves(pawnsBB, ~bs.occupiedBB);
|
||||||
|
count += movesBB.count();
|
||||||
|
}
|
||||||
|
// Bishops
|
||||||
|
count += (BitBoard::bishopAttacks((*bs.pieceBBs)[Board::toIndex(PieceType::Bishop)] & colorMask, ~bs.occupiedBB) &
|
||||||
|
~colorMask).count();
|
||||||
|
// Knights
|
||||||
|
count += (BitBoard::knightMoves((*bs.pieceBBs)[Board::toIndex(PieceType::Knight)] & colorMask) &
|
||||||
|
~colorMask).count();
|
||||||
|
// Rook
|
||||||
|
count += (BitBoard::rookAttacks((*bs.pieceBBs)[Board::toIndex(PieceType::Rook)] & colorMask, ~bs.occupiedBB) &
|
||||||
|
~colorMask).count();
|
||||||
|
// Queen
|
||||||
|
count += (BitBoard::queenAttacks((*bs.pieceBBs)[Board::toIndex(PieceType::Queen)] & colorMask, ~bs.occupiedBB) &
|
||||||
|
~colorMask).count();
|
||||||
|
// King
|
||||||
|
count += (BitBoard::kingMoves((*bs.pieceBBs)[Board::toIndex(PieceType::King)] & colorMask) & ~colorMask).count();
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
@@ -25,13 +25,16 @@ public:
|
|||||||
static void generateKnightMoves(const BoardState &bs, const Square &from, MoveVec &moves);
|
static void generateKnightMoves(const BoardState &bs, const Square &from, MoveVec &moves);
|
||||||
static BitBoard generateAttackedSquares(const BoardState &bs, BitBoard target, PieceColor opColor);
|
static BitBoard generateAttackedSquares(const BoardState &bs, BitBoard target, PieceColor opColor);
|
||||||
|
|
||||||
|
static unsigned int Mobility(const BoardState &bs, PieceColor color);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void generatePawnMoves(const BoardState &bs, const Square &from, BitBoard targets, MoveVec &moves);
|
static void generatePawnMoves(const BoardState &bs, const Square &from, BitBoard targets, MoveVec &moves);
|
||||||
|
|
||||||
static void generateMoves(const BoardState &bs, const Square &from, BitBoard movesBB, MoveVec &moves);
|
static void generateMoves(const BoardState &bs, const Square &from, BitBoard movesBB, PieceType pt, MoveVec &moves);
|
||||||
static void generateMovesWithPromotion(const BoardState &bs, const Square &from, BitBoard movesBB, MoveVec &moves);
|
static void generateMovesWithPromotion(const BoardState &bs, const Square &from, BitBoard movesBB, MoveVec &moves);
|
||||||
|
|
||||||
inline static bool isCheck(const BoardState &bs, const BitBoard &fromBB, const Square &to);
|
inline static bool isCheck(const BoardState &bs, const BitBoard &fromBB, const BitBoard &toBB);
|
||||||
|
inline static unsigned score(const BoardState &bs, const BitBoard &toBB, PieceType moved);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //CHESS_ENGINE_MOVEGENERATOR_HPP
|
#endif //CHESS_ENGINE_MOVEGENERATOR_HPP
|
||||||
|
18
Piece.hpp
18
Piece.hpp
@@ -24,19 +24,34 @@ class Piece {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
constexpr static const PieceType PromotionTypes[4] = {PieceType::Knight, PieceType::Bishop, PieceType::Rook, PieceType::Queen};
|
constexpr static const PieceType PromotionTypes[4] = {PieceType::Knight, PieceType::Bishop, PieceType::Rook,
|
||||||
|
PieceType::Queen};
|
||||||
|
constexpr static const unsigned PieceValue[6] = {100, 350, 350, 525, 1000, 10000};
|
||||||
|
constexpr static const unsigned PromotionScore[6] = {0, 26, 36, 46, 56, 0};
|
||||||
|
|
||||||
|
constexpr static const unsigned MVV_LVA[6][6] = {
|
||||||
|
{15, 14, 13, 12, 11, 10}, // Pawn
|
||||||
|
{25, 24, 23, 22, 21, 20}, // Knight
|
||||||
|
{35, 34, 33, 32, 31, 30}, // Bishop
|
||||||
|
{45, 44, 43, 42, 41, 40}, // Rook
|
||||||
|
{55, 54, 53, 52, 51, 50}, // Queen
|
||||||
|
{65, 64, 63, 62, 61, 60}, // King
|
||||||
|
};
|
||||||
|
|
||||||
using Optional = std::optional<Piece>;
|
using Optional = std::optional<Piece>;
|
||||||
|
|
||||||
Piece(PieceColor color, PieceType type);
|
Piece(PieceColor color, PieceType type);
|
||||||
|
|
||||||
static Optional fromSymbol(char symbol);
|
static Optional fromSymbol(char symbol);
|
||||||
|
|
||||||
static char toSymbol(PieceType type);
|
static char toSymbol(PieceType type);
|
||||||
|
|
||||||
static std::optional<PieceType> pieceTypeFromSymbol(char symbol);
|
static std::optional<PieceType> pieceTypeFromSymbol(char symbol);
|
||||||
|
|
||||||
PieceColor color() const;
|
PieceColor color() const;
|
||||||
|
|
||||||
PieceType type() const;
|
PieceType type() const;
|
||||||
|
|
||||||
char toSymbol() const;
|
char toSymbol() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -45,6 +60,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool operator==(const Piece &lhs, const Piece &rhs);
|
bool operator==(const Piece &lhs, const Piece &rhs);
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &os, const Piece &piece);
|
std::ostream &operator<<(std::ostream &os, const Piece &piece);
|
||||||
|
|
||||||
// Invert a color (White becomes Black and vice versa)
|
// Invert a color (White becomes Black and vice versa)
|
||||||
|
17
Search.cpp
17
Search.cpp
@@ -1,8 +1,11 @@
|
|||||||
|
#include <iostream>
|
||||||
#include "Search.hpp"
|
#include "Search.hpp"
|
||||||
#include "Move.hpp"
|
#include "Move.hpp"
|
||||||
#include "Board.hpp"
|
#include "Board.hpp"
|
||||||
|
|
||||||
int Search::search(Node *node, const Board &board, unsigned depth) {
|
#include <algorithm>
|
||||||
|
|
||||||
|
int Search::search(Node *node, const Board &board, unsigned depth, int alpha, int beta) {
|
||||||
|
|
||||||
if (depth == 0) {
|
if (depth == 0) {
|
||||||
return evaluate(board);
|
return evaluate(board);
|
||||||
@@ -13,6 +16,7 @@ int Search::search(Node *node, const Board &board, unsigned depth) {
|
|||||||
if (moves.empty()) {
|
if (moves.empty()) {
|
||||||
return evaluate(board);
|
return evaluate(board);
|
||||||
}
|
}
|
||||||
|
std::stable_sort(moves.begin(), moves.end());
|
||||||
|
|
||||||
int maxValue = kNegInfinity;
|
int maxValue = kNegInfinity;
|
||||||
for (auto &kMove: moves) {
|
for (auto &kMove: moves) {
|
||||||
@@ -20,13 +24,18 @@ int Search::search(Node *node, const Board &board, unsigned depth) {
|
|||||||
nodeBoard.makeMove(kMove);
|
nodeBoard.makeMove(kMove);
|
||||||
|
|
||||||
Node child(kMove);
|
Node child(kMove);
|
||||||
child.value = search(&child, nodeBoard, depth - 1);
|
child.value = search(&child, nodeBoard, depth - 1, -beta, -alpha);
|
||||||
|
|
||||||
auto value = -child.value;
|
auto value = -child.value;
|
||||||
if (value > maxValue) {
|
if (value > maxValue) {
|
||||||
maxValue = value;
|
maxValue = value;
|
||||||
node->next = std::make_unique<Node>(child);
|
node->next = std::make_unique<Node>(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alpha = std::max(alpha, value);
|
||||||
|
if (alpha >= beta) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node->value = maxValue;
|
node->value = maxValue;
|
||||||
@@ -39,9 +48,11 @@ int Search::evaluate(const Board &board) {
|
|||||||
return board.evaluate();
|
return board.evaluate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PrincipalVariation Search::start(const Board &board) {
|
PrincipalVariation Search::start(const Board &board) {
|
||||||
auto rootMoves = Board::MoveVec();
|
auto rootMoves = Board::MoveVec();
|
||||||
board.pseudoLegalMoves(rootMoves);
|
board.pseudoLegalMoves(rootMoves);
|
||||||
|
std::stable_sort(rootMoves.begin(), rootMoves.end());
|
||||||
|
|
||||||
if (rootMoves.size() <= 1) {
|
if (rootMoves.size() <= 1) {
|
||||||
auto b = board;
|
auto b = board;
|
||||||
@@ -56,7 +67,7 @@ PrincipalVariation Search::start(const Board &board) {
|
|||||||
Board nodeBoard = board;
|
Board nodeBoard = board;
|
||||||
nodeBoard.makeMove(kMove);
|
nodeBoard.makeMove(kMove);
|
||||||
|
|
||||||
auto value = -search(&node, nodeBoard, 4);
|
auto value = -search(&node, nodeBoard, 5, kNegInfinity, kPosInfinity);
|
||||||
if (value > best->value) {
|
if (value > best->value) {
|
||||||
best->child = std::make_unique<Node>(node);
|
best->child = std::make_unique<Node>(node);
|
||||||
best->board = nodeBoard;
|
best->board = nodeBoard;
|
||||||
|
@@ -9,15 +9,16 @@
|
|||||||
|
|
||||||
namespace Search {
|
namespace Search {
|
||||||
|
|
||||||
|
const int kPosInfinity = std::numeric_limits<int>::max();
|
||||||
const int kNegInfinity = std::numeric_limits<int>::min();
|
const int kNegInfinity = std::numeric_limits<int>::min();
|
||||||
|
|
||||||
struct Node {
|
struct Node {
|
||||||
explicit Node(const Move move) : move(move) {
|
explicit Node(const Move &move) : move(move) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Node(Node &node) : move(node.move) {
|
Node(Node &node) : move(node.move) {
|
||||||
next = std::move(node.next);
|
next = std::move(node.next);
|
||||||
value = node.value + 10;
|
value = node.value;
|
||||||
}
|
}
|
||||||
std::unique_ptr<Node> next;
|
std::unique_ptr<Node> next;
|
||||||
Move move;
|
Move move;
|
||||||
@@ -30,7 +31,7 @@ struct RootNode {
|
|||||||
int value = kNegInfinity;
|
int value = kNegInfinity;
|
||||||
};
|
};
|
||||||
|
|
||||||
int search(Node *node, const Board &board, unsigned depth);
|
int search(Node *node, const Board &board, unsigned depth, int alpha, int beta);
|
||||||
PrincipalVariation start(const Board &board);
|
PrincipalVariation start(const Board &board);
|
||||||
int evaluate(const Board &board);
|
int evaluate(const Board &board);
|
||||||
}
|
}
|
||||||
|
@@ -35,6 +35,7 @@ static void testMove(const char *fen, const std::vector<std::string> &expectedMo
|
|||||||
for (const auto &moveName : expectedMoves) {
|
for (const auto &moveName : expectedMoves) {
|
||||||
auto pv = engine->pv(board.value());
|
auto pv = engine->pv(board.value());
|
||||||
Move move = *pv.begin();
|
Move move = *pv.begin();
|
||||||
|
move.setScore(0);
|
||||||
REQUIRE(move == Move::fromUci(moveName));
|
REQUIRE(move == Move::fromUci(moveName));
|
||||||
board->makeMove(move);
|
board->makeMove(move);
|
||||||
}
|
}
|
||||||
@@ -67,6 +68,8 @@ TEST_CASE("Puzzles mateIn1_simple", "[Engine][Puzzle]") {
|
|||||||
auto [fen, moves] = GENERATE(table<const char*, std::vector<std::string>>({
|
auto [fen, moves] = GENERATE(table<const char*, std::vector<std::string>>({
|
||||||
{"2bQ1k1r/1p3p2/p4b1p/4pNp1/2q5/8/PPP2PPP/1K1RR3 b - - 3 23",{"f6d8", "d1d8"}}, // https://lichess.org/gQa01loO/black#46
|
{"2bQ1k1r/1p3p2/p4b1p/4pNp1/2q5/8/PPP2PPP/1K1RR3 b - - 3 23",{"f6d8", "d1d8"}}, // https://lichess.org/gQa01loO/black#46
|
||||||
{"5rk1/ppp5/2n4p/3b2p1/6R1/P1B1P2P/1Pq5/R2Q2K1 b - - 3 29",{"c2f2"}}, // https://lichess.org/haKJxadR#57
|
{"5rk1/ppp5/2n4p/3b2p1/6R1/P1B1P2P/1Pq5/R2Q2K1 b - - 3 29",{"c2f2"}}, // https://lichess.org/haKJxadR#57
|
||||||
|
{"r1b1k2r/ppp2pp1/2p5/2b1q1Bp/3PP1n1/2P5/PP2BPPP/RN1Q1RK1 b kq - 0 10",{"e5h2"}},
|
||||||
|
{"r3rk2/5ppQ/b1pp1q1p/p5n1/P1P5/2N5/1PB2PP1/R3R1K1 w - - 6 24", {"h7h8"}},
|
||||||
}));
|
}));
|
||||||
testMove(fen, moves);
|
testMove(fen, moves);
|
||||||
}
|
}
|
||||||
|
@@ -104,7 +104,7 @@ TEST_CASE("En passant square is correctly parsed", "[Fen][EnPassant]") {
|
|||||||
{
|
{
|
||||||
"rnbqkbnr/ppppp1pp/8/8/2PPPp2/8/PP3PPP/RNBQKBNR b KQkq e3 0 3",
|
"rnbqkbnr/ppppp1pp/8/8/2PPPp2/8/PP3PPP/RNBQKBNR b KQkq e3 0 3",
|
||||||
Square::E3
|
Square::E3
|
||||||
}
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
CAPTURE(fen, ep);
|
CAPTURE(fen, ep);
|
||||||
|
Reference in New Issue
Block a user