Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop / Promotion / Multi-Step Region Per Piece Type (Closing Milestone v14.0.2) #792

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
29cc75b
Update Makefile
yjf2002ghty May 3, 2024
83893fd
Add files via upload
yjf2002ghty May 3, 2024
5ee3491
Update variants.ini
yjf2002ghty May 3, 2024
eba6955
Update types.h: Fix assert
yjf2002ghty May 3, 2024
5d862eb
Fix support for no square
yjf2002ghty May 3, 2024
0645ef1
Fix rank syntax detection
yjf2002ghty May 3, 2024
75e8e3d
Convert memory allocation to auto managed
yjf2002ghty May 3, 2024
58f1e54
Fix assert & revert Makefile
yjf2002ghty May 3, 2024
ce2c450
Small performance optimization
yjf2002ghty May 4, 2024
fcc75bd
test
yjf2002ghty May 7, 2024
2673675
Update position.h: Fix not_moved_pieces[2]
yjf2002ghty May 7, 2024
617029a
Update evaluate.cpp: Remove unnecessary changes
yjf2002ghty May 7, 2024
188b340
Add PieceTypeBitboardGroup parser support for null value
yjf2002ghty May 7, 2024
ad9cbb6
Update Makefile: Test enabling strict aliasing optimization
yjf2002ghty Jun 2, 2024
a1213a8
Update stockfish.yml: Check debug=yes optimize=yes
yjf2002ghty Jun 2, 2024
1788305
Update stockfish.yml: Remove additional compiler flags
yjf2002ghty Jun 2, 2024
8642787
Update stockfish.yml: Clear CXXFLAGS when optimize=yes debug=yes
yjf2002ghty Jun 2, 2024
9c50bd6
Update Makefile: Disable -fno-strict-aliasing optimization
yjf2002ghty Jul 9, 2024
e6f1c28
Update stockfish.yml
yjf2002ghty Jul 9, 2024
c73e2c6
Update stockfish.yml
yjf2002ghty Jul 9, 2024
88961b3
Update stockfish.yml
yjf2002ghty Jul 9, 2024
af9f4a4
Update stockfish.yml
yjf2002ghty Jul 9, 2024
d8b28d9
Revert changes in CI & Makefile
yjf2002ghty Jul 9, 2024
289bc68
Remove comment prefix & Remove unnecessary comments
yjf2002ghty Nov 29, 2024
881ff61
Revert changes in bitboard.h
yjf2002ghty Nov 29, 2024
42d763d
Merge branch 'master' into patch-1
yjf2002ghty Dec 30, 2024
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
6 changes: 4 additions & 2 deletions src/endgame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ Value Endgame<KPK>::operator()(const Position& pos) const {
Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;

// Non-standard promotion, evaluation unclear
if ( pos.promotion_zone(us) != rank_bb(relative_rank(us, RANK_8, pos.max_rank()))
/// Since KPK means King-Pawn vs. King Endgame, the piece type is assumed to be PAWN. It can cause problems if the pawn is something else (e.g. Custom pawn piece)
if ( pos.promotion_zone(us, PAWN) != rank_bb(relative_rank(us, RANK_8, pos.max_rank()))
|| RANK_MAX != RANK_8
|| !(pos.promotion_piece_types(us) & QUEEN))
{
Expand Down Expand Up @@ -998,7 +999,8 @@ ScaleFactor Endgame<KPKP>::operator()(const Position& pos) const {

// Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw,
// it's probably at least a draw even with the pawn.
if ( pos.promotion_zone(us) != rank_bb(relative_rank(us, RANK_8, pos.max_rank()))
/// Since KPKP means King-Pawn vs. King-Pawn Endgame, the piece type is assumed to PAWN. It can cause problems if the pawn is something else (e.g. Custom pawn piece)
if ( pos.promotion_zone(us, PAWN) != rank_bb(relative_rank(us, RANK_8, pos.max_rank()))
|| RANK_MAX != RANK_8
|| !(pos.promotion_piece_types(us) & QUEEN))
return SCALE_FACTOR_NONE;
Expand Down
7 changes: 4 additions & 3 deletions src/evaluate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ namespace {
// Piece promotion bonus
if (pos.promoted_piece_type(Pt) != NO_PIECE_TYPE)
{
Bitboard zone = pos.promotion_zone(Us);
Bitboard zone = pos.promotion_zone(Us, Pt);
if (zone & (b | s))
score += make_score(PieceValue[MG][pos.promoted_piece_type(Pt)] - PieceValue[MG][Pt],
PieceValue[EG][pos.promoted_piece_type(Pt)] - PieceValue[EG][Pt]) / (zone & s && b ? 6 : 12);
Expand Down Expand Up @@ -738,7 +738,7 @@ namespace {
if (pos.promoted_piece_type(pt))
{
otherChecks = attacks_bb(Us, pos.promoted_piece_type(pt), ksq, pos.pieces()) & attackedBy[Them][pt]
& pos.promotion_zone(Them) & pos.board_bb();
& pos.promotion_zone(Them, pt) & pos.board_bb();
if (otherChecks & safe)
kingDanger += SafeCheck[FAIRY_PIECES][more_than_one(otherChecks & safe)];
else
Expand Down Expand Up @@ -1135,7 +1135,8 @@ namespace {
bool pawnsOnly = !(pos.pieces(Us) ^ pos.pieces(Us, PAWN));

// Early exit if, for example, both queens or 6 minor pieces have been exchanged
if (pos.non_pawn_material() < SpaceThreshold && !pawnsOnly && pos.double_step_region(Us))
/// By default double step is used for pawns in enhancing opening evaluation, so the piece type is assumed to be PAWN. It can cause problems if the pawn is something else (e.g. Custom pawn piece)
if (pos.non_pawn_material() < SpaceThreshold && !pawnsOnly && pos.double_step_region(Us, PAWN))
return SCORE_ZERO;

constexpr Color Them = ~Us;
Expand Down
12 changes: 8 additions & 4 deletions src/movegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,13 @@ namespace {
constexpr Direction UpRight = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
constexpr Direction UpLeft = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);

const Bitboard promotionZone = pos.promotion_zone(Us);
/// Since it's generate_pawn_moves, the piece type is assumed to be PAWN. It can cause problems if the pawn is something else (e.g. Custom pawn piece)
const Bitboard promotionZone = pos.promotion_zone(Us, PAWN);
const Bitboard standardPromotionZone = pos.sittuyin_promotion() ? Bitboard(0) : promotionZone;
const Bitboard doubleStepRegion = pos.double_step_region(Us);
const Bitboard tripleStepRegion = pos.triple_step_region(Us);
/// Since it's generate_pawn_moves, the piece type is assumed to be PAWN. It can cause problems if the pawn is something else (e.g. Custom pawn piece)
const Bitboard doubleStepRegion = pos.double_step_region(Us, PAWN);
/// Since it's generate_pawn_moves, the piece type is assumed to be PAWN. It can cause problems if the pawn is something else (e.g. Custom pawn piece)
const Bitboard tripleStepRegion = pos.triple_step_region(Us, PAWN);

const Bitboard pawns = pos.pieces(Us, PAWN);
const Bitboard movable = pos.board_bb(Us, PAWN) & ~pos.pieces();
Expand Down Expand Up @@ -302,13 +305,14 @@ namespace {
Bitboard b = ( (attacks & pos.pieces())
| (quiets & ~pos.pieces()));
Bitboard b1 = b & target;
Bitboard promotion_zone = pos.promotion_zone(Us);
Bitboard promotion_zone = pos.promotion_zone(Us, Pt);
PieceType promPt = pos.promoted_piece_type(Pt);
Bitboard b2 = promPt && (!pos.promotion_limit(promPt) || pos.promotion_limit(promPt) > pos.count(Us, promPt)) ? b1 : Bitboard(0);
Bitboard b3 = pos.piece_demotion() && pos.is_promoted(from) ? b1 : Bitboard(0);
Bitboard pawnPromotions = pos.variant()->promotionPawnTypes[Us] & Pt ? b & (Type == EVASIONS ? target : ~pos.pieces(Us)) & promotion_zone : Bitboard(0);
Bitboard epSquares = pos.variant()->enPassantTypes[Us] & Pt ? attacks & ~quiets & pos.ep_squares() & ~pos.pieces() : Bitboard(0);


// target squares considering pawn promotions
if (pawnPromotions && pos.mandatory_pawn_promotion())
b1 &= ~pawnPromotions;
Expand Down
6 changes: 6 additions & 0 deletions src/movegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,17 @@ namespace Stockfish {
class Position;

enum GenType {
//Moves that a piece is removed from the board as part of the completion of the move
CAPTURES,
//Moves which do not alter material, thus no captures nor promotions
QUIETS,
//Moves which do not alter material, and give check to opponent
QUIET_CHECKS,
//Check evasion moves, including interpositions, attacker capture and king withdrawal
EVASIONS,
//Moves that are not check evasion moves
NON_EVASIONS,
//Moves that are legal
LEGAL
};

Expand Down
193 changes: 193 additions & 0 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,162 @@ namespace {
return !ss.fail();
}

template <> bool set(const std::string& value, PieceTypeBitboardGroup& target) {
size_t i;
int ParserState = -1;
int RankNum = 0;
int FileNum = 0;
char PieceChar = 0;
Bitboard board = 0x00;
// String parser using state machine
for (i = 0; i < value.length(); i++)
{
const char ch = value.at(i);
if (ch == ' ')
{
continue;
}
if (ParserState == -1) // Initial state, if "-" exists here then it means a null value. e.g. promotionRegion = - means no promotion region
{
if (ch == '-')
{
return true;
}
ParserState = 0;
}
if (ParserState == 0) // Find piece type character
{
if (ch >= 'A' && ch <= 'Z')
{
PieceChar = ch;
ParserState = 1;
}
else
{
std::cerr << "At char " << i << " of PieceTypeBitboardGroup declaration: Illegal piece type character: " << ch << std::endl;
return false;
}
}
else if (ParserState == 1) // Find "("
{
if (ch == '(')
{
ParserState = 2;
}
else
{
std::cerr << "At char " << i << " of PieceTypeBitboardGroup declaration: Expect \"(\". Actual: " << ch << std::endl;
return false;
}
}
else if (ParserState == 2) //Find file
{
if (ch >= 'a' && ch <= 'z')
{
FileNum = ch - 'a';
ParserState = 3;
}
else if (ch == '*')
{
FileNum = -1;
ParserState = 3;
}
else
{
std::cerr << "At char " << i << " of PieceTypeBitboardGroup declaration: Illegal file character: " << ch << std::endl;
return false;
}
}
else if (ParserState == 3) //Find rank and terminator "," or ")"
{
if (ch == '*')
{
RankNum = -1;
}
else if (ch >= '0' && ch <= '9' && RankNum >= 0)
{
RankNum = RankNum * 10 + (ch - '0');
}
else if (ch == ',' || ch == ')')
{
if (RankNum == 0) // Here if RankNum==0 then it means either user delcared a 0 as rank, or no rank number delcared at all
{
std::cerr << "At char " << i << " of PieceTypeBitboardGroup declaration: Illegal rank number: " << RankNum << std::endl;
return false;
}
if (RankNum > 0) //When RankNum==-1, it means a whole File.
{
RankNum--;
}
if (RankNum < -1 || RankNum > RANK_MAX)
{
std::cerr << "At char " << i << " of PieceTypeBitboardGroup declaration: Max rank number exceeds. Max: " << RANK_MAX << "; Actual: " << RankNum << std::endl;
return false;
}
else if (FileNum < -1 || FileNum > FILE_MAX)
{
std::cerr << "At char " << i << " of PieceTypeBitboardGroup declaration: Max file number exceeds. Max: " << FILE_MAX << "; Actual: " << FileNum << std::endl;
return false;
}
if (RankNum == -1 && FileNum == -1)
{
board ^= ~board;
}
else if (FileNum == -1)
{
board |= rank_bb(Rank(RankNum));
}
else if (RankNum == -1)
{
board |= file_bb(File(FileNum));
}
else
{
board |= square_bb(make_square(File(FileNum), Rank(RankNum)));
}
if (ch == ')')
{
target.set(PieceChar, board);
ParserState = 4;
}
else
{
RankNum = 0;
FileNum = 0;
ParserState = 2;
}
}
else
{
std::cerr << "At char " << i << " of PieceTypeBitboardGroup declaration: Illegal rank character: " << ch << std::endl;
return false;
}
}
else if (ParserState == 4) // Find ";"
{
if (ch == ';')
{
ParserState = 0;
RankNum = 0;
FileNum = 0;
PieceChar = 0;
board = 0x00;
}
else
{
std::cerr << "At char " << i << " of PieceTypeBitboardGroup declaration: Expects \";\"." << std::endl;
return false;
}
}
}
if (ParserState != 0)
{
std::cerr << "At char " << i << " of PieceTypeBitboardGroup declaration: Unterminated expression." << std::endl;
return false;
}
return true;
}


template <> bool set(const std::string& value, CastlingRights& target) {
char c;
Expand Down Expand Up @@ -209,6 +365,7 @@ template <bool Current, class T> bool VariantParser<DoCheck>::parse_attribute(co
: std::is_same<T, ChasingRule>() ? "ChasingRule"
: std::is_same<T, EnclosingRule>() ? "EnclosingRule"
: std::is_same<T, Bitboard>() ? "Bitboard"
: std::is_same<T, PieceTypeBitboardGroup>() ? "PieceTypeBitboardGroup"
: std::is_same<T, CastlingRights>() ? "CastlingRights"
: std::is_same<T, WallingRule>() ? "WallingRule"
: typeid(T).name();
Expand Down Expand Up @@ -369,6 +526,15 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("startFen", v->startFen);
parse_attribute("promotionRegionWhite", v->promotionRegion[WHITE]);
parse_attribute("promotionRegionBlack", v->promotionRegion[BLACK]);
parse_attribute("pieceSpecificPromotionRegion", v->pieceSpecificPromotionRegion);
if (v->pieceSpecificPromotionRegion && !parse_attribute("whitePiecePromotionRegion", v->whitePiecePromotionRegion))
{
std::cerr << "Syntax error in whitePiecePromotionRegion or missing whitePiecePromotionRegion definition." << std::endl;
}
if (v->pieceSpecificPromotionRegion && !parse_attribute("blackPiecePromotionRegion", v->blackPiecePromotionRegion))
{
std::cerr << "Syntax error in blackPiecePromotionRegion or missing blackPiecePromotionRegion definition." << std::endl;
}
// Take the first promotionPawnTypes as the main promotionPawnType
parse_attribute("promotionPawnTypes", v->promotionPawnType[WHITE], v->pieceToChar);
parse_attribute("promotionPawnTypes", v->promotionPawnType[BLACK], v->pieceToChar);
Expand Down Expand Up @@ -422,6 +588,24 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("doubleStep", v->doubleStep);
parse_attribute("doubleStepRegionWhite", v->doubleStepRegion[WHITE]);
parse_attribute("doubleStepRegionBlack", v->doubleStepRegion[BLACK]);
parse_attribute("pieceSpecificDoubleStepRegion", v->pieceSpecificDoubleStepRegion);
if (v->pieceSpecificDoubleStepRegion && !parse_attribute("whitePieceDoubleStepRegion", v->whitePieceDoubleStepRegion))
{
std::cerr << "Syntax error in whitePieceDoubleStepRegion or missing whitePieceDoubleStepRegion definition." << std::endl;
}
if (v->pieceSpecificDoubleStepRegion && !parse_attribute("blackPieceDoubleStepRegion", v->blackPieceDoubleStepRegion))
{
std::cerr << "Syntax error in blackPieceDoubleStepRegion or missing blackPieceDoubleStepRegion definition." << std::endl;
}
parse_attribute("pieceSpecificTripleStepRegion", v->pieceSpecificTripleStepRegion);
if (v->pieceSpecificTripleStepRegion && !parse_attribute("whitePieceTripleStepRegion", v->whitePieceTripleStepRegion))
{
std::cerr << "Syntax error in whitePieceTripleStepRegion or missing whitePieceTripleStepRegion definition." << std::endl;
}
if (v->pieceSpecificTripleStepRegion && !parse_attribute("blackPieceTripleStepRegion", v->blackPieceTripleStepRegion))
{
std::cerr << "Syntax error in blackPieceTripleStepRegion or missing blackPieceTripleStepRegion definition." << std::endl;
}
parse_attribute("tripleStepRegionWhite", v->tripleStepRegion[WHITE]);
parse_attribute("tripleStepRegionBlack", v->tripleStepRegion[BLACK]);
parse_attribute("enPassantRegion", v->enPassantRegion);
Expand Down Expand Up @@ -460,6 +644,15 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("enclosingDropStart", v->enclosingDropStart);
parse_attribute("whiteDropRegion", v->whiteDropRegion);
parse_attribute("blackDropRegion", v->blackDropRegion);
parse_attribute("pieceSpecificDropRegion", v->pieceSpecificDropRegion);
if (v->pieceSpecificDropRegion && !parse_attribute("whitePieceDropRegion", v->whitePieceDropRegion))
{
std::cerr << "Syntax error in whitePieceDropRegion or missing whitePieceDropRegion definition." << std::endl;
}
if (v->pieceSpecificDropRegion && !parse_attribute("blackPieceDropRegion", v->blackPieceDropRegion))
{
std::cerr << "Syntax error in blackPieceDropRegion or missing blackPieceDropRegion definition." << std::endl;
}
parse_attribute("sittuyinRookDrop", v->sittuyinRookDrop);
parse_attribute("dropOppositeColoredBishop", v->dropOppositeColoredBishop);
parse_attribute("dropPromoted", v->dropPromoted);
Expand Down
12 changes: 6 additions & 6 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1336,7 +1336,7 @@ bool Position::pseudo_legal(const Move m) const {
// Handle the case where a mandatory piece promotion/demotion is not taken
if ( mandatory_piece_promotion()
&& (is_promoted(from) ? piece_demotion() : promoted_piece_type(type_of(pc)) != NO_PIECE_TYPE)
&& (promotion_zone(us) & (SquareBB[from] | to))
&& (promotion_zone(pc) & (SquareBB[from] | to))
&& (!piece_promotion_on_capture() || capture(m)))
return false;

Expand All @@ -1358,16 +1358,16 @@ bool Position::pseudo_legal(const Move m) const {
{
// We have already handled promotion moves, so destination
// cannot be on the 8th/1st rank.
if (mandatory_pawn_promotion() && (promotion_zone(us) & to) && !sittuyin_promotion())
if (mandatory_pawn_promotion() && (promotion_zone(pc) & to) && !sittuyin_promotion())
return false;

if ( !(pawn_attacks_bb(us, from) & pieces(~us) & to) // Not a capture
&& !((from + pawn_push(us) == to) && !(pieces() & to)) // Not a single push
&& !( (from + 2 * pawn_push(us) == to) // Not a double push
&& (double_step_region(us) & from)
&& (double_step_region(pc) & from)
&& !(pieces() & (to | (to - pawn_push(us)))))
&& !( (from + 3 * pawn_push(us) == to) // Not a triple push
&& (triple_step_region(us) & from)
&& (triple_step_region(pc) & from)
&& !(pieces() & (to | (to - pawn_push(us)) | (to - 2 * pawn_push(us))))))
return false;
}
Expand Down Expand Up @@ -1802,7 +1802,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
{
Piece promotion = make_piece(us, type_of(m) == PROMOTION ? promotion_type(m) : promoted_piece_type(PAWN));

assert((promotion_zone(us) & to) || sittuyin_promotion());
assert((promotion_zone(pc) & to) || sittuyin_promotion());
assert(type_of(promotion) >= KNIGHT && type_of(promotion) < KING);

st->promotionPawn = piece_on(to);
Expand Down Expand Up @@ -2176,7 +2176,7 @@ void Position::undo_move(Move m) {

if (type_of(m) == PROMOTION)
{
assert((promotion_zone(us) & to) || sittuyin_promotion());
assert((promotion_zone(st->promotionPawn) & to) || sittuyin_promotion());
assert(type_of(pc) == promotion_type(m));
assert(type_of(pc) >= KNIGHT && type_of(pc) < KING);
assert(type_of(st->promotionPawn) == promotion_pawn_type(us) || !captures_to_hand());
Expand Down
Loading
Loading