BenBot 1.7.5
A chess engine
Loading...
Searching...
No Matches
Square.hpp
Go to the documentation of this file.
1/*
2 * ======================================================================================
3 *
4 * ░▒▓███████▓▒░░▒▓████████▓▒░▒▓███████▓▒░ ░▒▓███████▓▒░ ░▒▓██████▓▒░▒▓████████▓▒░
5 * ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
6 * ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
7 * ░▒▓███████▓▒░░▒▓██████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
8 * ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
9 * ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░
10 * ░▒▓███████▓▒░░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓███████▓▒░ ░▒▓██████▓▒░ ░▒▓█▓▒░
11 *
12 * ======================================================================================
13 */
14
21
27
28#pragma once
29
30#include <cassert>
31#include <compare>
32#include <cstddef> // IWYU pragma: keep - for size_t
33#include <expected>
34#include <format>
38#include <libutil/Math.hpp>
39#include <string>
40#include <string_view>
41#include <utility>
42
48namespace chess::board {
49
72struct Square final {
75
78
82 [[nodiscard, gnu::const]] static constexpr auto from_index(BitboardIndex index) noexcept -> Square;
83
90 [[nodiscard]] static auto from_string(std::string_view text) -> std::expected<Square, std::string>;
91
95 [[nodiscard]] constexpr auto index() const noexcept -> BitboardIndex;
96
98 [[nodiscard]] constexpr auto operator==(const Square&) const noexcept -> bool = default;
99
102
104 [[nodiscard]] constexpr auto is_queenside() const noexcept -> bool;
105
107 [[nodiscard]] constexpr auto is_kingside() const noexcept -> bool;
108
110 [[nodiscard]] constexpr auto is_white_territory() const noexcept -> bool;
111
113 [[nodiscard]] constexpr auto is_black_territory() const noexcept -> bool;
114
116
118 [[nodiscard]] constexpr auto is_light() const noexcept -> bool;
119
121 [[nodiscard]] constexpr auto is_dark() const noexcept -> bool { return not is_light(); }
122};
123
126
130[[nodiscard, gnu::const]] constexpr auto operator<=>(
131 const Square& first, const Square& second) noexcept
132 -> std::strong_ordering
133{
134 return first.index() <=> second.index();
135}
136
140[[nodiscard, gnu::const]] constexpr auto get_en_passant_captured_square(
141 Square targetSquare, bool isWhite) noexcept
142 -> Square;
143
145
146} // namespace chess::board
147
155template <>
156struct std::formatter<chess::board::Square> final {
157 template <typename ParseContext>
158 constexpr auto parse(ParseContext& ctx) -> typename ParseContext::iterator
159 {
160 return ctx.begin();
161 }
162
163 template <typename FormatContext>
164 auto format(
165 const chess::board::Square& square, FormatContext& ctx) const
166 -> typename FormatContext::iterator
167 {
168 return std::format_to(ctx.out(), "{}{}", square.file, square.rank);
169 }
170};
171
172/*
173 ___ ,--,
174 ,---, ,--.'|_ ,--, ,--.'|
175 ,---.'| | | :,' ,--.'| | | :
176 | | : : : ' : | |, : : ' .--.--.
177 | | | ,---. .;__,' / ,--.--. `--'_ | ' | / / '
178 ,--.__| | / \ | | | / \ ,' ,'| ' | | | : /`./
179 / ,' | / / |:__,'| : .--. .-. | ' | | | | : | : ;_
180. ' / |. ' / | ' : |__ \__\/: . . | | : ' : |__ \ \ `.
181' ; |: |' ; /| | | '.'| ," .--.; | ' : |__ | | '.'| `----. \
182| | '/ '' | / | ; : ;/ / ,. | | | '.'|; : ;/ /`--' /__ ___ ___
183| : :|| : | | , /; : .' \; : ;| , /'--'. / .\/ .\/ .\
184 \ \ / \ \ / ---`-' | , .-./| , / ---`-' `--'---'\ ; \ ; \ ; |
185 `----' `----' `--`---' ---`-' `--" `--" `--"
186
187 */
188
189namespace chess::board {
190
191constexpr auto Square::from_index(const BitboardIndex index) noexcept -> Square
192{
193 assert(std::cmp_less_equal(index, MAX_BITBOARD_IDX));
194
195 return {
196 .file = static_cast<File>(index & static_cast<BitboardIndex>(7)),
197 .rank = static_cast<Rank>(index >> static_cast<BitboardIndex>(3))
198 };
199}
200
201constexpr auto Square::index() const noexcept -> BitboardIndex
202{
203 return static_cast<BitboardIndex>(
204 (static_cast<int>(rank) << 3) + static_cast<int>(file));
205}
206
207constexpr auto Square::is_queenside() const noexcept -> bool
208{
209 return std::cmp_less_equal(
210 std::to_underlying(file), std::to_underlying(File::D));
211}
212
213constexpr auto Square::is_kingside() const noexcept -> bool
214{
215 return std::cmp_greater_equal(
216 std::to_underlying(file), std::to_underlying(File::E));
217}
218
219constexpr auto Square::is_white_territory() const noexcept -> bool
220{
221 return std::cmp_less_equal(
222 std::to_underlying(rank), std::to_underlying(Rank::Four));
223}
224
225constexpr auto Square::is_black_territory() const noexcept -> bool
226{
227 return std::cmp_greater_equal(
228 std::to_underlying(rank), std::to_underlying(Rank::Five));
229}
230
231constexpr auto Square::is_light() const noexcept -> bool
232{
233 return not util::math::is_even(
234 std::to_underlying(rank) + std::to_underlying(file));
235}
236
237inline auto Square::from_string(const std::string_view text)
238 -> std::expected<Square, std::string>
239{
240 if (std::cmp_not_equal(text.length(), 2)) {
241 return std::unexpected {
242 std::format(
243 "Cannot parse Square from invalid input string: {}",
244 text)
245 };
246 }
247
248 return rank_from_char(text.back())
249 .and_then([fileChar = text.front()](const Rank rankToUse) {
250 return file_from_char(fileChar)
251 .transform([rankToUse](const File fileToUse) {
252 return Square {
253 .file = fileToUse,
254 .rank = rankToUse
255 };
256 });
257 });
258}
259
261 const Square targetSquare, const bool isWhite) noexcept
262 -> Square
263{
264 // the captured pawn is on the file of the target square, but
265 // one rank below (White capture) or one rank above (Black capture)
266 const auto capturedRank = isWhite
267 ? prev_pawn_rank<Color::White>(targetSquare.rank)
268 : prev_pawn_rank<Color::Black>(targetSquare.rank);
269
270 return Square {
271 .file = targetSquare.file,
272 .rank = capturedRank
273 };
274}
275
276} // namespace chess::board
constexpr auto prev_pawn_rank(Rank rank) noexcept -> Rank
Definition Rank.hpp:153
std::uint_fast8_t BitboardIndex
auto rank_from_char(char character) -> std::expected< Rank, std::string >
Definition Rank.hpp:164
constexpr auto operator<=>(const Square &first, const Square &second) noexcept -> std::strong_ordering
Definition Square.hpp:130
constexpr BitboardIndex MAX_BITBOARD_IDX
@ One
The first rank. This is the rank that white's king starts on.
Definition Rank.hpp:41
@ Four
The fourth rank.
Definition Rank.hpp:44
@ Five
The fifth rank.
Definition Rank.hpp:45
@ E
The E file. This is the file that the kings start on.
Definition File.hpp:41
@ A
The A file.
Definition File.hpp:37
@ D
The D file. This is the file that the queens start on.
Definition File.hpp:40
constexpr auto is_even(const T value) noexcept -> bool
Definition Math.hpp:41
constexpr auto get_en_passant_captured_square(Square targetSquare, bool isWhite) noexcept -> Square
Definition Square.hpp:260
constexpr auto is_dark() const noexcept -> bool
Definition Square.hpp:121
constexpr auto is_kingside() const noexcept -> bool
Definition Square.hpp:213
static auto from_string(std::string_view text) -> std::expected< Square, std::string >
Definition Square.hpp:237
constexpr auto is_light() const noexcept -> bool
Definition Square.hpp:231
constexpr auto index() const noexcept -> BitboardIndex
Definition Square.hpp:201
constexpr auto is_black_territory() const noexcept -> bool
Definition Square.hpp:225
static constexpr auto from_index(BitboardIndex index) noexcept -> Square
Definition Square.hpp:191
constexpr auto is_queenside() const noexcept -> bool
Definition Square.hpp:207
constexpr auto is_white_territory() const noexcept -> bool
Definition Square.hpp:219
auto format(const chess::board::Square &square, FormatContext &ctx) const -> typename FormatContext::iterator
Definition Square.hpp:164
constexpr auto parse(ParseContext &ctx) -> typename ParseContext::iterator
Definition Square.hpp:158