stellar

UCI Chess engine written in C++20
git clone git://git.dimitrijedobrota.com/stellar.git
Log | Files | Refs | README | LICENSE |

commit9f2c299a72ac90aa9d2a927666375cc5b6d527b3
parentedfb2f6999e4cc1e8215e10736850b48a12d424b
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateWed, 13 Mar 2024 21:41:22 +0000

Merge square and color into utils out of namespace

Diffstat:
MCMakeLists.txt|+-
Msrc/arena/engine.cpp|-
Msrc/arena/game.cpp|++++++++++---------
Msrc/arena/game.hpp|++++----
Msrc/arena/match.cpp|++++++++++++++++++++--------------------
Msrc/arena/match.hpp|+-
Msrc/attack/attack.hpp|++---
Msrc/attack/bishop.cpp|+++++-----
Msrc/attack/bishop.hpp|++---
Msrc/attack/king.hpp|+++----
Msrc/attack/knight.hpp|+++----
Msrc/attack/pawn.hpp|++++++----------
Msrc/attack/queen.hpp|+-
Msrc/attack/rook.cpp|+++++-----
Msrc/attack/rook.hpp|+--
Msrc/attack/slider.hpp|+--
Msrc/bitboard/bitboard.cpp|++++++++++++
Msrc/bitboard/bitboard.hpp|+++-
Msrc/board/board.cpp|+++++++----------
Msrc/board/board.hpp|++++++++++++++++++++++++++++++++++++----------------------------------------------
Msrc/board/zobrist.hpp|++++----
Msrc/engine/engine.cpp|+-
Msrc/engine/evaluate.cpp|+++++++++++++--------------
Msrc/engine/score.hpp|++---
Msrc/engine/uci.cpp|+++++------
Msrc/engine/uci.hpp|+
Msrc/move/move.cpp|++++++++++++++++---------------------
Msrc/move/move.hpp|++++++--------
Msrc/move/movelist.cpp|+++++++++++++++++++++++++++++++----------------------------------
Msrc/move/movelist.hpp|+-
Msrc/perft/perft.cpp|++---
Msrc/piece/piece.hpp|++++++++++++++++++--------------------
Dsrc/utils/color.hpp|--------------------
Msrc/utils/repetition.hpp|+++++
Dsrc/utils/square.hpp|-------------------------------------------------------------
Msrc/utils/utils.hpp|++++++++++++++++++++++++++++++++++++++++++++++--
Asrc/utils/utils_ui.hpp|+++++++++++++++++++++++++++++++++++

37 files changed, 336 insertions(+), 364 deletions(-)


diff --git a/CMakeLists.txt b/CMakeLists.txt

@@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

project(
Stellar
VERSION 1.3.3
VERSION 1.3.4
DESCRIPTION "Chess engine written in C++"
HOMEPAGE_URL https://git.dimitrijedobrota.com/stellar.git
LANGUAGES CXX

diff --git a/src/arena/engine.cpp b/src/arena/engine.cpp

@@ -13,7 +13,6 @@ Engine::Pipes::Pipes() {

}
}
void Engine::Pipes::close() {
if (::close(fd[0]) < 0 || ::close(fd[1])) {
logger::error("close");

diff --git a/src/arena/game.cpp b/src/arena/game.cpp

@@ -3,6 +3,7 @@

#include "board.hpp"
#include "logger.hpp"
#include "timer.hpp"
#include "utils_ui.hpp"
#include <format>

@@ -45,12 +46,12 @@ const std::string Game::to_san(const Board &board, const Move move) {

int file[9] = {0}, rank[9] = {0};
uint8_t square_i = 0;
bitboard_for_each_bit(square_i, potential) {
const std::string crd = square::to_coordinates(static_cast<square::Square>(square_i));
const std::string crd = to_coordinates(static_cast<Square>(square_i));
file[crd[0] & 0x3]++;
rank[crd[1] & 0x3]++;
}
const std::string crd = square::to_coordinates(move.source());
const std::string crd = to_coordinates(move.source());
if (file[crd[0] & 0x3] == 1) res += crd[0];
else if (rank[crd[1] & 0x3] == 1)
res += crd[1];

@@ -58,13 +59,13 @@ const std::string Game::to_san(const Board &board, const Move move) {

res += crd;
}
res += piece::get_code(piece, color::WHITE);
res += piece::get_code(piece, WHITE);
if (target != piece::NONE) res += "x";
res += square::to_coordinates(move.target());
res += to_coordinates(move.target());
} else {
if (target != piece::NONE) res += std::format("{}x", square::to_coordinates(move.source())[0]);
res += square::to_coordinates(move.target());
if (move.is_promote()) res += piece::get_code(move.promoted(), color::WHITE);
if (target != piece::NONE) res += std::format("{}x", to_coordinates(move.source())[0]);
res += to_coordinates(move.target());
if (move.is_promote()) res += piece::get_code(move.promoted(), WHITE);
if (move.is_enpassant()) res += " e.p.";
}

@@ -94,8 +95,8 @@ std::ostream &operator<<(std::ostream &os, const Game &game) {

if (!game.list.size()) return os;
Board board(game.fen);
const color::Color side = board.get_side();
if (side == color::BLACK) os << std::format("1. ... ");
const Color side = board.get_side();
if (side == BLACK) os << std::format("1. ... ");
for (int i = 0; i < game.list.size(); i++) {
if (i % 2 == side) os << std::format("{}. ", i / 2 + 1);
os << std::format("{} ", Game::san ? Game::to_san(board, game.list[i]) : (std::string)game.list[i]);

diff --git a/src/arena/game.hpp b/src/arena/game.hpp

@@ -23,12 +23,12 @@ class Game {

[[nodiscard]] const std::string &get_black() const { return black; }
[[nodiscard]] const Terminate get_terminate() const { return terminate; }
[[nodiscard]] const bool is_win_white() const { return !draw && winner == color::WHITE; }
[[nodiscard]] const bool is_win_black() const { return !draw && winner == color::BLACK; }
[[nodiscard]] const bool is_win_white() const { return !draw && winner == WHITE; }
[[nodiscard]] const bool is_win_black() const { return !draw && winner == BLACK; }
[[nodiscard]] const bool is_draw() const { return draw; }
void set_terminate(const Terminate terminate) { this->terminate = terminate; }
void set_winner(const color::Color winner) { this->winner = winner; }
void set_winner(const Color winner) { this->winner = winner; }
void set_draw(const bool draw) { this->draw = draw; }
static void set_san(bool san) { Game::san = san; }

@@ -47,7 +47,7 @@ class Game {

MoveList list;
bool draw = false;
color::Color winner;
Color winner;
Terminate terminate = Terminate::Deatch;
static bool san;

diff --git a/src/arena/match.cpp b/src/arena/match.cpp

@@ -2,6 +2,7 @@

#include "logger.hpp"
#include "repetition.hpp"
#include "timer.hpp"
#include "utils_ui.hpp"
uint16_t Match::id_t = 0;
Match::~Match() { logger::log(std::format("Match {}: destroyed", id), logger::Debug); }

@@ -23,11 +24,11 @@ Game Match::play(Settings swhite, Settings sblack, const std::string fen = Game:

engines[0]->send("ucinewgame");
engines[1]->send("ucinewgame");
color::Color turn = board.get_side();
Color turn = board.get_side();
while (true) {
const MoveList list = MoveList(board, false, true);
if (!list.size()) {
game.set_winner(color::other(turn));
game.set_winner(other(turn));
break;
}

@@ -45,15 +46,14 @@ Game Match::play(Settings swhite, Settings sblack, const std::string fen = Game:

std::string move_str = response.substr(9);
if ((move = parse_move(list, move_str)) == Move() || !move.make(board)) {
logger::log(
std::format("Match {}: {} illegal {}", id, color::to_string(turn), (std::string)move));
logger::log(std::format("Match {}: {} illegal {}", id, to_string(turn), (std::string)move));
game.set_terminate(Game::Illegal);
game.set_winner(color::other(turn));
game.set_winner(other(turn));
break;
}
if (rtable.is_repetition(board.get_hash())) {
logger::log(std::format("Match {}: {} repetition", id, color::to_string(turn)));
logger::log(std::format("Match {}: {} repetition", id, to_string(turn)));
game.set_terminate(Game::Repetition);
game.set_draw(true);
break;

@@ -64,21 +64,21 @@ Game Match::play(Settings swhite, Settings sblack, const std::string fen = Game:

game.play(move);
uint64_t time_passed = timer::get_ms() - time_start;
if (turn == color::WHITE ? swhite.time <= time_passed : sblack.time <= time_passed) {
logger::log(std::format("Match {}: {} timeout", id, color::to_string(turn)));
if (turn == WHITE ? swhite.time <= time_passed : sblack.time <= time_passed) {
logger::log(std::format("Match {}: {} timeout", id, to_string(turn)));
game.set_terminate(Game::Timeout);
game.set_winner(color::other(turn));
game.set_winner(other(turn));
break;
}
if (turn == color::WHITE && !swhite.depth) swhite.time -= time_passed;
if (turn == color::BLACK && !sblack.depth) sblack.time -= time_passed;
if (turn == WHITE && !swhite.depth) swhite.time -= time_passed;
if (turn == BLACK && !sblack.depth) sblack.time -= time_passed;
turn = color::other(turn);
turn = other(turn);
}
if (!game.is_draw()) {
logger::log(std::format("Match {}: winner is {}", id, color::to_string(turn)));
logger::log(std::format("Match {}: winner is {}", id, to_string(turn)));
} else {
logger::log(std::format("Match {}: ended in a draw", id));
}

@@ -87,19 +87,19 @@ Game Match::play(Settings swhite, Settings sblack, const std::string fen = Game:

return game;
}
std::string Match::get_go(Settings &swhite, Settings &sblack, color::Color side) {
std::string Match::get_go(Settings &swhite, Settings &sblack, Color side) {
std::string go = "go";
if (side == color::WHITE && swhite.depth) go += " depth " + std::to_string(swhite.depth);
if (side == WHITE && swhite.depth) go += " depth " + std::to_string(swhite.depth);
else {
if (side == color::WHITE && swhite.togo) go += " movestogo " + std::to_string(swhite.togo);
if (side == WHITE && swhite.togo) go += " movestogo " + std::to_string(swhite.togo);
if (!sblack.depth && swhite.time) go += " wtime " + std::to_string(swhite.time);
if (swhite.inc) go += " winc " + std::to_string(swhite.inc);
if (swhite.movetime) go += " movetime " + std::to_string(swhite.movetime);
}
if (side == color::BLACK && sblack.depth) go += " depth " + std::to_string(sblack.depth);
if (side == BLACK && sblack.depth) go += " depth " + std::to_string(sblack.depth);
else {
if (side == color::BLACK && sblack.togo) go += " movestogo " + std::to_string(sblack.togo);
if (side == BLACK && sblack.togo) go += " movestogo " + std::to_string(sblack.togo);
if (!swhite.depth && sblack.time) go += " btime " + std::to_string(sblack.time);
if (sblack.inc) go += " binc " + std::to_string(sblack.inc);
if (swhite.movetime) go += " movetime " + std::to_string(sblack.movetime);

@@ -108,8 +108,8 @@ std::string Match::get_go(Settings &swhite, Settings &sblack, color::Color side)

}
Move Match::parse_move(const MoveList list, const std::string &move_string) {
const square::Square source = square::from_coordinates(move_string.substr(0, 2));
const square::Square target = square::from_coordinates(move_string.substr(2, 2));
const Square source = from_coordinates(move_string.substr(0, 2));
const Square target = from_coordinates(move_string.substr(2, 2));
for (int i = 0; i < list.size(); i++) {
const Move crnt = list[i];

diff --git a/src/arena/match.hpp b/src/arena/match.hpp

@@ -17,7 +17,7 @@ class Match {

Game play(Settings swhite, Settings sblack, const std::string fen);
private:
static std::string get_go(Settings &swhite, Settings &sblack, color::Color side);
static std::string get_go(Settings &swhite, Settings &sblack, Color side);
static Move parse_move(const MoveList list, const std::string &move_string);
std::array<Engine *, 2> engines;

diff --git a/src/attack/attack.hpp b/src/attack/attack.hpp

@@ -1,7 +1,6 @@

#ifndef STELLAR_ATTACK_H
#define STELLAR_ATTACK_H
#include "square.hpp"
#include "utils.hpp"
#include "bishop.hpp"

@@ -17,11 +16,11 @@ namespace attack {

void init(void);
inline constexpr const U64 attack_pawn(const color::Color color, const square::Square from) {
inline constexpr const U64 attack_pawn(const Color color, const Square from) {
return attack::pawn::attack(color, from);
}
inline constexpr const U64 attack(const piece::Type type, const square::Square from, const U64 occupancy) {
inline constexpr const U64 attack(const piece::Type type, const Square from, const U64 occupancy) {
switch (type) {
case piece::QUEEN: return attack::queen::attack(from, occupancy);
case piece::ROOK: return attack::rook::attack(from, occupancy);

diff --git a/src/attack/bishop.cpp b/src/attack/bishop.cpp

@@ -44,11 +44,11 @@ static inline constexpr const int relevant_bits[64] = {

inline constexpr const bitboard::direction_f dir[4] = {bitboard::noEaOne, bitboard::noWeOne,
bitboard::soEaOne, bitboard::soWeOne};
inline constexpr U32 hash(const U64 key, const square::Square square) {
inline constexpr U32 hash(const U64 key, const Square square) {
return (key * bishop_magic_numbers[square]) >> (64 - relevant_bits[square]);
}
inline constexpr U64 mask_fly(const square::Square square, U64 block) {
inline constexpr U64 mask_fly(const Square square, U64 block) {
int tr = square / 8, tf = square % 8;
int len[4] = {std::min(7 - tf, 7 - tr), std::min(tf, 7 - tr), std::min(7 - tf, tr), std::min(tf, tr)};

@@ -59,14 +59,14 @@ std::array<U64, 64> mask = {{0}};

std::array<std::array<U64, 4098>, 64> attacks = {{{0}}};
void init(void) {
for (square::Square square = square::a1; square <= square::h8; ++square) {
for (Square square = Square::a1; square <= Square::h8; ++square) {
int tr = square / 8, tf = square % 8;
int len[4] = {std::min(7 - tf, 7 - tr) - 1, std::min(tf, 7 - tr) - 1, std::min(7 - tf, tr) - 1,
std::min(tf, tr) - 1};
mask[square] = attack::slider::mask(square, C64(0), dir, len);
}
for (square::Square square = square::a1; square <= square::h8; ++square) {
for (Square square = Square::a1; square <= Square::h8; ++square) {
U64 attack_mask = mask[square];
uint8_t relevant_bits = bit::count(attack_mask);
U64 occupancy_indices = C64(1) << relevant_bits;

@@ -79,7 +79,7 @@ void init(void) {

}
}
U64 attack(const square::Square square, U64 occupancy) {
U64 attack(const Square square, U64 occupancy) {
occupancy &= mask[square];
occupancy = hash(occupancy, square);
return attacks[square][occupancy];

diff --git a/src/attack/bishop.hpp b/src/attack/bishop.hpp

@@ -1,16 +1,15 @@

#ifndef STELLAR_BISHOP_H
#define STELLAR_BISHOP_H
#include "square.hpp"
#include "utils.hpp"
namespace attack {
namespace bishop {
void init(void);
U64 attack(const square::Square square, U64 occupancy);
U64 attack(const Square square, U64 occupancy);
}
} // namespace bishop
} // namespace attack
#endif

diff --git a/src/attack/king.hpp b/src/attack/king.hpp

@@ -3,7 +3,6 @@

#include "bit.hpp"
#include "bitboard.hpp"
#include "square.hpp"
#include "utils.hpp"
#include <array>

@@ -11,7 +10,7 @@

namespace attack {
namespace king {
static constexpr U64 mask(const square::Square square) {
static constexpr U64 mask(const Square square) {
U64 bitboard = C64(0), attacks = C64(0);
bit::set(bitboard, square);

@@ -28,14 +27,14 @@ typedef std::array<U64, 64> attack_array;

const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (square::Square square = square::a1; square <= square::h8; ++square) {
for (Square square = Square::a1; square <= Square::h8; ++square) {
attacks[square] = mask(square);
}
return attacks;
}();
inline constexpr U64 attack(const square::Square square) { return attacks[square]; }
inline constexpr U64 attack(const Square square) { return attacks[square]; }
} // namespace king
} // namespace attack

diff --git a/src/attack/knight.hpp b/src/attack/knight.hpp

@@ -3,7 +3,6 @@

#include "bit.hpp"
#include "bitboard.hpp"
#include "square.hpp"
#include "utils.hpp"
#include <array>

@@ -11,7 +10,7 @@

namespace attack {
namespace knight {
static constexpr U64 mask(const square::Square square) {
static constexpr U64 mask(const Square square) {
U64 bitboard = C64(0), attacks = C64(0), tmp;
bit::set(bitboard, square);

@@ -31,14 +30,14 @@ typedef std::array<U64, 64> attack_array;

const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (square::Square square = square::a1; square <= square::h8; ++square) {
for (Square square = Square::a1; square <= Square::h8; ++square) {
attacks[square] = mask(square);
}
return attacks;
}();
inline constexpr U64 attack(const square::Square square) { return attacks[square]; }
inline constexpr U64 attack(const Square square) { return attacks[square]; }
} // namespace knight
} // namespace attack

diff --git a/src/attack/pawn.hpp b/src/attack/pawn.hpp

@@ -3,8 +3,6 @@

#include "bit.hpp"
#include "bitboard.hpp"
#include "color.hpp"
#include "square.hpp"
#include "utils.hpp"
#include <array>

@@ -12,14 +10,14 @@

namespace attack {
namespace pawn {
static constexpr U64 mask_white(const square::Square square) {
static constexpr U64 mask_white(const Square square) {
U64 bitboard = C64(0);
bit::set(bitboard, square);
return bitboard::noWeOne(bitboard) | bitboard::noEaOne(bitboard);
}
static constexpr U64 mask_black(const square::Square square) {
static constexpr U64 mask_black(const Square square) {
U64 bitboard = C64(0);
bit::set(bitboard, square);

@@ -30,17 +28,15 @@ typedef std::array<std::array<U64, 64>, 2> attack_array;

const auto attacks = []() {
attack_array attacks;
for (square::Square square = square::a1; square <= square::h8; ++square) {
attacks[color::WHITE][square] = mask_white(square);
attacks[color::BLACK][square] = mask_black(square);
for (Square square = Square::a1; square <= Square::h8; ++square) {
attacks[WHITE][square] = mask_white(square);
attacks[BLACK][square] = mask_black(square);
}
return attacks;
}();
inline constexpr U64 attack(color::Color color, square::Square square) {
return attacks[color][square];
}
inline constexpr U64 attack(Color color, Square square) { return attacks[color][square]; }
} // namespace pawn
} // namespace attack

diff --git a/src/attack/queen.hpp b/src/attack/queen.hpp

@@ -7,7 +7,7 @@

namespace attack {
namespace queen {
inline U64 attack(const square::Square square, U64 occupancy) {
inline U64 attack(const Square square, U64 occupancy) {
return rook::attack(square, occupancy) | bishop::attack(square, occupancy);
}

diff --git a/src/attack/rook.cpp b/src/attack/rook.cpp

@@ -43,11 +43,11 @@ inline constexpr const U64 rook_magic_numbers[64] = {

inline constexpr const bitboard::direction_f dir[4] = {bitboard::westOne, bitboard::soutOne,
bitboard::eastOne, bitboard::nortOne};
inline constexpr U32 hash(const U64 key, const square::Square square) {
inline constexpr U32 hash(const U64 key, const Square square) {
return (key * rook_magic_numbers[square]) >> (64 - relevant_bits[square]);
}
inline constexpr U64 mask_fly(const square::Square square, U64 block) {
inline constexpr U64 mask_fly(const Square square, U64 block) {
int tr = square / 8, tf = square % 8;
int len[4] = {tf, tr, 7 - tf, 7 - tr};

@@ -58,14 +58,14 @@ std::array<U64, 64> mask = {{0}};

std::array<std::array<U64, 4096>, 64> attacks = {{{0}}};
void init(void) {
for (square::Square square = square::a1; square <= square::h8; ++square) {
for (Square square = Square::a1; square <= Square::h8; ++square) {
const int tr = square / 8, tf = square % 8;
const int len[4] = {tf - 1, tr - 1, 6 - tf, 6 - tr};
mask[square] = attack::slider::mask(square, C64(0), dir, len);
}
for (square::Square square = square::a1; square <= square::h8; ++square) {
for (Square square = Square::a1; square <= Square::h8; ++square) {
U64 attack_mask = mask[square];
uint8_t relevant_bits = bit::count(attack_mask);
U64 occupancy_indices = C64(1) << relevant_bits;

@@ -78,7 +78,7 @@ void init(void) {

}
}
U64 attack(const square::Square square, U64 occupancy) {
U64 attack(const Square square, U64 occupancy) {
occupancy &= mask[square];
occupancy = hash(occupancy, square);
return attacks[square][occupancy];

diff --git a/src/attack/rook.hpp b/src/attack/rook.hpp

@@ -1,14 +1,13 @@

#ifndef STELLAR_ATTACK_ROOK_H
#define STELLAR_ATTACK_ROOK_H
#include "square.hpp"
#include "utils.hpp"
namespace attack {
namespace rook {
void init(void);
U64 attack(const square::Square square, U64 occupancy);
U64 attack(const Square square, U64 occupancy);
} // namespace rook
} // namespace attack

diff --git a/src/attack/slider.hpp b/src/attack/slider.hpp

@@ -3,7 +3,6 @@

#include "bit.hpp"
#include "bitboard.hpp"
#include "square.hpp"
#include "utils.hpp"
namespace attack {

@@ -22,7 +21,7 @@ inline constexpr U64 occupancy(U64 index, uint8_t bits_in_mask, U64 attack_mask)

return occupancy;
}
inline constexpr U64 mask(const square::Square square, U64 block, const bitboard::direction_f dir[4],
inline constexpr U64 mask(const Square square, U64 block, const bitboard::direction_f dir[4],
const int len[4]) {
U64 bitboard = C64(0), attacks = C64(0);
bit::set(bitboard, square);

diff --git a/src/bitboard/bitboard.cpp b/src/bitboard/bitboard.cpp

@@ -1,10 +1,22 @@

#include "bitboard.hpp"
#include "bit.hpp"
#include "piece.hpp"
#include <iostream>
namespace bitboard {
/*
void init() {
for (Square s1 = Square::a1; s1 <= Square::h8; ++s1) {
for (Square s2 = Square::a1; s2 <= Square::h8; ++s2) {
line[s1][s2] |=
(piece::get_attack(piece::BISHOP, s1, 0) & piece::get_attack(piece::BISHOP, s2, 0)) | s1 | s2;
}
}
}
*/
void print(U64 bitboard) {
for (int rank = 0; rank < 8; rank++) {
for (int file = 0; file < 8; file++) {

diff --git a/src/bitboard/bitboard.hpp b/src/bitboard/bitboard.hpp

@@ -1,11 +1,11 @@

#ifndef STELLAR_BITBOARD_H
#define STELLAR_BITBOARD_H
#include "square.hpp"
#include "utils.hpp"
namespace bitboard {
void init(void);
void print(U64 bitboard);
inline constexpr const U64 notAFile = C64(0xfefefefefefefefe);

@@ -21,6 +21,8 @@ inline constexpr U64 soWeOne(U64 b) { return (b & notAFile) >> 9; }

inline constexpr U64 noEaOne(U64 b) { return (b & notHFile) << 9; }
inline constexpr U64 noWeOne(U64 b) { return (b & notAFile) << 7; }
extern U64 line[Square::no_sq][Square::no_sq];
} // namespace bitboard
#endif

diff --git a/src/board/board.cpp b/src/board/board.cpp

@@ -5,8 +5,7 @@

#include "board.hpp"
#include "piece.hpp"
#include "square.hpp"
#include "utils.hpp"
#include "utils_ui.hpp"
#include "zobrist.hpp"
/* Init arrays for Zobris hashing */

@@ -21,7 +20,7 @@ Board::Board(const std::string &fen) {

for (i = 0; fen[i] != ' '; i++) {
if (isalpha(fen[i])) {
const piece::Piece &piece = piece::get_from_code(fen[i]);
set_piece(piece.type, piece.color, static_cast<square::Square>(rank * 8 + file));
set_piece(piece.type, piece.color, static_cast<Square>(rank * 8 + file));
file++;
} else if (isdigit(fen[i])) {
file += fen[i] - '0';

@@ -34,9 +33,7 @@ Board::Board(const std::string &fen) {

}
}
side = fen[++i] == 'w' ? color::WHITE
: fen[i] == 'b' ? color::BLACK
: throw std::runtime_error("Invalid player char");
side = fen[++i] == 'w' ? WHITE : fen[i] == 'b' ? BLACK : throw std::runtime_error("Invalid player char");
for (i += 2; fen[i] != ' '; i++) {
if (fen[i] == 'K') castle |= Castle::WK;

@@ -53,7 +50,7 @@ Board::Board(const std::string &fen) {

throw std::runtime_error("Invalid castle rights");
}
enpassant = fen[++i] != '-' ? square::from_coordinates(fen.substr(i, 2)) : square::no_sq;
enpassant = fen[++i] != '-' ? from_coordinates(fen.substr(i, 2)) : Square::no_sq;
hash = zobrist::hash(*this);
}

@@ -62,7 +59,7 @@ std::ostream &operator<<(std::ostream &os, const Board &board) {

for (int rank = 0; rank < 8; rank++) {
for (int file = 0; file < 8; file++) {
if (!file) os << 8 - rank << " ";
auto square = static_cast<square::Square>((7 - rank) * 8 + file);
auto square = static_cast<Square>((7 - rank) * 8 + file);
const piece::Piece *piece = board.get_square_piece(square);
os << (piece ? piece->code : '.') << " ";
}

@@ -70,8 +67,8 @@ std::ostream &operator<<(std::ostream &os, const Board &board) {

}
os << " A B C D E F G H\n";
os << " Side: ";
os << ((board.side == color::WHITE) ? "white" : "black") << "\n";
os << "Enpassant: " << square::to_coordinates(board.enpassant) << "\n";
os << ((board.side == WHITE) ? "white" : "black") << "\n";
os << "Enpassant: " << to_coordinates(board.enpassant) << "\n";
os << " Castle:";
os << ((board.castle & Board::Castle::WK) ? 'K' : '-');
os << ((board.castle & Board::Castle::WQ) ? 'Q' : '-');

diff --git a/src/board/board.hpp b/src/board/board.hpp

@@ -3,9 +3,7 @@

#include "attack.hpp"
#include "bit.hpp"
#include "color.hpp"
#include "piece.hpp"
#include "square.hpp"
#include "utils.hpp"
#include "zobrist.hpp"

@@ -31,105 +29,101 @@ class Board {

/* Getters */
[[nodiscard]] inline constexpr U64 get_hash() const;
[[nodiscard]] inline constexpr color::Color get_side() const;
[[nodiscard]] inline constexpr Color get_side() const;
[[nodiscard]] inline constexpr uint8_t get_castle() const;
[[nodiscard]] inline constexpr square::Square get_enpassant() const;
[[nodiscard]] inline constexpr Square get_enpassant() const;
[[nodiscard]] inline constexpr U64 get_bitboard_color(color::Color side) const;
[[nodiscard]] inline constexpr U64 get_bitboard_color(Color side) const;
[[nodiscard]] inline constexpr U64 get_bitboard_occupancy() const;
[[nodiscard]] inline constexpr U64 get_bitboard_piece(piece::Type piece) const;
[[nodiscard]] inline constexpr U64 get_bitboard_piece(piece::Type piece, color::Color color) const;
[[nodiscard]] inline constexpr U64 get_bitboard_piece(piece::Type piece, Color color) const;
[[nodiscard]] inline constexpr U64 get_bitboard_piece_attacks(piece::Type piece, color::Color color,
square::Square from) const;
[[nodiscard]] inline constexpr U64 get_bitboard_piece_moves(piece::Type piece, color::Color color,
square::Square from) const;
[[nodiscard]] inline constexpr U64 get_bitboard_square_land(square::Square land, piece::Type piece,
color::Color side) const;
[[nodiscard]] inline constexpr U64 get_bitboard_piece_attacks(piece::Type piece, Color color,
Square from) const;
[[nodiscard]] inline constexpr U64 get_bitboard_piece_moves(piece::Type piece, Color color,
Square from) const;
[[nodiscard]] inline constexpr U64 get_bitboard_square_land(Square land, piece::Type piece,
Color side) const;
[[nodiscard]] inline constexpr color::Color get_square_piece_color(square::Square square) const;
[[nodiscard]] inline constexpr piece::Type get_square_piece_type(square::Square square) const;
[[nodiscard]] inline constexpr const piece::Piece *get_square_piece(square::Square square) const;
[[nodiscard]] inline constexpr Color get_square_piece_color(Square square) const;
[[nodiscard]] inline constexpr piece::Type get_square_piece_type(Square square) const;
[[nodiscard]] inline constexpr const piece::Piece *get_square_piece(Square square) const;
/* Setters */
inline constexpr void xor_hash(U64 op);
inline constexpr void switch_side();
inline constexpr void and_castle(uint8_t right);
inline constexpr void set_enpassant(square::Square target);
inline constexpr void set_enpassant(Square target);
inline constexpr void pop_bitboard_color(color::Color color, square::Square square);
inline constexpr void set_bitboard_color(color::Color color, square::Square square);
inline constexpr void pop_bitboard_color(Color color, Square square);
inline constexpr void set_bitboard_color(Color color, Square square);
inline constexpr void pop_bitboard_piece(piece::Type type, square::Square square);
inline constexpr void set_bitboard_piece(piece::Type type, square::Square square);
inline constexpr void pop_bitboard_piece(piece::Type type, Square square);
inline constexpr void set_bitboard_piece(piece::Type type, Square square);
inline constexpr void pop_piece(piece::Type type, color::Color side, square::Square square);
inline constexpr void set_piece(piece::Type type, color::Color side, square::Square square);
inline constexpr void pop_piece(piece::Type type, Color side, Square square);
inline constexpr void set_piece(piece::Type type, Color side, Square square);
/* Queries */
[[nodiscard]] inline constexpr bool is_square_attacked(square::Square square, color::Color side) const;
[[nodiscard]] inline constexpr bool is_square_occupied(square::Square square) const;
[[nodiscard]] inline constexpr bool is_piece_attack_square(piece::Type type, color::Color color,
square::Square source,
square::Square target) const;
[[nodiscard]] inline constexpr bool is_square_attacked(Square square, Color side) const;
[[nodiscard]] inline constexpr bool is_square_occupied(Square square) const;
[[nodiscard]] inline constexpr bool is_piece_attack_square(piece::Type type, Color color, Square source,
Square target) const;
[[nodiscard]] inline constexpr bool is_check() const;
private:
U64 colors[2] = {0};
U64 pieces[6] = {0};
U64 hash = 0;
color::Color side = color::WHITE;
square::Square enpassant = square::Square::no_sq;
Color side = WHITE;
Square enpassant = Square::no_sq;
uint8_t castle = 0;
};
constexpr color::Color Board::get_side() const { return side; }
constexpr Color Board::get_side() const { return side; }
constexpr U64 Board::get_hash() const { return hash; }
constexpr uint8_t Board::get_castle() const { return castle; }
constexpr square::Square Board::get_enpassant() const { return enpassant; }
constexpr Square Board::get_enpassant() const { return enpassant; }
constexpr U64 Board::get_bitboard_color(color::Color side) const { return colors[side]; }
constexpr U64 Board::get_bitboard_occupancy() const { return colors[color::WHITE] | colors[color::BLACK]; }
constexpr U64 Board::get_bitboard_color(Color side) const { return colors[side]; }
constexpr U64 Board::get_bitboard_occupancy() const { return colors[WHITE] | colors[BLACK]; }
constexpr U64 Board::get_bitboard_piece(piece::Type piece) const { return pieces[piece]; }
constexpr U64 Board::get_bitboard_piece(piece::Type piece, color::Color color) const {
constexpr U64 Board::get_bitboard_piece(piece::Type piece, Color color) const {
return pieces[piece] & colors[color];
}
constexpr U64 Board::get_bitboard_piece_attacks(piece::Type type, color::Color color,
square::Square from) const {
constexpr U64 Board::get_bitboard_piece_attacks(piece::Type type, Color color, Square from) const {
if (type == piece::PAWN) return attack::attack_pawn(color, from);
return attack::attack(type, from, get_bitboard_occupancy());
}
constexpr U64 Board::get_bitboard_piece_moves(piece::Type type, color::Color color,
square::Square square) const {
constexpr U64 Board::get_bitboard_piece_moves(piece::Type type, Color color, Square square) const {
return get_bitboard_piece_attacks(type, color, square) & ~get_bitboard_color(color);
}
constexpr U64 Board::get_bitboard_square_land(square::Square land, piece::Type piece,
color::Color side) const {
constexpr U64 Board::get_bitboard_square_land(Square land, piece::Type piece, Color side) const {
return get_bitboard_piece_attacks(piece, color::other(side), land) & get_bitboard_piece(piece, side);
return get_bitboard_piece_attacks(piece, other(side), land) & get_bitboard_piece(piece, side);
}
constexpr color::Color Board::get_square_piece_color(square::Square square) const {
if (bit::get(colors[color::WHITE], square)) return color::WHITE;
if (bit::get(colors[color::BLACK], square)) return color::BLACK;
constexpr Color Board::get_square_piece_color(Square square) const {
if (bit::get(colors[WHITE], square)) return WHITE;
if (bit::get(colors[BLACK], square)) return BLACK;
throw std::exception();
}
constexpr piece::Type Board::get_square_piece_type(square::Square square) const {
constexpr piece::Type Board::get_square_piece_type(Square square) const {
for (piece::Type type = piece::PAWN; type <= piece::KING; ++type) {
if (bit::get(pieces[type], square)) return type;
}
return piece::Type::NONE;
}
constexpr const piece::Piece *Board::get_square_piece(square::Square square) const {
constexpr const piece::Piece *Board::get_square_piece(Square square) const {
try {
return &piece::get(get_square_piece_type(square), get_square_piece_color(square));
} catch (std::exception &e) {

@@ -147,50 +141,39 @@ constexpr void Board::and_castle(uint8_t right) {

}
constexpr void Board::switch_side() {
side = color::other(side);
side = other(side);
hash ^= zobrist::key_side();
}
constexpr void Board::set_enpassant(square::Square target) {
if (enpassant != square::Square::no_sq) hash ^= zobrist::key_enpassant(enpassant);
if (target != square::Square::no_sq) hash ^= zobrist::key_enpassant(target);
constexpr void Board::set_enpassant(Square target) {
if (enpassant != Square::no_sq) hash ^= zobrist::key_enpassant(enpassant);
if (target != Square::no_sq) hash ^= zobrist::key_enpassant(target);
enpassant = target;
}
constexpr void Board::pop_bitboard_color(color::Color color, square::Square square) {
bit::pop(colors[color], square);
}
constexpr void Board::set_bitboard_color(color::Color color, square::Square square) {
bit::set(colors[color], square);
}
constexpr void Board::pop_bitboard_piece(piece::Type type, square::Square square) {
bit::pop(pieces[type], square);
}
constexpr void Board::set_bitboard_piece(piece::Type type, square::Square square) {
bit::set(pieces[type], square);
}
constexpr void Board::pop_bitboard_color(Color color, Square square) { bit::pop(colors[color], square); }
constexpr void Board::set_bitboard_color(Color color, Square square) { bit::set(colors[color], square); }
constexpr void Board::pop_bitboard_piece(piece::Type type, Square square) { bit::pop(pieces[type], square); }
constexpr void Board::set_bitboard_piece(piece::Type type, Square square) { bit::set(pieces[type], square); }
constexpr void Board::pop_piece(piece::Type type, color::Color side, square::Square square) {
constexpr void Board::pop_piece(piece::Type type, Color side, Square square) {
pop_bitboard_color(side, square);
pop_bitboard_piece(type, square);
}
constexpr void Board::set_piece(piece::Type type, color::Color side, square::Square square) {
constexpr void Board::set_piece(piece::Type type, Color side, Square square) {
set_bitboard_color(side, square);
set_bitboard_piece(type, square);
}
/* Queries */
constexpr bool Board::is_square_occupied(square::Square square) const {
constexpr bool Board::is_square_occupied(Square square) const {
return bit::get(get_bitboard_occupancy(), square);
}
constexpr bool Board::is_square_attacked(square::Square square, color::Color side) const {
const color::Color side_other = color::other(side);
constexpr bool Board::is_square_attacked(Square square, Color side) const {
const Color side_other = other(side);
for (piece::Type type = piece::PAWN; type <= piece::KING; ++type) {
if (get_bitboard_piece_attacks(type, side_other, square) & get_bitboard_piece(type, side)) {

@@ -201,15 +184,15 @@ constexpr bool Board::is_square_attacked(square::Square square, color::Color sid

return false;
}
constexpr bool Board::is_piece_attack_square(piece::Type type, color::Color color, square::Square source,
square::Square target) const {
constexpr bool Board::is_piece_attack_square(piece::Type type, Color color, Square source,
Square target) const {
return get_bitboard_piece_attacks(type, color, source) & (C64(1) << target);
}
constexpr bool Board::is_check() const {
U64 king = pieces[piece::Type::KING] & colors[side];
color::Color side_other = (side == color::BLACK) ? color::WHITE : color::BLACK;
auto square = static_cast<square::Square>(bit::lsb_index(king));
Color side_other = (side == BLACK) ? WHITE : BLACK;
auto square = static_cast<Square>(bit::lsb_index(king));
return is_square_attacked(square, side_other);
}

@@ -218,19 +201,19 @@ U64 zobrist::hash(const Board &board) {

uint8_t square = 0;
for (piece::Type type = piece::PAWN; type <= piece::KING; ++type) {
int piece_white_index = piece::get_index(type, color::WHITE);
U64 bitboard_white = board.get_bitboard_piece(type, color::WHITE);
int piece_white_index = piece::get_index(type, WHITE);
U64 bitboard_white = board.get_bitboard_piece(type, WHITE);
bitboard_for_each_bit(square, bitboard_white) { key_final ^= keys_piece[piece_white_index][square]; }
int piece_black_index = piece::get_index(type, color::BLACK);
U64 bitboard_black = board.get_bitboard_piece(type, color::BLACK);
int piece_black_index = piece::get_index(type, BLACK);
U64 bitboard_black = board.get_bitboard_piece(type, BLACK);
bitboard_for_each_bit(square, bitboard_black) { key_final ^= keys_piece[piece_black_index][square]; }
}
key_final ^= keys_castle[board.get_castle()];
if (board.get_side() == color::BLACK) key_final ^= keys_side;
if (board.get_enpassant() != square::Square::no_sq) key_final ^= keys_enpassant[board.get_enpassant()];
if (board.get_side() == BLACK) key_final ^= keys_side;
if (board.get_enpassant() != Square::no_sq) key_final ^= keys_enpassant[board.get_enpassant()];
return key_final;
}

diff --git a/src/board/zobrist.hpp b/src/board/zobrist.hpp

@@ -20,8 +20,8 @@ const U64 keys_side = Random(C32(1699391443))();

inline void init() {
Random gen1(C64(1804289383));
for (piece::Type type = piece::PAWN; type <= piece::KING; ++type) {
int piece_index_white = piece::get(type, color::Color::WHITE).index;
int piece_index_black = piece::get(type, color::Color::BLACK).index;
int piece_index_white = piece::get(type, Color::WHITE).index;
int piece_index_black = piece::get(type, Color::BLACK).index;
for (int square = 0; square < 64; square++) {
keys_piece[piece_index_white][square] = gen1();
keys_piece[piece_index_black][square] = gen1();

@@ -42,8 +42,8 @@ inline void init() {

inline U64 hash(const Board &board);
inline constexpr U64 key_side() { return keys_side; }
inline constexpr U64 key_castle(int exp) { return keys_castle[exp]; }
inline constexpr U64 key_enpassant(square::Square square) { return keys_enpassant[square]; }
inline constexpr U64 key_piece(piece::Type type, color::Color color, square::Square square) {
inline constexpr U64 key_enpassant(Square square) { return keys_enpassant[square]; }
inline constexpr U64 key_piece(piece::Type type, Color color, Square square) {
return keys_piece[piece::get_index(type, color)][square];
}

diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp

@@ -194,7 +194,7 @@ int stats_move_make(Board &copy, const Move move) {

void stats_move_make_pruning(Board &copy) {
copy = board;
board.switch_side();
board.set_enpassant(square::no_sq);
board.set_enpassant(Square::no_sq);
ply++;
}

diff --git a/src/engine/evaluate.cpp b/src/engine/evaluate.cpp

@@ -3,7 +3,6 @@

#include "bitboard.hpp"
#include "piece.hpp"
#include "score.hpp"
#include "square.hpp"
#include "utils.hpp"
#include <array>

@@ -83,7 +82,7 @@ uint16_t score_game_phase(const Board &board) {

return total;
}
int16_t score_position_side(const Board &board, const color::Color side, const uint16_t phase_score) {
int16_t score_position_side(const Board &board, const Color side, const uint16_t phase_score) {
U64 bitboard;
int16_t total = 0, opening = 0, endgame = 0;

@@ -95,12 +94,12 @@ int16_t score_position_side(const Board &board, const color::Color side, const u

bitboard = board.get_bitboard_piece(PAWN, side);
bitboard_for_each_bit(square_i, bitboard) {
const auto square = static_cast<square::Square>(square_i);
const auto square = static_cast<Square>(square_i);
opening += score::get(PAWN, side, square, OPENING) + score::get(PAWN, OPENING);
endgame += score::get(PAWN, side, square, ENDGAME) + score::get(PAWN, ENDGAME);
// check isolated, doubled and passed pawns
const uint8_t file = square::file(square), rank = square::rank(square);
const uint8_t file = get_file(square), rank = get_rank(square);
if (!(mask_isolated[file] & pawnsS)) {
opening -= score::pawn_isolated_opening;
endgame -= score::pawn_isolated_endgame;

@@ -116,45 +115,45 @@ int16_t score_position_side(const Board &board, const color::Color side, const u

bitboard = board.get_bitboard_piece(KNIGHT, side);
bitboard_for_each_bit(square_i, bitboard) {
const auto square = static_cast<square::Square>(square_i);
const auto square = static_cast<Square>(square_i);
opening += score::get(KNIGHT, side, square, OPENING) + score::get(KNIGHT, OPENING);
endgame += score::get(KNIGHT, side, square, ENDGAME) + score::get(KNIGHT, ENDGAME);
}
bitboard = board.get_bitboard_piece(BISHOP, side);
bitboard_for_each_bit(square_i, bitboard) {
const auto square = static_cast<square::Square>(square_i);
const auto square = static_cast<Square>(square_i);
opening += score::get(BISHOP, side, square, OPENING) + score::get(BISHOP, OPENING);
endgame += score::get(BISHOP, side, square, ENDGAME) + score::get(BISHOP, ENDGAME);
}
bitboard = board.get_bitboard_piece(ROOK, side);
bitboard_for_each_bit(square_i, bitboard) {
const auto square = static_cast<square::Square>(square_i);
const auto square = static_cast<Square>(square_i);
opening += score::get(ROOK, side, square, OPENING) + score::get(ROOK, OPENING);
endgame += score::get(ROOK, side, square, ENDGAME) + score::get(ROOK, ENDGAME);
// rook on open and semi-open files
const uint8_t file = square::file(square);
const uint8_t file = get_file(square);
if (!(pawns & mask_file[file])) total += score::file_open;
if (!(pawnsS & mask_file[file])) total += score::file_open_semi;
}
bitboard = board.get_bitboard_piece(QUEEN, side);
bitboard_for_each_bit(square_i, bitboard) {
const auto square = static_cast<square::Square>(square_i);
const auto square = static_cast<Square>(square_i);
opening += score::get(QUEEN, side, square, OPENING) + score::get(QUEEN, OPENING);
endgame += score::get(QUEEN, side, square, ENDGAME) + score::get(QUEEN, ENDGAME);
}
bitboard = board.get_bitboard_piece(KING, side);
bitboard_for_each_bit(square_i, bitboard) {
const auto square = static_cast<square::Square>(square_i);
const auto square = static_cast<Square>(square_i);
opening += score::get(KING, side, square, OPENING) + score::get(KING, OPENING);
endgame += score::get(KING, side, square, ENDGAME) + score::get(KING, ENDGAME);
// king on open and semi-open files
const uint8_t file = square::file(square);
const uint8_t file = get_file(square);
if (!(pawns & mask_file[file])) total -= score::file_open;
if (!(pawnsS & mask_file[file])) total -= score::file_open_semi;
}

@@ -167,9 +166,9 @@ int16_t score_position_side(const Board &board, const color::Color side, const u

int16_t score_position(const Board &board) {
const uint16_t phase_score = score_game_phase(board);
const int16_t score = score_position_side(board, color::WHITE, phase_score) -
score_position_side(board, color::BLACK, phase_score);
return board.get_side() == color::WHITE ? score : -score;
const int16_t score =
score_position_side(board, WHITE, phase_score) - score_position_side(board, BLACK, phase_score);
return board.get_side() == WHITE ? score : -score;
}
} // namespace evaluate

diff --git a/src/engine/score.hpp b/src/engine/score.hpp

@@ -150,9 +150,8 @@ inline constexpr int16_t get(const piece::Type piece, const Phase phase = OPENIN

return value[phase][piece];
}
inline constexpr int16_t get(piece::Type piece, color::Color color, square::Square square,
Phase phase = ENDGAME) {
if (color != color::WHITE) square = square::mirror(square);
inline constexpr int16_t get(piece::Type piece, Color color, Square square, Phase phase = ENDGAME) {
if (color != WHITE) square = get_mirror(square);
return position[phase][piece][square];
}

diff --git a/src/engine/uci.cpp b/src/engine/uci.cpp

@@ -18,8 +18,8 @@ void communicate(const uci::Settings *settings) {

}
inline bool parse_move(const Board &board, Move &move, const std::string &move_string) {
const square::Square source = square::from_coordinates(move_string.substr(0, 2));
const square::Square target = square::from_coordinates(move_string.substr(2, 2));
const Square source = from_coordinates(move_string.substr(0, 2));
const Square target = from_coordinates(move_string.substr(2, 2));
const MoveList list(board);
for (int i = 0; i < list.size(); i++) {

@@ -85,8 +85,7 @@ void loop() {

uint16_t winc = 0, binc = 0, movestogo = 60;
while (iss >> command) {
if (command == "wtime")
iss >> wtime;
if (command == "wtime") iss >> wtime;
else if (command == "btime")
iss >> btime;
else if (command == "winc")

@@ -116,13 +115,13 @@ void loop() {

}
settings.starttime = timer::get_ms();
uint64_t time = (board.get_side() == color::WHITE) ? wtime : btime;
uint64_t time = (board.get_side() == WHITE) ? wtime : btime;
if (movetime != 0) {
time = movetime;
movestogo = 1;
} else if (time != 0) {
uint16_t inc = (board.get_side() == color::WHITE) ? winc : binc;
uint16_t inc = (board.get_side() == WHITE) ? winc : binc;
time /= movestogo;
time -= 50;
settings.stoptime = settings.starttime + time + inc;

diff --git a/src/engine/uci.hpp b/src/engine/uci.hpp

@@ -6,6 +6,7 @@

#include "movelist.hpp"
#include "score.hpp"
#include "utils.hpp"
#include "utils_ui.hpp"
namespace uci {

diff --git a/src/move/move.cpp b/src/move/move.cpp

@@ -1,21 +1,21 @@

#include "move.hpp"
#include "utils.hpp"
#include "utils_ui.hpp"
#include <algorithm>
#include <iomanip>
void Move::piece_remove(Board &board, piece::Type type, color::Color color, square::Square square) const {
void Move::piece_remove(Board &board, piece::Type type, Color color, Square square) const {
board.pop_piece(type, color, square);
board.xor_hash(zobrist::key_piece(type, color, square));
}
void Move::piece_set(Board &board, piece::Type type, color::Color color, square::Square square) const {
void Move::piece_set(Board &board, piece::Type type, Color color, Square square) const {
board.set_piece(type, color, square);
board.xor_hash(zobrist::key_piece(type, color, square));
}
void Move::piece_move(Board &board, piece::Type type, color::Color color, square::Square source,
square::Square target) const {
void Move::piece_move(Board &board, piece::Type type, Color color, Square source, Square target) const {
piece_remove(board, type, color, source);
piece_set(board, type, color, target);
}

@@ -37,11 +37,10 @@ bool Move::make(Board &board) const {

// clang-format on
};
const color::Color color = board.get_side(), colorOther = color::other(color);
const square::Square source = this->source(), target = this->target();
const Color color = board.get_side(), colorOther = other(color);
const Square source = this->source(), target = this->target();
const auto ntarget =
static_cast<square::Square>(this->target() + (color == color::Color::WHITE ? -8 : +8));
const auto ntarget = static_cast<Square>(this->target() + (color == Color::WHITE ? -8 : +8));
const piece::Type piece = board.get_square_piece_type(source);

@@ -67,19 +66,15 @@ bool Move::make(Board &board) const {

}
}
board.set_enpassant(is_double() ? ntarget : square::Square::no_sq);
board.set_enpassant(is_double() ? ntarget : Square::no_sq);
if (is_castle()) {
if (color == color::Color::WHITE) {
if (is_castle_king())
piece_move(board, ROOK, color::Color::WHITE, square::Square::h1, square::Square::f1);
if (is_castle_queen())
piece_move(board, ROOK, color::Color::WHITE, square::Square::a1, square::Square::d1);
if (color == Color::WHITE) {
if (is_castle_king()) piece_move(board, ROOK, Color::WHITE, Square::h1, Square::f1);
if (is_castle_queen()) piece_move(board, ROOK, Color::WHITE, Square::a1, Square::d1);
} else {
if (is_castle_king())
piece_move(board, ROOK, color::Color::BLACK, square::Square::h8, square::Square::f8);
if (is_castle_queen())
piece_move(board, ROOK, color::Color::BLACK, square::Square::a8, square::Square::d8);
if (is_castle_king()) piece_move(board, ROOK, Color::BLACK, Square::h8, Square::f8);
if (is_castle_queen()) piece_move(board, ROOK, Color::BLACK, Square::a8, Square::d8);
}
}

@@ -93,8 +88,8 @@ bool Move::make(Board &board) const {

}
void Move::print() const {
std::cout << square::to_coordinates(source()) << " ";
std::cout << square::to_coordinates(target()) << " ";
std::cout << to_coordinates(source()) << " ";
std::cout << to_coordinates(target()) << " ";
std::cout << (is_promote() ? piece::get_code(promoted()) : '.') << " ";
std::cout << is_double() << " ";
std::cout << is_enpassant() << " ";

@@ -102,7 +97,7 @@ void Move::print() const {

}
Move::operator std::string() const {
std::string res = square::to_coordinates(source()) + square::to_coordinates(target());
std::string res = to_coordinates(source()) + to_coordinates(target());
if (is_promote()) res += piece::get_code(promoted());
return res;
}

diff --git a/src/move/move.hpp b/src/move/move.hpp

@@ -28,15 +28,14 @@ struct Move {

};
Move() : source_i(0), target_i(0), flags_i(0) {}
Move(square::Square source, square::Square target, Flag flags)
: source_i(source), target_i(target), flags_i(flags) {}
Move(Square source, Square target, Flag flags) : source_i(source), target_i(target), flags_i(flags) {}
friend bool operator==(const Move a, const Move b) {
return a.source_i == b.source_i && a.target_i == b.target_i && a.flags_i == b.flags_i;
}
[[nodiscard]] square::Square source() const { return static_cast<square::Square>(source_i); }
[[nodiscard]] square::Square target() const { return static_cast<square::Square>(target_i); }
[[nodiscard]] Square source() const { return static_cast<Square>(source_i); }
[[nodiscard]] Square target() const { return static_cast<Square>(target_i); }
[[nodiscard]] bool is_capture() const { return flags_i != PQUIET && (flags_i & CAPTURE); }
[[nodiscard]] bool is_promote() const { return flags_i & 0x8; }

@@ -60,10 +59,9 @@ struct Move {

void print() const;
private:
inline void piece_remove(Board &board, piece::Type type, color::Color color, square::Square square) const;
inline void piece_set(Board &board, piece::Type type, color::Color color, square::Square square) const;
inline void piece_move(Board &board, piece::Type type, color::Color color, square::Square source,
square::Square target) const;
inline void piece_remove(Board &board, piece::Type type, Color color, Square square) const;
inline void piece_set(Board &board, piece::Type type, Color color, Square square) const;
inline void piece_move(Board &board, piece::Type type, Color color, Square source, Square target) const;
unsigned source_i : 6;
unsigned target_i : 6;

diff --git a/src/move/movelist.cpp b/src/move/movelist.cpp

@@ -1,30 +1,29 @@

#include "movelist.hpp"
#include "color.hpp"
#include "piece.hpp"
#include <iomanip>
#define pawn_canPromote(color, source) \
((color == color::WHITE && source >= square::a7 && source <= square::h7) || \
(color == color::BLACK && source >= square::a2 && source <= square::h2))
((color == WHITE && source >= Square::a7 && source <= Square::h7) || \
(color == BLACK && source >= Square::a2 && source <= Square::h2))
#define pawn_onStart(color, source) \
((color == color::BLACK && source >= square::a7 && source <= square::h7) || \
(color == color::WHITE && source >= square::a2 && source <= square::h2))
((color == BLACK && source >= Square::a7 && source <= Square::h7) || \
(color == WHITE && source >= Square::a2 && source <= Square::h2))
using piece::Type::PAWN;
void MoveList::generate(const Board &board, bool attacks_only) {
uint8_t src_i = 0, tgt_i = 0;
const color::Color color = board.get_side(), colorOther = color::other(color);
const Color color = board.get_side(), colorOther = other(color);
// pawn moves
const int add = (color == color::WHITE) ? +8 : -8;
const int add = (color == WHITE) ? +8 : -8;
U64 bitboard = board.get_bitboard_piece(PAWN, color);
bitboard_for_each_bit(src_i, bitboard) {
const auto src = static_cast<square::Square>(src_i);
const auto tgt = static_cast<square::Square>(tgt_i = src_i + add);
const auto src = static_cast<Square>(src_i);
const auto tgt = static_cast<Square>(tgt_i = src_i + add);
if (!attacks_only && !board.is_square_occupied(tgt)) {
if (pawn_canPromote(color, src)) {
list.emplace_back(src, tgt, Move::PKNIGHT);

@@ -35,7 +34,7 @@ void MoveList::generate(const Board &board, bool attacks_only) {

list.emplace_back(src, tgt, Move::PQUIET);
// two ahead
const auto tgt = static_cast<square::Square>(tgt_i + add);
const auto tgt = static_cast<Square>(tgt_i + add);
if (pawn_onStart(color, src) && !board.is_square_occupied(tgt))
list.emplace_back(src, tgt, Move::DOUBLE);
}

@@ -45,7 +44,7 @@ void MoveList::generate(const Board &board, bool attacks_only) {

U64 attack =
board.get_bitboard_piece_attacks(PAWN, color, src) & board.get_bitboard_color(colorOther);
bitboard_for_each_bit(tgt_i, attack) {
const auto tgt = static_cast<square::Square>(tgt_i);
const auto tgt = static_cast<Square>(tgt_i);
if (pawn_canPromote(color, src)) {
list.emplace_back(src, tgt, Move::PCKNIGHT);
list.emplace_back(src, tgt, Move::PCBISHOP);

@@ -57,8 +56,8 @@ void MoveList::generate(const Board &board, bool attacks_only) {

}
// en passant
const square::Square enpassant = board.get_enpassant();
if (enpassant != square::no_sq && board.is_piece_attack_square(PAWN, color, src, enpassant))
const Square enpassant = board.get_enpassant();
if (enpassant != Square::no_sq && board.is_piece_attack_square(PAWN, color, src, enpassant))
list.emplace_back(src, enpassant, Move::ENPASSANT);
}

@@ -66,10 +65,10 @@ void MoveList::generate(const Board &board, bool attacks_only) {

for (piece::Type type = piece::KNIGHT; type <= piece::KING; ++type) {
U64 bitboard = board.get_bitboard_piece(type, color);
bitboard_for_each_bit(src_i, bitboard) {
const auto src = static_cast<square::Square>(src_i);
const auto src = static_cast<Square>(src_i);
U64 attack = board.get_bitboard_piece_moves(type, color, src);
bitboard_for_each_bit(tgt_i, attack) {
const auto tgt = static_cast<square::Square>(tgt_i);
const auto tgt = static_cast<Square>(tgt_i);
if (board.is_square_occupied(tgt)) {
list.emplace_back(src, tgt, Move::CAPTURE);
} else {

@@ -83,34 +82,32 @@ void MoveList::generate(const Board &board, bool attacks_only) {

if (attacks_only) return;
// Castling
if (color == color::WHITE) {
if (!board.is_square_attacked(square::e1, color::BLACK)) {
if (color == WHITE) {
if (!board.is_square_attacked(Square::e1, BLACK)) {
if (board.get_castle() & Board::Castle::WK) {
if (!board.is_square_occupied(square::f1) && !board.is_square_occupied(square::g1) &&
!board.is_square_attacked(square::f1, color::BLACK))
list.emplace_back(square::e1, square::g1, Move::CASTLEK);
if (!board.is_square_occupied(Square::f1) && !board.is_square_occupied(Square::g1) &&
!board.is_square_attacked(Square::f1, BLACK))
list.emplace_back(Square::e1, Square::g1, Move::CASTLEK);
}
if (board.get_castle() & Board::Castle::WQ) {
if (!board.is_square_occupied(square::d1) && !board.is_square_occupied(square::c1) &&
!board.is_square_occupied(square::b1) &&
!board.is_square_attacked(square::d1, color::BLACK) &&
!board.is_square_attacked(square::c1, color::BLACK))
list.emplace_back(square::e1, square::c1, Move::CASTLEQ);
if (!board.is_square_occupied(Square::d1) && !board.is_square_occupied(Square::c1) &&
!board.is_square_occupied(Square::b1) && !board.is_square_attacked(Square::d1, BLACK) &&
!board.is_square_attacked(Square::c1, BLACK))
list.emplace_back(Square::e1, Square::c1, Move::CASTLEQ);
}
}
} else {
if (!board.is_square_attacked(square::e8, color::WHITE)) {
if (!board.is_square_attacked(Square::e8, WHITE)) {
if (board.get_castle() & Board::Castle::BK) {
if (!board.is_square_occupied(square::f8) && !board.is_square_occupied(square::g8) &&
!board.is_square_attacked(square::f8, color::WHITE))
list.emplace_back(square::Square::e8, square::Square::g8, Move::CASTLEK);
if (!board.is_square_occupied(Square::f8) && !board.is_square_occupied(Square::g8) &&
!board.is_square_attacked(Square::f8, WHITE))
list.emplace_back(Square::e8, Square::g8, Move::CASTLEK);
}
if (board.get_castle() & Board::Castle::BQ) {
if (!board.is_square_occupied(square::d8) && !board.is_square_occupied(square::c8) &&
!board.is_square_occupied(square::b8) &&
!board.is_square_attacked(square::d8, color::WHITE) &&
!board.is_square_attacked(square::c8, color::WHITE))
list.emplace_back(square::e8, square::c8, Move::CASTLEQ);
if (!board.is_square_occupied(Square::d8) && !board.is_square_occupied(Square::c8) &&
!board.is_square_occupied(Square::b8) && !board.is_square_attacked(Square::d8, WHITE) &&
!board.is_square_attacked(Square::c8, WHITE))
list.emplace_back(Square::e8, Square::c8, Move::CASTLEQ);
}
}
}

diff --git a/src/move/movelist.hpp b/src/move/movelist.hpp

@@ -21,7 +21,7 @@ class MoveList {

if (!legal) return;
int size = 0;
for (const auto& move : list) {
for (const auto &move : list) {
Board copy = board;
if (move.make(copy)) list[size++] = move;
}

diff --git a/src/perft/perft.cpp b/src/perft/perft.cpp

@@ -12,7 +12,7 @@

#define tricky_position "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1 "
enum {
THREAD_MAX = 64
THREAD_MAX = 64
};
class Perft {

@@ -68,8 +68,7 @@ class Perft {

Board copy = board;
if (!list[i].make(copy)) continue;
// debug(board, list[i], copy);
if (depth != 1)
test(copy, depth - 1);
if (depth != 1) test(copy, depth - 1);
else
score(copy, list[i]);
}

diff --git a/src/piece/piece.hpp b/src/piece/piece.hpp

@@ -1,10 +1,10 @@

#ifndef STELLAR_PIECE_H
#define STELLAR_PIECE_H
#include "color.hpp"
#include "utils.hpp"
#include <cctype>
#include <exception>
namespace piece {

@@ -23,42 +23,40 @@ ENABLE_INCR_OPERATORS_ON(Type)

struct Piece {
const uint8_t index;
const Type type;
const color::Color color;
const Color color;
const char code;
};
inline constexpr const Piece table[2][6] = {
// clang-format off
{
{ .index = 0, .type = PAWN, .color = color::WHITE, .code = 'P' },
{ .index = 1, .type = KNIGHT, .color = color::WHITE, .code = 'N' },
{ .index = 2, .type = BISHOP, .color = color::WHITE, .code = 'B' },
{ .index = 3, .type = ROOK, .color = color::WHITE, .code = 'R' },
{ .index = 4, .type = QUEEN, .color = color::WHITE, .code = 'Q' },
{ .index = 5, .type = KING, .color = color::WHITE, .code = 'K' },
{ .index = 0, .type = PAWN, .color = WHITE, .code = 'P' },
{ .index = 1, .type = KNIGHT, .color = WHITE, .code = 'N' },
{ .index = 2, .type = BISHOP, .color = WHITE, .code = 'B' },
{ .index = 3, .type = ROOK, .color = WHITE, .code = 'R' },
{ .index = 4, .type = QUEEN, .color = WHITE, .code = 'Q' },
{ .index = 5, .type = KING, .color = WHITE, .code = 'K' },
}, {
{ .index = 6, .type = PAWN, .color = color::BLACK, .code = 'p' },
{ .index = 7, .type = KNIGHT, .color = color::BLACK, .code = 'n' },
{ .index = 8, .type = BISHOP, .color = color::BLACK, .code = 'b' },
{ .index = 9, .type = ROOK, .color = color::BLACK, .code = 'r' },
{.index = 10, .type = QUEEN, .color = color::BLACK, .code = 'q' },
{.index = 11, .type = KING, .color = color::BLACK, .code = 'k' },
{ .index = 6, .type = PAWN, .color = BLACK, .code = 'p' },
{ .index = 7, .type = KNIGHT, .color = BLACK, .code = 'n' },
{ .index = 8, .type = BISHOP, .color = BLACK, .code = 'b' },
{ .index = 9, .type = ROOK, .color = BLACK, .code = 'r' },
{.index = 10, .type = QUEEN, .color = BLACK, .code = 'q' },
{.index = 11, .type = KING, .color = BLACK, .code = 'k' },
},
// clang-format on
};
inline constexpr const Piece &get(const Type type, const color::Color color) { return table[color][type]; }
inline constexpr const Piece &get(const Type type, const Color color) { return table[color][type]; }
inline constexpr const char get_code(const Type type, const color::Color color = color::BLACK) {
inline constexpr const char get_code(const Type type, const Color color = BLACK) {
return get(type, color).code;
}
inline constexpr const U64 get_index(const Type type, const color::Color color) {
return get(type, color).index;
}
inline constexpr const U64 get_index(const Type type, const Color color) { return get(type, color).index; }
inline constexpr const Piece &get_from_code(const char code) {
color::Color color = isupper(code) ? color::WHITE : color::BLACK;
Color color = isupper(code) ? WHITE : BLACK;
for (Type type = PAWN; type <= KING; ++type) {
const Piece &piece = get(type, color);

diff --git a/src/utils/color.hpp b/src/utils/color.hpp

@@ -1,20 +0,0 @@

#ifndef STELLAR_COLOR_H
#define STELLAR_COLOR_H
#include <string>
namespace color {
enum Color {
WHITE = 0,
BLACK
};
inline constexpr const Color other(const Color color) { return color == WHITE ? BLACK : WHITE; }
inline constexpr const std::string to_string(const Color color) {
return std::string(color == WHITE ? "white" : "black");
}
} // namespace color
#endif

diff --git a/src/utils/repetition.hpp b/src/utils/repetition.hpp

@@ -1,6 +1,11 @@

#ifndef STELLAR_REPETITION_H
#define STELLAR_REPETITION_H
#include <iostream>
#include <vector>
#include "utils.hpp"
namespace repetition {
class Table {

diff --git a/src/utils/square.hpp b/src/utils/square.hpp

@@ -1,61 +0,0 @@

#ifndef STELLAR_SQUARE_H
#define STELLAR_SQUARE_H
#include "utils.hpp"
#include <string>
namespace square {
enum Square : int {
// clang-format off
a1, b1, c1, d1, e1, f1, g1, h1,
a2, b2, c2, d2, e2, f2, g2, h2,
a3, b3, c3, d3, e3, f3, g3, h3,
a4, b4, c4, d4, e4, f4, g4, h4,
a5, b5, c5, d5, e5, f5, g5, h5,
a6, b6, c6, d6, e6, f6, g6, h6,
a7, b7, c7, d7, e7, f7, g7, h7,
a8, b8, c8, d8, e8, f8, g8, h8, no_sq
// clang-format on
};
ENABLE_INCR_OPERATORS_ON(Square)
inline constexpr const Square mirror_array[]{
// clang-format off
a8, b8, c8, d8, e8, f8, g8, h8,
a7, b7, c7, d7, e7, f7, g7, h7,
a6, b6, c6, d6, e6, f6, g6, h6,
a5, b5, c5, d5, e5, f5, g5, h5,
a4, b4, c4, d4, e4, f4, g4, h4,
a3, b3, c3, d3, e3, f3, g3, h3,
a2, b2, c2, d2, e2, f2, g2, h2,
a1, b1, c1, d1, e1, f1, g1, h1, no_sq
// clang-format on
};
inline constexpr const char *coordinates_array[] = {
// clang-format off
"a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1",
"a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2",
"a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3",
"a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4",
"a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5",
"a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6",
"a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7",
"a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8", " "
// clang-format on
};
inline constexpr const uint8_t file(const Square square) { return square & 0x07; }
inline constexpr const uint8_t rank(const Square square) { return square >> 3; }
inline constexpr const Square mirror(const Square square) { return mirror_array[square]; }
inline constexpr const std::string to_coordinates(const Square square) { return coordinates_array[square]; }
inline const Square from_coordinates(const std::string &cord) {
return static_cast<Square>((cord[1] - '1') * 8 + (cord[0] - 'a'));
}
} // namespace square
#endif

diff --git a/src/utils/utils.hpp b/src/utils/utils.hpp

@@ -1,5 +1,5 @@

#ifndef STELLAR_UTILS_CPP_H
#define STELLAR_UTILS_CPP_H
#ifndef STELLAR_UTILS_HPP
#define STELLAR_UTILS_HPP
#include <cstdint>

@@ -13,4 +13,48 @@ typedef uint32_t U32;

inline T &operator++(T &d) { return d = T(int(d) + 1); } \
inline T &operator--(T &d) { return d = T(int(d) - 1); }
/* Color */
enum Color {
WHITE,
BLACK,
COLOR_NB = 2
};
inline constexpr const Color other(const Color color) { return color == WHITE ? BLACK : WHITE; }
/* Square */
enum Square : int {
// clang-format off
a1, b1, c1, d1, e1, f1, g1, h1,
a2, b2, c2, d2, e2, f2, g2, h2,
a3, b3, c3, d3, e3, f3, g3, h3,
a4, b4, c4, d4, e4, f4, g4, h4,
a5, b5, c5, d5, e5, f5, g5, h5,
a6, b6, c6, d6, e6, f6, g6, h6,
a7, b7, c7, d7, e7, f7, g7, h7,
a8, b8, c8, d8, e8, f8, g8, h8, no_sq
// clang-format on
};
ENABLE_INCR_OPERATORS_ON(Square)
constexpr const Square mirror_array[]{
// clang-format off
a8, b8, c8, d8, e8, f8, g8, h8,
a7, b7, c7, d7, e7, f7, g7, h7,
a6, b6, c6, d6, e6, f6, g6, h6,
a5, b5, c5, d5, e5, f5, g5, h5,
a4, b4, c4, d4, e4, f4, g4, h4,
a3, b3, c3, d3, e3, f3, g3, h3,
a2, b2, c2, d2, e2, f2, g2, h2,
a1, b1, c1, d1, e1, f1, g1, h1, no_sq
// clang-format on
};
constexpr uint8_t get_file(const Square square) { return square & 0x07; }
constexpr uint8_t get_rank(const Square square) { return square >> 3; }
constexpr Square get_mirror(const Square square) { return mirror_array[square]; }
#endif

diff --git a/src/utils/utils_ui.hpp b/src/utils/utils_ui.hpp

@@ -0,0 +1,35 @@

#ifndef STELLAR_UTILS_UI_HPP
#define STELLAR_UTILS_UI_HPP
#include <string>
#include "utils.hpp"
/* Color */
constexpr const std::string to_string(const Color color) {
return std::string(color == WHITE ? "white" : "black");
}
/* Square */
constexpr const char *coordinates_array[] = {
// clang-format off
"a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1",
"a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2",
"a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3",
"a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4",
"a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5",
"a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6",
"a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7",
"a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8", " "
// clang-format on
};
constexpr const std::string to_coordinates(const Square square) { return coordinates_array[square]; }
constexpr Square from_coordinates(const std::string &cord) {
return static_cast<Square>((cord[1] - '1') * 8 + (cord[0] - 'a'));
}
#endif