Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Chess/ExitCondition.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include <variant>
#include "Evaluation.h"
#include "Searcher.h"
namespace SimpleChessEngine {
Expand Down
177 changes: 86 additions & 91 deletions Chess/Move.h
Original file line number Diff line number Diff line change
@@ -1,106 +1,101 @@
#pragma once
#include <cstdint>
#include <cassert>
#include <tuple>
#include <variant>

#include "BitBoard.h"
#include "Piece.h"
namespace SimpleChessEngine {
struct NullMove {};

struct DefaultMove {
bool operator==(const DefaultMove&) const = default;

BitIndex from{};
BitIndex to{};
Piece captured_piece{};
};

struct PawnPush {
bool operator==(const PawnPush&) const = default;

BitIndex from{};
BitIndex to{};
};

struct DoublePush {
bool operator==(const DoublePush&) const = default;

BitIndex from{};
BitIndex to{};
};
namespace SimpleChessEngine {

struct EnCroissant {
BitIndex from{};
BitIndex to{};
struct NullMove {};

bool operator==(const EnCroissant&) const = default;
enum class MoveType : std::uint16_t {
kNormal = 0,
kCastling = 1 << 14,
kEnPassant = 2 << 14,
kPromotion = 3 << 14,
};

struct Promotion : DefaultMove {
bool operator==(const Promotion& other) const {
return DefaultMove::operator==(other) && promoted_to == other.promoted_to;
}

Piece promoted_to{};
class Move {
private:
static constexpr std::uint16_t kSquareMask = 0x3F;
static constexpr std::uint16_t kPromotionMask = 0x3;
static constexpr std::uint16_t kTypeMask = 0x3;
static constexpr std::uint8_t kFromShift = 6;
static constexpr std::uint8_t kPromotionShift = 12;
static constexpr std::uint8_t kTypeShift = 14;
static constexpr std::uint16_t kNullValue = 65;
static constexpr std::uint16_t kNoneValue = 0;

public:
Move() = default;
constexpr explicit Move(std::uint16_t data) : data_(data) {}
constexpr Move(BitIndex from, BitIndex to) : data_((from << kFromShift) + to) {}

template<MoveType T>
static constexpr Move Make(BitIndex from, BitIndex to, Piece promotion_piece = Piece::kKnight) {
return Move(static_cast<std::uint16_t>(T) +
((static_cast<std::uint16_t>(promotion_piece) - static_cast<std::uint16_t>(Piece::kKnight)) << kPromotionShift) +
(from << kFromShift) + to);
}

constexpr BitIndex From() const {
assert(IsValid());
return static_cast<BitIndex>((data_ >> kFromShift) & kSquareMask);
}

constexpr BitIndex To() const {
assert(IsValid());
return static_cast<BitIndex>(data_ & kSquareMask);
}

constexpr MoveType Type() const {
return static_cast<MoveType>(data_ & (kTypeMask << kTypeShift));
}

constexpr Piece PromotionPiece() const {
return static_cast<Piece>(((data_ >> kPromotionShift) & kPromotionMask) + static_cast<std::uint8_t>(Piece::kKnight));
}

constexpr bool IsValid() const {
return data_ != kNoneValue && data_ != kNullValue;
}

constexpr bool IsPromotion() const { return Type() == MoveType::kPromotion; }
constexpr bool IsEnPassant() const { return Type() == MoveType::kEnPassant; }
constexpr bool IsCastling() const { return Type() == MoveType::kCastling; }
constexpr bool IsNormal() const { return Type() == MoveType::kNormal; }

template<typename Position>
bool IsQuiet(const Position& position) const {
if (IsPromotion() || IsEnPassant()) return false;
if (IsCastling()) return true;
return position.GetPieceAt(To()) == Piece::kNone;
}

static constexpr Move Null() { return Move(kNullValue); }
static constexpr Move None() { return Move(kNoneValue); }

constexpr bool operator==(const Move& other) const = default;
constexpr bool operator!=(const Move& other) const = default;
constexpr explicit operator bool() const { return data_ != 0; }
constexpr std::uint16_t Raw() const { return data_; }

struct Hash {
std::size_t operator()(const Move& move) const {
return move.data_ * 6364136223846793005ULL + 1442695040888963407ULL;
}
};

private:
std::uint16_t data_;
};

struct Castling {
enum class CastlingSide : std::uint8_t { k00, k000 };

CastlingSide side;
enum class CastlingSide : std::uint8_t { k00, k000 };

BitIndex king_from{};
BitIndex rook_from{};

bool operator==(const Castling&) const = default;
};
static_assert(sizeof(Move) == 2, "Move must be exactly 2 bytes");
static_assert(alignof(Move) == 2, "Move should be 2-byte aligned");
static_assert(std::is_trivially_copyable_v<Move>, "Move must be trivially copyable");
static_assert(std::is_standard_layout_v<Move>, "Move must have standard layout");

using Move = std::variant<PawnPush, DoublePush, EnCroissant, DefaultMove,
Castling, Promotion>;

inline std::tuple<BitIndex, BitIndex, Piece> GetMoveData(const PawnPush& move) {
return {move.from, move.to, Piece::kNone};
}

inline std::tuple<BitIndex, BitIndex, Piece> GetMoveData(
const DoublePush& move) {
return {move.from, move.to, Piece::kNone};
}

inline std::tuple<BitIndex, BitIndex, Piece> GetMoveData(
const EnCroissant& move) {
return {move.from, move.to, Piece::kPawn};
}

inline std::tuple<BitIndex, BitIndex, Piece> GetMoveData(
const DefaultMove& move) {
return {move.from, move.to, move.captured_piece};
}

inline std::tuple<BitIndex, BitIndex, Piece> GetMoveData(const Castling& move) {
return {move.king_from, 64, Piece::kNone};
}

inline std::tuple<BitIndex, BitIndex, Piece> GetMoveData(
const Promotion& move) {
return {move.from, move.to, move.captured_piece};
}

inline std::tuple<BitIndex, BitIndex, Piece> GetMoveData(const Move& move) {
return std::visit(
[](const auto& unwrapped_move) { return GetMoveData(unwrapped_move); },
move);
}

inline bool IsQuiet(const Move& move) {
return !std::get<Piece>(GetMoveData(move));
}

inline bool DoesReset(const Move& move) {
if (std::holds_alternative<DefaultMove>(move)) {
return !!std::get<DefaultMove>(move).captured_piece;
}
return !std::holds_alternative<Castling>(move);
}
} // namespace SimpleChessEngine
32 changes: 14 additions & 18 deletions Chess/MoveFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "Utility.h"

namespace SimpleChessEngine {

struct MoveFactory {
Move operator()(const Position &position, const std::string &move) const;

Expand All @@ -25,12 +26,14 @@ struct MoveFactory {
inline Move MoveFactory::operator()(const Position &position,
const std::string &move) const {
if (move == "O-O") {
return Castling{Castling::CastlingSide::k00,
position.GetKingSquare(position.GetSideToMove())};
return Move::Make<MoveType::kCastling>(
position.GetKingSquare(position.GetSideToMove()),
position.GetKingSquare(position.GetSideToMove()) + 2);
}
if (move == "O-O-O") {
return Castling{Castling::CastlingSide::k000,
position.GetKingSquare(position.GetSideToMove())};
return Move::Make<MoveType::kCastling>(
position.GetKingSquare(position.GetSideToMove()),
position.GetKingSquare(position.GetSideToMove()) - 2);
}

const auto [from, to] = ParseDefaultMove(move);
Expand All @@ -39,34 +42,27 @@ inline Move MoveFactory::operator()(const Position &position,

if (piece_to_move == Piece::kKing) {
if (!IsAdjacent(from, to)) {
static std::unordered_map<File, Castling::CastlingSide> castling_file = {
{2, Castling::CastlingSide::k000}, {6, Castling::CastlingSide::k00}};
static std::unordered_map<File, File> rook_from_file = {{1, 0}, {6, 7}};

auto [king_file, king_rank] = GetCoordinates(to);

return Castling{castling_file[king_file], from,
GetSquareIndex(rook_from_file[king_file], king_rank)};
return Move::Make<MoveType::kCastling>(from, to);
}
}

if (constexpr size_t kPromotionSize = 5; move.size() == kPromotionSize) {
return Promotion{{from, to, position.GetPieceAt(to)},
kCharToPiece[move.back()].first};
return Move::Make<MoveType::kPromotion>(from, to, kCharToPiece[move.back()].first);
}

if (piece_to_move != Piece::kPawn || position.GetPieceAt(to) != Piece::kNone) {
return DefaultMove{from, to, position.GetPieceAt(to)};
return Move(from, to);
}

if (!IsAdjacent(from, to)) {
return DoublePush{from, to};
return Move(from, to);
}

if (to == position.GetEnCroissantSquare()) {
return EnCroissant{from, to};
return Move::Make<MoveType::kEnPassant>(from, to);
}

return PawnPush{from, to};
return Move(from, to);
}

inline MoveFactory::ParsedMove MoveFactory::ParseDefaultMove(
Expand Down
Loading