Skip to content

Commit

Permalink
Merge remote-tracking branch 'fairy/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
ianfab committed Aug 26, 2023
2 parents ee109fb + 84e305f commit 5611138
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 43 deletions.
16 changes: 1 addition & 15 deletions src/evaluate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1280,22 +1280,8 @@ namespace {
// Connect-n
if (pos.connect_n() > 0)
{
std::vector<Direction> connect_directions;
for (const Direction& d : pos.getConnectDirections())

if (pos.connect_horizontal())
{
connect_directions.push_back(EAST);
}
if (pos.connect_vertical())
{
connect_directions.push_back(NORTH);
}
if (pos.connect_diagonal())
{
connect_directions.push_back(NORTH_EAST);
connect_directions.push_back(SOUTH_EAST);
}
for (Direction d : connect_directions)
{
// Find sufficiently large gaps
Bitboard b = pos.board_bb() & ~pos.pieces(Them);
Expand Down
17 changes: 16 additions & 1 deletion src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ namespace {
int rank;
std::stringstream ss(value);
target = 0;
while (!ss.eof() && ss >> file && ss >> rank)
while (!ss.eof() && ss >> file && file != '-' && ss >> rank)
{
if (Rank(rank - 1) > RANK_MAX || (file != '*' && File(tolower(file) - 'a') > FILE_MAX))
return false;
Expand Down Expand Up @@ -357,7 +357,10 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("mandatoryPiecePromotion", v->mandatoryPiecePromotion);
parse_attribute("pieceDemotion", v->pieceDemotion);
parse_attribute("blastOnCapture", v->blastOnCapture);
parse_attribute("blastImmuneTypes", v->blastImmuneTypes, v->pieceToChar);
parse_attribute("mutuallyImmuneTypes", v->mutuallyImmuneTypes, v->pieceToChar);
parse_attribute("petrifyOnCapture", v->petrifyOnCapture);
parse_attribute("petrifyBlastPieces", v->petrifyBlastPieces);
parse_attribute("doubleStep", v->doubleStep);
parse_attribute("doubleStepRegionWhite", v->doubleStepRegion[WHITE]);
parse_attribute("doubleStepRegionBlack", v->doubleStepRegion[BLACK]);
Expand Down Expand Up @@ -523,6 +526,7 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
// Check for limitations
if (v->pieceDrops && (v->arrowGating || v->duckGating || v->staticGating || v->pastGating))
std::cerr << "pieceDrops and arrowGating/duckGating are incompatible." << std::endl;

// Options incompatible with royal kings
if (v->pieceTypes & KING)
{
Expand All @@ -546,6 +550,17 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
std::cerr << piece_name(v->kingType) << " is not supported as kingType." << std::endl;
}
}
// Options incompatible with royal kings OR pseudo-royal kings. Possible in theory though:
// 1. In blast variants, moving a (pseudo-)royal blastImmuneType into another piece is legal.
// 2. In blast variants, capturing a piece next to a (pseudo-)royal blastImmuneType is legal.
// 3. Moving a (pseudo-)royal mutuallyImmuneType into a square threatened by the same type is legal.
if ((v->extinctionPseudoRoyal) || (v->pieceTypes & KING))
{
if (v->blastImmuneTypes)
std::cerr << "Can not use kings or pseudo-royal with blastImmuneTypes." << std::endl;
if (v->mutuallyImmuneTypes)
std::cerr << "Can not use kings or pseudo-royal with mutuallyImmuneTypes." << std::endl;
}
}
return v;
}
Expand Down
36 changes: 18 additions & 18 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,14 @@ bool Position::legal(Move m) const {
if (var->petrifyOnCapture && capture(m) && type_of(moved_piece(m)) == KING)
return false;

// mutuallyImmuneTypes (diplomacy in Atomar)-- In no-check Atomic, kings can be beside each other, but in Atomar, this prevents them from actually taking.
// Generalized to allow a custom set of pieces that can't capture a piece of the same type.
if (capture(m) &&
(mutually_immune_types() & type_of(moved_piece(m))) &&
(type_of(moved_piece(m)) == type_of(piece_on(to)))
)
return false;

// En passant captures are a tricky special case. Because they are rather
// uncommon, we do it simply by testing whether the king is attacked after
// the move is made.
Expand Down Expand Up @@ -1921,13 +1929,19 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
if (cambodian_moves() && type_of(pc) == ROOK && (square<KING>(them) & gates(them) & attacks_bb<ROOK>(to)))
st->gatesBB[them] ^= square<KING>(them);


// Remove the blast pieces
if (captured && (blast_on_capture() || var->petrifyOnCapture))
{
std::memset(st->unpromotedBycatch, 0, sizeof(st->unpromotedBycatch));
st->demotedBycatch = st->promotedBycatch = 0;
Bitboard blast = blast_on_capture() ? (attacks_bb<KING>(to) & ((pieces(WHITE) | pieces(BLACK)) ^ pieces(PAWN))) | to
: type_of(pc) != PAWN ? square_bb(to) : Bitboard(0);
Bitboard blastImmune = 0;
for (PieceSet ps = blast_immune_types(); ps;){
PieceType pt = pop_lsb(ps);
blastImmune |= pieces(pt);
};
Bitboard blast = blast_on_capture() ? ((attacks_bb<KING>(to) & ((pieces(WHITE) | pieces(BLACK)) ^ pieces(PAWN))) | to)
& (pieces() ^ blastImmune) : type_of(pc) != PAWN ? square_bb(to) : Bitboard(0);
while (blast)
{
Square bsq = pop_lsb(blast);
Expand Down Expand Up @@ -1989,7 +2003,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
}

// Make a wall square where the piece was
if (var->petrifyOnCapture)
if (bsq == to ? var->petrifyOnCapture : var->petrifyBlastPieces)
{
st->wallSquares |= bsq;
byTypeBB[ALL_PIECES] |= bsq;
Expand Down Expand Up @@ -2717,22 +2731,8 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
if (connect_n() > 0)
{
Bitboard b;
std::vector<Direction> connect_directions;

if (connect_horizontal())
{
connect_directions.push_back(EAST);
}
if (connect_vertical())
{
connect_directions.push_back(NORTH);
}
if (connect_diagonal())
{
connect_directions.push_back(NORTH_EAST);
connect_directions.push_back(SOUTH_EAST);
}
for (Direction d : connect_directions)
for (Direction d : var->connect_directions)
{
b = pieces(~sideToMove);
for (int i = 1; i < connect_n() && b; i++)
Expand Down
31 changes: 24 additions & 7 deletions src/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ class Position {
bool mandatory_piece_promotion() const;
bool piece_demotion() const;
bool blast_on_capture() const;
PieceSet blast_immune_types() const;
PieceSet mutually_immune_types() const;
bool endgame_eval() const;
Bitboard double_step_region(Color c) const;
Bitboard triple_step_region(Color c) const;
Expand Down Expand Up @@ -206,6 +208,7 @@ class Position {
bool connect_horizontal() const;
bool connect_vertical() const;
bool connect_diagonal() const;
const std::vector<Direction>& getConnectDirections() const;

CheckCount checks_remaining(Color c) const;
MaterialCounting material_counting() const;
Expand Down Expand Up @@ -489,6 +492,16 @@ inline bool Position::blast_on_capture() const {
return var->blastOnCapture;
}

inline PieceSet Position::blast_immune_types() const {
assert(var != nullptr);
return var->blastImmuneTypes;
}

inline PieceSet Position::mutually_immune_types() const {
assert(var != nullptr);
return var->mutuallyImmuneTypes;
}

inline bool Position::endgame_eval() const {
assert(var != nullptr);
return var->endgameEval && !count_in_hand(ALL_PIECES) && count<KING>() == 2;
Expand Down Expand Up @@ -965,6 +978,10 @@ inline bool Position::connect_diagonal() const {
return var->connectDiagonal;
}

inline const std::vector<Direction>& Position::getConnectDirections() const {
assert(var != nullptr);
return var->connect_directions;
}

inline CheckCount Position::checks_remaining(Color c) const {
return st->checksRemaining[c];
Expand Down Expand Up @@ -1391,18 +1408,18 @@ inline bool Position::allow_virtual_drop(Color c, PieceType pt) const {
}

inline Value Position::material_counting_result() const {
auto weigth_count = [this](PieceType pt, int v){ return v * (count(WHITE, pt) - count(BLACK, pt)); };
auto weight_count = [this](PieceType pt, int v){ return v * (count(WHITE, pt) - count(BLACK, pt)); };
int materialCount;
Value result;
switch (var->materialCounting)
{
case JANGGI_MATERIAL:
materialCount = weigth_count(ROOK, 13)
+ weigth_count(JANGGI_CANNON, 7)
+ weigth_count(HORSE, 5)
+ weigth_count(JANGGI_ELEPHANT, 3)
+ weigth_count(WAZIR, 3)
+ weigth_count(SOLDIER, 2)
materialCount = weight_count(ROOK, 13)
+ weight_count(JANGGI_CANNON, 7)
+ weight_count(HORSE, 5)
+ weight_count(JANGGI_ELEPHANT, 3)
+ weight_count(WAZIR, 3)
+ weight_count(SOLDIER, 2)
- 1;
result = materialCount > 0 ? VALUE_MATE : -VALUE_MATE;
break;
Expand Down
2 changes: 1 addition & 1 deletion src/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -936,7 +936,7 @@ namespace {
&& (ss-1)->statScore < 23767
&& eval >= beta
&& eval >= ss->staticEval
&& ss->staticEval >= beta - 20 * depth - 22 * improving + 168 * ss->ttPv + 159 + 200 * (!pos.double_step_region(pos.side_to_move()) && pos.piece_to_char()[PAWN] != ' ')
&& ss->staticEval >= beta - 20 * depth - 22 * improving + 168 * ss->ttPv + 159 + 200 * (!pos.double_step_region(pos.side_to_move()) && (pos.piece_types() & PAWN))
&& !excludedMove
&& pos.non_pawn_material(us)
&& pos.count<ALL_PIECES>(~us) != pos.count<PAWN>(~us)
Expand Down
25 changes: 25 additions & 0 deletions src/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,15 @@ namespace {
return v;
}

// Atomar chess
// https://web.archive.org/web/20230519082613/https://chronatog.com/wp-content/uploads/2021/09/atomar-chess-rules.pdf
Variant* atomar_variant() {
Variant* v = nocheckatomic_variant()->init();
v->blastImmuneTypes = piece_set(COMMONER);
v->mutuallyImmuneTypes = piece_set(COMMONER);
return v;
}

#ifdef ALLVARS
// Duck chess
Variant* duck_variant() {
Expand Down Expand Up @@ -1802,6 +1811,7 @@ void VariantMap::init() {
add("isolation7x7", isolation7x7_variant());
add("snailtrail", snailtrail_variant());
add("fox-and-hounds", fox_and_hounds_variant());
add("atomar", atomar_variant());
#ifdef ALLVARS
add("duck", duck_variant());
#endif
Expand Down Expand Up @@ -2016,6 +2026,21 @@ Variant* Variant::conclude() {
break;
}

connect_directions.clear();
if (connectHorizontal)
{
connect_directions.push_back(EAST);
}
if (connectVertical)
{
connect_directions.push_back(NORTH);
}
if (connectDiagonal)
{
connect_directions.push_back(NORTH_EAST);
connect_directions.push_back(SOUTH_EAST);
}

return this;
}

Expand Down
4 changes: 4 additions & 0 deletions src/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ struct Variant {
bool mandatoryPiecePromotion = false;
bool pieceDemotion = false;
bool blastOnCapture = false;
PieceSet blastImmuneTypes = NO_PIECE_SET;
PieceSet mutuallyImmuneTypes = NO_PIECE_SET;
bool petrifyOnCapture = false;
bool petrifyBlastPieces = false;
bool doubleStep = true;
Bitboard doubleStepRegion[COLOR_NB] = {Rank2BB, Rank7BB};
Bitboard tripleStepRegion[COLOR_NB] = {};
Expand Down Expand Up @@ -167,6 +170,7 @@ struct Variant {
int nnueMaxPieces;
bool endgameEval = false;
bool shogiStylePromotions = false;
std::vector<Direction> connect_directions;

void add_piece(PieceType pt, char c, std::string betza = "", char c2 = ' ') {
// Avoid ambiguous definition by removing existing piece with same letter
Expand Down
22 changes: 21 additions & 1 deletion src/variants.ini
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,10 @@
# mandatoryPiecePromotion: piece promotion (and demotion if enabled) is mandatory [bool] (default: false)
# pieceDemotion: enable demotion of pieces (e.g., Kyoto shogi) [bool] (default: false)
# blastOnCapture: captures explode all adjacent non-pawn pieces (e.g., atomic chess) [bool] (default: false)
# blastImmuneTypes: pieces completely immune to explosions (even at ground zero) [PieceSet] (default: none)
# mutuallyImmuneTypes: pieces that can't capture another piece of same types (e.g., kings (commoners) in atomar) [PieceSet] (default: none)
# petrifyOnCapture: non-pawn pieces are turned into wall squares when capturing [bool] (default: false)
# petrifyBlastPieces: if petrify and blast combined, should pieces destroyed in the blast be petrified? [bool] (default: false)
# doubleStep: enable pawn double step [bool] (default: true)
# doubleStepRegionWhite: region where pawn double steps are allowed for white [Bitboard] (default: *2)
# doubleStepRegionBlack: region where pawn double steps are allowed for black [Bitboard] (default: *2)
Expand Down Expand Up @@ -339,6 +342,12 @@ capturesToHand = true
dropChecks = false
whiteDropRegion = *1 *2 *3 *4 *5
blackDropRegion = *6 *7 *8 *9 *10
mobilityRegionWhiteFers = d1 f1 e2 d3 f3
mobilityRegionBlackFers = d8 f8 e9 d10 f10
mobilityRegionWhiteElephant = c1 g1 a3 e3 i3 c5 g5
mobilityRegionBlackElephant = c6 g6 a8 e8 i8 c10 g10
mobilityRegionWhiteSoldier = a4 a5 c4 c5 e4 e5 g4 g5 i4 i5 *6 *7 *8 *9 *10
mobilityRegionBlackSoldier = *1 *2 *3 *4 *5 a6 a7 c6 c7 e6 e7 g6 g7 i6 i7

# Hybrid variant of janggi and crazyhouse
[janggihouse:janggi]
Expand Down Expand Up @@ -1326,7 +1335,7 @@ customPiece1 = i:NN
customPiece2 = h:mfWcfFfhmnN
startFen = r8r/3nkqn3/hcb1ii1bch/1hhhhhhhh1/10/10/1HHHHHHHH1/HCB1II1BCH/3NKQN3/R8R
#technically not needed because of initial setup
##enPassantRegion = 0
##enPassantRegion = -
##castling = false

#https://boardgamegeek.com/boardgame/32/buffalo-chess
Expand Down Expand Up @@ -1574,3 +1583,14 @@ customPiece4 = w:mRpRFAcpR
customPiece5 = f:mBpBWDcpB
promotedPieceType = u:w a:w c:f i:f
startFen = lnsgkgsnl/1rci1uab1/p1p1p1p1p/9/9/9/P1P1P1P1P/1BAU1ICR1/LNSGKGSNL[-] w 0 1

#https://www.chessvariants.com/difftaking.dir/deadsquare.html
[nuclear:atomic]
#define a piece that looks exactly like a pawn, but is not one. Takes care of major differences:
#1. Pawns can be petrified.
#2. Pawns can be destroyed by explosions.
pawn = -
customPiece1 = p:fmWfceFifmnD
pawnTypes = p
petrifyOnCapture = true
enPassantRegion = -

0 comments on commit 5611138

Please sign in to comment.