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
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ function(do_test name)
add_test(${name} ${name})
endfunction()

do_test(test_see)
do_test(test_see_prototype)
do_test(test_is_legal)
do_test(test_repetition)
do_test(test_static_vector)
Expand Down
14 changes: 9 additions & 5 deletions src/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,17 @@ struct Place {
return {};
}

static constexpr u8 COLOR_MASK = 0x10;
static constexpr i32 PTYPE_SHIFT = 5;
static constexpr u8 PTYPE_MASK = 0xE0;
static constexpr i32 COLOR_SHIFT = 4;
static constexpr u8 COLOR_MASK = 0x10;
static constexpr u8 ID_MASK = 0x0F;

constexpr Place() = default;

constexpr Place(Color color, PieceType pt, PieceId id) {
raw =
static_cast<u8>((static_cast<i32>(color) << 4) | (static_cast<i32>(pt) << 5) | id.raw);
raw = static_cast<u8>((static_cast<i32>(color) << COLOR_SHIFT)
| (static_cast<i32>(pt) << PTYPE_SHIFT) | id.raw);
}

[[nodiscard]] constexpr bool is_empty() const {
Expand All @@ -51,10 +55,10 @@ struct Place {
return static_cast<Color>((raw & COLOR_MASK) != 0);
}
[[nodiscard]] constexpr PieceType ptype() const {
return static_cast<PieceType>((raw >> 5) & 0x7);
return static_cast<PieceType>((raw & PTYPE_MASK) >> PTYPE_SHIFT);
}
[[nodiscard]] constexpr PieceId id() const {
return PieceId{static_cast<u8>(raw & 0xF)};
return PieceId{static_cast<u8>(raw & ID_MASK)};
}

[[nodiscard]] constexpr char to_char() const {
Expand Down
4 changes: 4 additions & 0 deletions src/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ constexpr Color invert(Color color) {
return static_cast<Color>(static_cast<i32>(color) ^ 1);
}

constexpr Color operator~(Color color) {
return invert(color);
}

enum class PieceType : u8 {
None,
Pawn,
Expand Down
6 changes: 6 additions & 0 deletions src/geometry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ inline v512 superpiece_attacks(v512 ray_places, v512 ray_valid) {
ray_valid);
}

inline u64 closest(u64 occupied) {
u64 o = occupied | 0x8181818181818181;
u64 x = o ^ (o - 0x0303030303030303);
return x & occupied;
}

inline v512 attackers_from_rays(v512 ray_places) {
constexpr u8 K = 1 << 0;
constexpr u8 WP = 1 << 1;
Expand Down
6 changes: 5 additions & 1 deletion src/move.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ struct Move {
}

[[nodiscard]] constexpr bool is_castle() const {
return raw & static_cast<u16>(MoveFlags::Castle);
return flags() == MoveFlags::Castle;
}

[[nodiscard]] constexpr bool is_en_passant() const {
return flags() == MoveFlags::EnPassant;
}

[[nodiscard]] constexpr std::optional<PieceType> promo() const {
Expand Down
6 changes: 6 additions & 0 deletions src/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "common.hpp"
#include "movegen.hpp"
#include "movepick.hpp"
#include "see.hpp"
#include "tm.hpp"
#include "tuned.hpp"
#include "uci.hpp"
Expand Down Expand Up @@ -78,7 +79,7 @@
Value last_search_score = -VALUE_INF;
Move last_best_move = Move::none();

const auto print_info_line = [&] {

Check warning on line 82 in src/search.cpp

View workflow job for this annotation

GitHub Actions / Linter / cpp-linter

src/search.cpp:82:16 [readability-identifier-naming]

invalid case style for constant 'print_info_line'
// Lambda to convert internal units score to uci score. TODO: add eval rescaling here once we get one
auto format_score = [](Value score) {
if (score < -VALUE_WIN && score > -VALUE_MATED) {
Expand Down Expand Up @@ -206,7 +207,7 @@
}

if (!PV_NODE && !is_in_check && depth >= tuned::nmp_depth) {
int R = tuned::nmp_base_r;

Check warning on line 210 in src/search.cpp

View workflow job for this annotation

GitHub Actions / Linter / cpp-linter

src/search.cpp:210:18 [readability-identifier-naming]

invalid case style for variable 'R'
Position pos_after = pos.null_move();

m_repetition_info.push(pos_after.get_hash_key(), true);
Expand All @@ -222,7 +223,7 @@

// Razoring
if (!PV_NODE && !is_in_check && depth <= 7 && static_eval + 260 * depth < alpha) {
const Value razor_score = quiesce(pos, ss, alpha, beta, ply);

Check warning on line 226 in src/search.cpp

View workflow job for this annotation

GitHub Actions / Linter / cpp-linter

src/search.cpp:226:21 [readability-identifier-naming]

invalid case style for constant 'razor_score'
if (razor_score <= alpha) {
return razor_score;
}
Expand Down Expand Up @@ -312,7 +313,7 @@
if (best_value >= beta && quiet_move(best_move)) {
ss->killer = best_move;

const i32 bonus = std::min(1896, 4 * depth * depth + 120 * depth - 120);

Check warning on line 316 in src/search.cpp

View workflow job for this annotation

GitHub Actions / Linter / cpp-linter

src/search.cpp:316:19 [readability-identifier-naming]

invalid case style for constant 'bonus'
m_td.history.update_quiet_stats(pos, best_move, bonus);
for (Move quiet : quiets_played) {
m_td.history.update_quiet_stats(pos, quiet, -bonus);
Expand Down Expand Up @@ -383,6 +384,11 @@

// Iterate over the move list
for (Move m = moves.next(); m != Move::none(); m = moves.next()) {
// QS SEE Pruning
if (best_value > -VALUE_WIN && !SEE::see(pos, m, tuned::quiesce_see_threshold)) {
continue;
}

// Do move
Position pos_after = pos.move(m);
moves_searched++;
Expand Down Expand Up @@ -422,7 +428,7 @@
}

Value Worker::evaluate(const Position& pos) {
const Color us = pos.active_color();

Check warning on line 431 in src/search.cpp

View workflow job for this annotation

GitHub Actions / Linter / cpp-linter

src/search.cpp:431:17 [readability-identifier-naming]

invalid case style for constant 'us'
const Color them = invert(us);

Value material =
Expand Down
108 changes: 108 additions & 0 deletions src/see.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#pragma once

#include "common.hpp"
#include "geometry.hpp"
#include "move.hpp"
#include "position.hpp"
#include "util/types.hpp"
#include "util/vec.hpp"
#include <array>
#include <bit>
#include <cassert>
#include <tuple>

namespace Clockwork::SEE {

inline Value value(PieceType ptype) {
constexpr std::array<Value, 7> TABLE{{0, 100, 300, 300, 500, 900, 10000}};
return TABLE[static_cast<usize>(ptype)];
}

inline Value gain(const Position& pos, Move move) {
if (move.is_castle()) {
return 0;
}
if (move.is_en_passant()) {
return value(PieceType::Pawn);
}

Value score = value(pos.board()[move.to()].ptype());
if (move.is_promotion()) {
score += value(*move.promo()) - value(PieceType::Pawn);
}
return score;
}

inline bool see(const Position& pos, Move move, Value threshold) {
Square sq = move.to();
Color stm = pos.active_color();

Value score = gain(pos, move) - threshold;
if (score < 0) {
return false;
}

PieceType next = move.promo().value_or(pos.board()[move.from()].ptype());
score -= value(next);
stm = invert(stm);

if (score >= 0) {
return true;
}

// Extract all possible attackers to our position
auto [ray_coords, ray_valid] = geometry::superpiece_rays(sq);
v512 ray_places = v512::permute8(ray_coords, pos.board().to_vec());
v512 ray_attackers = ray_places & geometry::attackers_from_rays(ray_places);
v512 ptypes = ray_attackers & ray_valid & v512::broadcast8(Place::PTYPE_MASK);

// Bitrays (not bitboards)
u64 color = v512::test8(ray_places, v512::broadcast8(Place::COLOR_MASK));
u64 occupied = v512::test8(ray_places, ray_valid);
u64 attackers = v512::test8(ray_attackers, ray_valid);

// Remove already moved piece
occupied ^= v512::eq8(ray_coords, v512::broadcast8(move.from().raw));
if (move.is_en_passant()) {
occupied &= pos.active_color() == Color::Black ? 0xFFFFFFFFFFFFFFFD : 0xFFFFFFFDFFFFFFFF;
}

// Extract bitrays for each piece type
std::array<u64, 8> ptype_bits{
0, // None
v512::eq8(ptypes, v512::broadcast8(static_cast<u8>(PieceType::Pawn) << Place::PTYPE_SHIFT)),
0x0101010101010101, // Knight
v512::eq8(ptypes, v512::broadcast8(static_cast<u8>(PieceType::Bishop) << Place::PTYPE_SHIFT)),
v512::eq8(ptypes, v512::broadcast8(static_cast<u8>(PieceType::Rook) << Place::PTYPE_SHIFT)),
v512::eq8(ptypes, v512::broadcast8(static_cast<u8>(PieceType::Queen) << Place::PTYPE_SHIFT)),
v512::eq8(ptypes, v512::broadcast8(static_cast<u8>(PieceType::King) << Place::PTYPE_SHIFT)),
0, // Invalid
};
v512 ptype_vec{ptype_bits};

auto current_attackers = [&]() {
return geometry::closest(occupied) & (stm == Color::Black ? color : ~color) & attackers;
};

while (u64 current = current_attackers()) {
i32 next = std::countr_zero((ptype_vec & v512::broadcast64(current)).nonzero64());
auto ptype = static_cast<PieceType>(next);
u64 br = ptype_bits[next] & current;
occupied ^= lowest_bit(br);

score = -score - 1 - value(ptype);
stm = invert(stm);

if (score >= 0) {
if (ptype == PieceType::King && current_attackers() != 0) {
// We'd be in check if we actually did that.
stm = invert(stm);
}
break;
}
}

return stm != pos.active_color();
}

}
23 changes: 13 additions & 10 deletions src/tuned.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@

namespace Clockwork::tuned {

#define CLOCKWORK_TUNABLES(TUNE, NO_TUNE) \
\
/* RFP Values */ \
TUNE(rfp_margin, 80, 40, 160, 4, 0.002) \
NO_TUNE(rfp_depth, 6, 4, 10, .5, 0.002) \
\
/* NMP Values */ \
NO_TUNE(nmp_depth, 3, 1, 10, .5, 0.002) \
NO_TUNE(nmp_base_r, 3, 1, 10, .5, 0.002) \
\
#define CLOCKWORK_TUNABLES(TUNE, NO_TUNE) \
\
/* RFP Values */ \
TUNE(rfp_margin, 80, 40, 160, 4, 0.002) \
NO_TUNE(rfp_depth, 6, 4, 10, .5, 0.002) \
\
/* NMP Values */ \
NO_TUNE(nmp_depth, 3, 1, 10, .5, 0.002) \
NO_TUNE(nmp_base_r, 3, 1, 10, .5, 0.002) \
\
/* SEE Values */ \
TUNE(quiesce_see_threshold, 0, -1000, 100, 20, 0.002) \
\
/* End of Tunables */

#define DEFINE_VARIABLE(NAME, DEFAULT, ...) inline i32 NAME = DEFAULT;
Expand Down
5 changes: 5 additions & 0 deletions src/util/bit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ template<typename T>
return x & (x - 1);
}

template<typename T>
[[nodiscard]] constexpr T lowest_bit(T x) {
return x & -x;
}

[[nodiscard]] constexpr i32 sign(i32 x) {
if (x == 0) {
return 0;
Expand Down
17 changes: 17 additions & 0 deletions src/util/vec/avx2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

namespace Clockwork {

forceinline u8 concat8(u8 a, u8 b) {
return a | (b << 4);
}
forceinline u32 concat32(u16 a, u16 b) {
return static_cast<u32>(a) | (static_cast<u32>(b) << 16);
}
Expand Down Expand Up @@ -248,6 +251,10 @@ struct v256 {
static_cast<u32>(~_mm256_movemask_epi8(_mm256_cmpeq_epi16(a.raw, b.raw))), 0xAAAAAAAA));
}

static forceinline u8 eq64(v256 a, v256 b) {
return static_cast<u8>(_mm256_movemask_pd((__m256d)_mm256_cmpeq_epi64(a.raw, b.raw)));
}

template<i32 offset>
[[nodiscard]] forceinline v128 extract128() const {
return {_mm256_extracti128_si256(raw, offset)};
Expand Down Expand Up @@ -293,6 +300,9 @@ struct v512 {
forceinline explicit v512(std::array<u16, 32> src) :
raw(std::bit_cast<std::array<v256, 2>>(src)) {
}
forceinline explicit v512(std::array<u64, 8> src) :
raw(std::bit_cast<std::array<v256, 2>>(src)) {
}

static forceinline v512 zero() {
return v512{v256::zero(), v256::zero()};
Expand Down Expand Up @@ -406,6 +416,10 @@ struct v512 {
return static_cast<u32>(_pext_u64(~x, 0xAAAAAAAAAAAAAAAA));
}

static forceinline u8 neq64(v512 a, v512 b) {
return ~concat8(v256::eq64(a.raw[0], b.raw[0]), v256::eq64(a.raw[1], b.raw[1]));
}

static forceinline u64 testn8(v512 a, v512 b) {
return (a & b).zero8();
}
Expand All @@ -422,6 +436,9 @@ struct v512 {
[[nodiscard]] forceinline u32 nonzero16() const {
return neq16(*this, zero());
}
[[nodiscard]] forceinline u64 nonzero64() const {
return neq64(*this, zero());
}

friend forceinline v512 operator&(v512 a, v512 b) {
return v512{a.raw[0] & b.raw[0], a.raw[1] & b.raw[1]};
Expand Down
92 changes: 92 additions & 0 deletions tests/test_see.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#include "move.hpp"
#include "position.hpp"
#include "see.hpp"
#include "test.hpp"
#include <iostream>
#include <string_view>

using namespace Clockwork;

void test_see(std::string_view pos_str, std::string_view move_str, i32 value) {
Position pos = Position::parse(pos_str).value();
Move move = Move::parse(move_str, pos).value();

std::cout << pos << " | " << move << " | " << value << std::endl;

REQUIRE(SEE::see(pos, move, value + 1) == false);
REQUIRE(SEE::see(pos, move, value - 1) == true);
}

int main() {
test_see("6k1/1pp4p/p1pb4/6q1/3P1pRr/2P4P/PP1Br1P1/5RKN w - - 0 1", "f1f4", -100);
test_see("5rk1/1pp2q1p/p1pb4/8/3P1NP1/2P5/1P1BQ1P1/5RK1 b - - 0 1", "d6f4", 0);
test_see("4R3/2r3p1/5bk1/1p1r3p/p2PR1P1/P1BK1P2/1P6/8 b - - 0 1", "h5g4", 0);
test_see("4R3/2r3p1/5bk1/1p1r1p1p/p2PR1P1/P1BK1P2/1P6/8 b - - 0 1", "h5g4", 0);
test_see("4r1k1/5pp1/nbp4p/1p2p2q/1P2P1b1/1BP2N1P/1B2QPPK/3R4 b - - 0 1", "g4f3", 0);
test_see("2r1r1k1/pp1bppbp/3p1np1/q3P3/2P2P2/1P2B3/P1N1B1PP/2RQ1RK1 b - - 0 1", "d6e5", 100);
test_see("7r/5qpk/p1Qp1b1p/3r3n/BB3p2/5p2/P1P2P2/4RK1R w - - 0 1", "e1e8", 0);
test_see("6rr/6pk/p1Qp1b1p/2n5/1B3p2/5p2/P1P2P2/4RK1R w - - 0 1", "e1e8", -500);
test_see("7r/5qpk/2Qp1b1p/1N1r3n/BB3p2/5p2/P1P2P2/4RK1R w - - 0 1", "e1e8", -500);
test_see("6RR/4bP2/8/8/5r2/3K4/5p2/4k3 w - - 0 1", "f7f8q", 200);
test_see("6RR/4bP2/8/8/5r2/3K4/5p2/4k3 w - - 0 1", "f7f8n", 200);
test_see("7R/5P2/8/8/6r1/3K4/5p2/4k3 w - - 0 1", "f7f8q", 800);
test_see("7R/5P2/8/8/6r1/3K4/5p2/4k3 w - - 0 1", "f7f8b", 200);
test_see("7R/4bP2/8/8/1q6/3K4/5p2/4k3 w - - 0 1", "f7f8r", -100);
test_see("8/4kp2/2npp3/1Nn5/1p2PQP1/7q/1PP1B3/4KR1r b - - 0 1", "h1f1", 0);
test_see("8/4kp2/2npp3/1Nn5/1p2P1P1/7q/1PP1B3/4KR1r b - - 0 1", "h1f1", 0);
test_see("2r2r1k/6bp/p7/2q2p1Q/3PpP2/1B6/P5PP/2RR3K b - - 0 1", "c5c1", 100);
test_see("r2qk1nr/pp2ppbp/2b3p1/2p1p3/8/2N2N2/PPPP1PPP/R1BQR1K1 w kq - 0 1", "f3e5", 100);
test_see("6r1/4kq2/b2p1p2/p1pPb3/p1P2B1Q/2P4P/2B1R1P1/6K1 w - - 0 1", "f4e5", 0);
test_see("3q2nk/pb1r1p2/np6/3P2Pp/2p1P3/2R4B/PQ3P1P/3R2K1 w - h6 0 1", "g5h6", 0);
test_see("3q2nk/pb1r1p2/np6/3P2Pp/2p1P3/2R1B2B/PQ3P1P/3R2K1 w - h6 0 1", "g5h6", 100);
test_see("2r4r/1P4pk/p2p1b1p/7n/BB3p2/2R2p2/P1P2P2/4RK2 w - - 0 1", "c3c8", 500);
// test_see("2r5/1P4pk/p2p1b1p/5b1n/BB3p2/2R2p2/P1P2P2/4RK2 w - - 0 1", "c3c8", 500); // Q promo
test_see("2r4k/2r4p/p7/2b2p1b/4pP2/1BR5/P1R3PP/2Q4K w - - 0 1", "c3c5", 300);
test_see("8/pp6/2pkp3/4bp2/2R3b1/2P5/PP4B1/1K6 w - - 0 1", "g2c6", -200);
test_see("4q3/1p1pr1k1/1B2rp2/6p1/p3PP2/P3R1P1/1P2R1K1/4Q3 b - - 0 1", "e6e4", -400);
test_see("4q3/1p1pr1kb/1B2rp2/6p1/p3PP2/P3R1P1/1P2R1K1/4Q3 b - - 0 1", "h7e4", 100);
test_see("3r3k/3r4/2n1n3/8/3p4/2PR4/1B1Q4/3R3K w - - 0 1", "d3d4", -100);
test_see("1k1r4/1ppn3p/p4b2/4n3/8/P2N2P1/1PP1R1BP/2K1Q3 w - - 0 1", "d3e5", 100);
test_see("1k1r3q/1ppn3p/p4b2/4p3/8/P2N2P1/1PP1R1BP/2K1Q3 w - - 0 1", "d3e5", -200);
test_see("rnb2b1r/ppp2kpp/5n2/4P3/q2P3B/5R2/PPP2PPP/RN1QKB2 w Q - 0 1", "h4f6", 100);
test_see("r2q1rk1/2p1bppp/p2p1n2/1p2P3/4P1b1/1nP1BN2/PP3PPP/RN1QR1K1 b - - 0 1", "g4f3", 0);
test_see("r1bqkb1r/2pp1ppp/p1n5/1p2p3/3Pn3/1B3N2/PPP2PPP/RNBQ1RK1 b kq - 0 1", "c6d4", 0);
test_see("r1bq1r2/pp1ppkbp/4N1p1/n3P1B1/8/2N5/PPP2PPP/R2QK2R w KQ - 0 1", "e6g7", 0);
test_see("r1bq1r2/pp1ppkbp/4N1pB/n3P3/8/2N5/PPP2PPP/R2QK2R w KQ - 0 1", "e6g7", 300);
test_see("rnq1k2r/1b3ppp/p2bpn2/1p1p4/3N4/1BN1P3/PPP2PPP/R1BQR1K1 b kq - 0 1", "d6h2", -200);
test_see("rn2k2r/1bq2ppp/p2bpn2/1p1p4/3N4/1BN1P3/PPP2PPP/R1BQR1K1 b kq - 0 1", "d6h2", 100);
test_see("r2qkbn1/ppp1pp1p/3p1rp1/3Pn3/4P1b1/2N2N2/PPP2PPP/R1BQKB1R b KQq - 0 1", "g4f3", 100);
test_see("rnbq1rk1/pppp1ppp/4pn2/8/1bPP4/P1N5/1PQ1PPPP/R1B1KBNR b KQ - 0 1", "b4c3", 0);
test_see("r4rk1/3nppbp/bq1p1np1/2pP4/8/2N2NPP/PP2PPB1/R1BQR1K1 b - - 0 1", "b6b2", -800);
test_see("r4rk1/1q1nppbp/b2p1np1/2pP4/8/2N2NPP/PP2PPB1/R1BQR1K1 b - - 0 1", "f6d5", -200);
test_see("1r3r2/5p2/4p2p/2k1n1P1/2PN1nP1/1P3P2/8/2KR1B1R b - - 0 1", "b8b3", -400);
test_see("1r3r2/5p2/4p2p/4n1P1/kPPN1nP1/5P2/8/2KR1B1R b - - 0 1", "b8b4", 100);
test_see("2r2rk1/5pp1/pp5p/q2p4/P3n3/1Q3NP1/1P2PP1P/2RR2K1 b - - 0 1", "c8c1", 0);
test_see("1r3r1k/p4pp1/2p1p2p/qpQP3P/2P5/3R4/PP3PP1/1K1R4 b - - 0 1", "a5a2", -800);
test_see("1r5k/p4pp1/2p1p2p/qpQP3P/2P2P2/1P1R4/P4rP1/1K1R4 b - - 0 1", "a5a2", 100);
test_see("r2q1rk1/1b2bppp/p2p1n2/1ppNp3/3nP3/P2P1N1P/BPP2PP1/R1BQR1K1 w - - 0 1", "d5e7", 0);
test_see("rnbqrbn1/pp3ppp/3p4/2p2k2/4p3/3B1K2/PPP2PPP/RNB1Q1NR w - - 0 1", "d3e4", 100);
test_see("rnb1k2r/p3p1pp/1p3p1b/7n/1N2N3/3P1PB1/PPP1P1PP/R2QKB1R w KQkq - 0 1", "e4d6", -200);
test_see("r1b1k2r/p4npp/1pp2p1b/7n/1N2N3/3P1PB1/PPP1P1PP/R2QKB1R w KQkq - 0 1", "e4d6", 0);
test_see("2r1k2r/pb4pp/5p1b/2KB3n/4N3/2NP1PB1/PPP1P1PP/R2Q3R w k - 0 1", "d5c6", -300);
test_see("2r1k2r/pb4pp/5p1b/2KB3n/1N2N3/3P1PB1/PPP1P1PP/R2Q3R w k - 0 1", "d5c6", 0);
test_see("2r1k3/pbr3pp/5p1b/2KB3n/1N2N3/3P1PB1/PPP1P1PP/R2Q3R w - - 0 1", "d5c6", -300);
test_see("5k2/p2P2pp/8/1pb5/1Nn1P1n1/6Q1/PPP4P/R3K1NR w KQ - 0 1", "d7d8q", 800);
test_see("r4k2/p2P2pp/8/1pb5/1Nn1P1n1/6Q1/PPP4P/R3K1NR w KQ - 0 1", "d7d8q", -100);
test_see("5k2/p2P2pp/1b6/1p6/1Nn1P1n1/8/PPP4P/R2QK1NR w KQ - 0 1", "d7d8q", 200);
test_see("4kbnr/p1P1pppp/b7/4q3/7n/8/PP1PPPPP/RNBQKBNR w KQk - 0 1", "c7c8q", -100);
test_see("4kbnr/p1P1pppp/b7/4q3/7n/8/PPQPPPPP/RNB1KBNR w KQk - 0 1", "c7c8q", 200);
test_see("4kbnr/p1P1pppp/b7/4q3/7n/8/PPQPPPPP/RNB1KBNR w KQk - 0 1", "c7c8q", 200);
test_see("4kbnr/p1P4p/b1q5/5pP1/4n3/5Q2/PP1PPP1P/RNB1KBNR w KQk f6 0 1", "g5f6", 0);
test_see("4kbnr/p1P4p/b1q5/5pP1/4n3/5Q2/PP1PPP1P/RNB1KBNR w KQk f6 0 1", "g5f6", 0);
test_see("4kbnr/p1P4p/b1q5/5pP1/4n2Q/8/PP1PPP1P/RNB1KBNR w KQk f6 0 1", "g5f6", 0);
test_see("1n2kb1r/p1P4p/2qb4/5pP1/4n2Q/8/PP1PPP1P/RNB1KBNR w KQk - 0 1", "c7b8q", 200);
test_see("rnbqk2r/pp3ppp/2p1pn2/3p4/3P4/N1P1BN2/PPB1PPPb/R2Q1RK1 w kq - 0 1", "g1h2", 300);
test_see("3N4/2K5/2n5/1k6/8/8/8/8 b - - 0 1", "c6d8", 0);
test_see("3n3r/2P5/8/1k6/8/8/3Q4/4K3 w - - 0 1", "c7d8q", 700);
test_see("r2n3r/2P1P3/4N3/1k6/8/8/8/4K3 w - - 0 1", "e6d8", 300);
test_see("8/8/8/1k6/6b1/4N3/2p3K1/3n4 w - - 0 1", "e3d1", 0);
test_see("8/8/1k6/8/8/2N1N3/4p1K1/3n4 w - - 0 1", "c3d1", 100);
test_see("r1bqk1nr/pppp1ppp/2n5/1B2p3/1b2P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 0 1", "e1g1", 0);
return 0;
}
Loading
Loading