diff --git a/README.md b/README.md index c679300..8d9930f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The C++ rewrite is complete! Clarity is now faster and better, using new techniq For those who didn't see the engine in its depressing, confusing, error-filled C# state, this engine was originally written in C# before I decided to switch to C++. That decision was one of the greatest I think I've ever had, as the engine is now faster, easier to read, less error-filled(hopefully), and better overall. -My current Estimate of elo (calculated by playing large sums of games against engines with known CCRL ratings) is 2050. +My current Estimate of elo (calculated by playing large sums of games against engines with known CCRL ratings) is 2200. #### Warning: Clarity currently uses pext for move generation, which means that CPUs without BMI2 or CPUs with a slow implementation (Zen 2 or earlier) will not be able to use it, A replacement (magic bitboards) is underway. @@ -44,6 +44,17 @@ Evaluation: ## Feature List: +CLI: + 1. UCI Implementation + 2. printstate: shows the state of the board. + 3. perftsuite : performs a suite of perft tests, currently only supports the suite ethereal. + 4. perft : performs a perft test from the current position and outputs the result. + 5. splitperft : performs a perft test from the current position and outputs the result seperated by which move is the first one done. + 6: getfen: outputs a string of Forsyth-Edwards Notation (FEN) that encodes the current position. + 7: incheck: outputs if the current position is in check or not. + 8: evaluate: outputs the evaluation of the current position. + 9: bench : performs the bench test, a fixed depth search on a series of 50 positions. + Board Representation: 1. Copymake moves 2. Board represented using 8 bitboards diff --git a/src/board.cpp b/src/board.cpp index 36139d8..be71c39 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -760,7 +760,7 @@ void Board::undoChangeColor() { } int Board::getEvaluation() { - // currently disabled passed pawn bonuses, as it wasn't gaining any elo + // currently disabled passed pawn bonuses, as it wasn't gaining any elo, even after my goofy and probablly messed up tuning int egPhase = 24 - phase; return ((mgEval * phase + egEval * egPhase) / 24) * ((2 * colorToMove) - 1); //return (((mgEval * phase + egEval * egPhase) / 24) + getPassedPawnBonuses()) * ((2 * colorToMove) - 1); @@ -875,4 +875,39 @@ bool Board::isRepeatedPosition() { } } return false; +} + +bool Board::isLegalMove(const Move& move) { + if(move.getValue() != 0) { + int startSquare = move.getStartSquare(); + uint64_t occupiedBitboard = getOccupiedBitboard(); + int movePiece = getType(pieceAtIndex(startSquare)); + if(movePiece != None) { + uint64_t total = 0; + if(movePiece == Pawn) { + total = getPawnAttacks(startSquare, colorToMove); + uint64_t capturable = coloredBitboards[1 - colorToMove]; + if(enPassantIndex != 64) { + capturable |= (1ULL << enPassantIndex); + } + total &= capturable; + total |= (1ULL << (startSquare + directionalOffsets[colorToMove])) & ~occupiedBitboard; + } else { + if(movePiece == Knight) { + total = getKnightAttacks(startSquare); + } else if(movePiece == Bishop) { + total = getBishopAttacks(startSquare, occupiedBitboard); + } else if(movePiece == Rook) { + total = getRookAttacks(startSquare, occupiedBitboard); + } else if(movePiece == Queen) { + total = getRookAttacks(startSquare, occupiedBitboard) | getBishopAttacks(startSquare, occupiedBitboard); + } else if(movePiece == King) { + total = getKingAttacks(startSquare); + } + total ^= (total & coloredBitboards[colorToMove]); + } + if((total & (1ULL << move.getEndSquare())) != 0) return true; + } + } + return false; } \ No newline at end of file diff --git a/src/globals.h b/src/globals.h index 41ce360..7f8e8d8 100644 --- a/src/globals.h +++ b/src/globals.h @@ -60,10 +60,10 @@ struct BoardState { struct Move { public: - int getStartSquare(); - int getEndSquare(); - int getFlag(); - int getValue(); + int getStartSquare() const; + int getEndSquare() const; + int getFlag() const; + int getValue() const; Move(int startSquare, int endSquare, int flag); Move(); Move(std::string longAlgebraic, const Board& board); @@ -100,6 +100,7 @@ struct Board { uint64_t fullZobristRegen(); bool isRepeatedPosition(); int detectPassedPawns(); + bool isLegalMove(const Move& move); private: std::array coloredBitboards; std::array pieceBitboards; diff --git a/src/move.cpp b/src/move.cpp index 1911c16..ff681c3 100644 --- a/src/move.cpp +++ b/src/move.cpp @@ -1,18 +1,18 @@ #include "globals.h" -int Move::getValue() { +int Move::getValue() const { return value; } -int Move::getStartSquare() { +int Move::getStartSquare() const { return value & 0b111111; } -int Move::getEndSquare() { +int Move::getEndSquare() const { return (value >> 6) & 0b111111; } -int Move::getFlag() { +int Move::getFlag() const { return value >> 12; } diff --git a/src/search.cpp b/src/search.cpp index 890f6ff..80ba84d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -279,7 +279,8 @@ std::string getPV(Board board) { std::string pv = ""; if(TT.matchZobrist(board.zobristHash)) { Move bestMove = TT.getBestMove(board.zobristHash); - if(bestMove.getValue() != 0 && board.makeMove(bestMove)) { + // need a move.isLegal() to make sure that the move is legal in the position, not just that it doesn't put you in check + if(board.isLegalMove(bestMove) && board.makeMove(bestMove)) { std::string restOfPV = getPV(board); pv = toLongAlgebraic(bestMove) + " " + restOfPV; } @@ -328,7 +329,7 @@ Move think(Board board, int timeLeft) { } //std::string pv = getPV(board); //std::cout << "info depth " << std::to_string(depth) << " nodes " << std::to_string(nodes) << " time " << std::to_string(elapsedTime) << " score cp " << std::to_string(score) << " pv " << pv << std::endl; - std::cout << "info depth " << std::to_string(depth) << " nodes " << std::to_string(nodes) << " time " << std::to_string(elapsedTime) << " score cp " << std::to_string(score) << std::endl; + std::cout << "info depth " << std::to_string(depth) << " nodes " << std::to_string(nodes) << " time " << std::to_string(elapsedTime) << " score cp " << std::to_string(score) << " pv " << toLongAlgebraic(rootBestMove) << std::endl; } return rootBestMove; diff --git a/src/uci.cpp b/src/uci.cpp index 0359349..b674b5d 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -64,7 +64,7 @@ void sigmoidTest() { }*/ void identify() { - std::cout << "id name Clarity V0.1.2\n"; + std::cout << "id name Clarity V1.0.0\n"; std::cout << "id author Vast\n"; std::cout << "option name Hash type spin default 256 min 1 max 2048\n"; } @@ -119,13 +119,6 @@ void interpretCommand(std::string command) { splitPerft(board, std::stoi(bits[1])); } else if(bits[0] == "evaluate") { std::cout << "evaluation " << board.getEvaluation() << '\n'; - } else if(bits[0] == "showstate") { - board.toString(); - } else if(bits[0] == "detectpassers") { - const int passed = board.detectPassedPawns(); - std::cout << "passed pawns: " << passed << '\n'; - } else if(bits[0] == "masktest") { - std::cout << "mask: " << getPassedPawnMask(43, 1) << '\n'; } else if(bits[0] == "setoption") { setOption(bits); } else if(bits[0] == "bench") {