{ -8, -1, 1, 8 }, // horse
{ -8, -1, 1, 8 }, // clobber
{ 7, 9 }, // breakthrough
+ {}, // immobile
{ -9, -8, -7, -1, 1, 7, 8, 9 }, // commoner
{ -9, -8, -7, -1, 1, 7, 8, 9 } // king
};
{ -8, -1, 1, 8 }, // horse
{}, // clobber
{ 7, 8, 9 }, // breakthrough
+ {}, // immobile
{ -9, -8, -7, -1, 1, 7, 8, 9 }, // commoner
{ -9, -8, -7, -1, 1, 7, 8, 9 } // king
};
{ NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // horse
{}, // clobber
{}, // breakthrough
+ {}, // immobile
{}, // commoner
{} // king
};
{ NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // horse
{}, // clobber
{}, // breakthrough
+ {}, // immobile
{}, // commoner
{} // king
};
7, // horse
0, // clobber
0, // breakthrough
+ 0, // immobile
0, // commoner
0 // king
};
7, // horse
0, // clobber
0, // breakthrough
+ 0, // immobile
0, // commoner
0 // king
};
}
+/// shift() moves a bitboard one step along direction D (mainly for pawns)
+
+constexpr Bitboard shift(Direction D, Bitboard b) {
+ return D == NORTH ? b << 8 : D == SOUTH ? b >> 8
+ : D == EAST ? (b & ~FileHBB) << 1 : D == WEST ? (b & ~FileABB) >> 1
+ : D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == NORTH_WEST ? (b & ~FileABB) << 7
+ : D == SOUTH_EAST ? (b & ~FileHBB) >> 7 : D == SOUTH_WEST ? (b & ~FileABB) >> 9
+ : 0;
+}
+
+
/// pawn_attacks_bb() returns the pawn attacks for the given color from the
/// squares in the given bitboard.
ExtMove* generate_drops(const Position& pos, ExtMove* moveList, PieceType pt, Bitboard b) {
if (pos.count_in_hand(Us, pt))
{
+ // Consider only drops on top of already placed pieces
+ if (pos.drop_on_top())
+ b &= shift<NORTH>(pos.pieces()) | Rank1BB;
if (pt == PAWN)
{
b &= ~promotion_zone_bb(Us, pos.promotion_rank(), pos.max_rank());
bool drop_loop() const;
bool captures_to_hand() const;
bool first_rank_drops() const;
+ bool drop_on_top() const;
bool immobility_illegal() const;
// winning conditions
Value stalemate_value(int ply = 0) const;
Bitboard capture_the_flag(Color c) const;
bool flag_move() const;
CheckCount max_check_count() const;
+ int connect_n() const;
CheckCount checks_given(Color c) const;
bool is_variant_end() const;
bool is_variant_end(Value& result, int ply = 0) const;
return var->firstRankDrops;
}
+inline bool Position::drop_on_top() const {
+ assert(var != nullptr);
+ return var->dropOnTop;
+}
+
inline bool Position::immobility_illegal() const {
assert(var != nullptr);
return var->immobilityIllegal;
return var->maxCheckCount;
}
+inline int Position::connect_n() const {
+ assert(var != nullptr);
+ return var->connectN;
+}
+
inline CheckCount Position::checks_given(Color c) const {
return st->checksGiven[c];
}
result = mated_in(ply);
return true;
}
+ // Connect-n
+ if (connect_n() > 0)
+ {
+ Bitboard b;
+ for (Direction d : {NORTH, NORTH_EAST, EAST, SOUTH_EAST})
+ {
+ b = pieces(~sideToMove);
+ for (int i = 1; i < connect_n() && b; i++)
+ b &= shift(d, b);
+ if (b)
+ {
+ result = mated_in(ply);
+ return true;
+ }
+ }
+ }
return false;
}
FersValueMg, AlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg, ChancellorValueMg,
AmazonValueMg, KnibisValueMg, BiskniValueMg,
ShogiPawnValueMg, LanceValueMg, ShogiKnightValueMg, EuroShogiKnightValueMg, GoldValueMg, HorseValueMg,
- ClobberPieceValueMg, BreakthroughPieceValueMg, CommonerValueMg },
+ ClobberPieceValueMg, BreakthroughPieceValueMg, ImmobilePieceValueMg, CommonerValueMg },
{ VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg,
FersValueEg, AlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg, ChancellorValueEg,
AmazonValueEg, KnibisValueMg, BiskniValueMg,
ShogiPawnValueEg, LanceValueEg, ShogiKnightValueEg, EuroShogiKnightValueEg, GoldValueEg, HorseValueEg,
- ClobberPieceValueEg, BreakthroughPieceValueEg, CommonerValueEg }
+ ClobberPieceValueEg, BreakthroughPieceValueEg, ImmobilePieceValueEg, CommonerValueEg }
};
namespace PSQT {
HorseValueMg = 1500, HorseValueEg = 1500,
ClobberPieceValueMg = 300, ClobberPieceValueEg = 300,
BreakthroughPieceValueMg = 300, BreakthroughPieceValueEg = 300,
+ ImmobilePieceValueMg = 100, ImmobilePieceValueEg = 100,
CommonerValueMg = 600, CommonerValueEg = 600,
MidgameLimit = 15258, EndgameLimit = 3915
NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK,
QUEEN, FERS, MET = FERS, ALFIL, SILVER, KHON = SILVER, AIWOK, BERS, DRAGON = BERS, CHANCELLOR,
AMAZON, KNIBIS, BISKNI, SHOGI_PAWN, LANCE, SHOGI_KNIGHT, EUROSHOGI_KNIGHT, GOLD, HORSE,
- CLOBBER_PIECE, BREAKTHROUGH_PIECE, COMMONER, KING,
+ CLOBBER_PIECE, BREAKTHROUGH_PIECE, IMMOBILE_PIECE, COMMONER, KING,
ALL_PIECES = 0,
PIECE_TYPE_NB = 1 << PIECE_TYPE_BITS
v->blackFlag = Rank1BB;
return v;
} ();
+ const Variant* connect4 = [&]{
+ Variant* v = new Variant();
+ v->maxRank = RANK_6;
+ v->maxFile = FILE_G;
+ v->reset_pieces();
+ v->add_piece(IMMOBILE_PIECE, 'p');
+ v->startFen = "7/7/7/7/7/7[PPPPPPPPPPPPPPPPPPPPPppppppppppppppppppppp] w 0 1";
+ v->pieceDrops = true;
+ v->dropOnTop = true;
+ v->promotionPieceTypes = {};
+ v->doubleStep = false;
+ v->castling = false;
+ v->stalemateValue = -VALUE_MATE;
+ v->immobilityIllegal = false;
+ v->connectN = 4;
+ return v;
+ } ();
// Add to UCI_Variant option
add("chess", chess);
add("shatar", shatar);
add("clobber", clobber);
add("breakthrough", breakthrough);
+ add("connect4", connect4);
}
void VariantMap::add(std::string s, const Variant* v) {
bool dropLoop = false;
bool capturesToHand = false;
bool firstRankDrops = false;
+ bool dropOnTop = false;
bool immobilityIllegal = false;
// game end
Value stalemateValue = VALUE_DRAW;
Bitboard blackFlag = 0;
bool flagMove = false;
CheckCount maxCheckCount = CheckCount(0);
+ int connectN = 0;
void add_piece(PieceType pt, char c) {
pieceToChar[make_piece(WHITE, pt)] = toupper(c);