parse_attribute("flagPieceSafe", v->flagPieceSafe);
parse_attribute("checkCounting", v->checkCounting);
parse_attribute("connectN", v->connectN);
+ parse_attribute("connectPieceTypes", v->connectPieceTypes, v->pieceToChar);
parse_attribute("connectHorizontal", v->connectHorizontal);
parse_attribute("connectVertical", v->connectVertical);
parse_attribute("connectDiagonal", v->connectDiagonal);
parse_attribute("connectRegion1Black", v->connectRegion1[BLACK]);
parse_attribute("connectRegion2Black", v->connectRegion2[BLACK]);
parse_attribute("connectNxN", v->connectNxN);
+ parse_attribute("collinearN", v->collinearN);
parse_attribute("connectValue", v->connectValue);
parse_attribute("materialCounting", v->materialCounting);
parse_attribute("adjudicateFullBoard", v->adjudicateFullBoard);
/// Position::is_immediate_game_end() tests whether the position ends the game
/// immediately by a variant rule, i.e., there are no more legal moves.
-/// It does not not detect stalemates.
+/// It does not detect stalemates.
bool Position::is_immediate_game_end(Value& result, int ply) const {
result = mated_in(ply);
return true;
}
+
+ //Calculate eligible pieces for connection once.
+ Bitboard connectPieces = 0;
+ for (PieceSet ps = connect_piece_types(); ps;){
+ PieceType pt = pop_lsb(ps);
+ connectPieces |= pieces(pt);
+ };
+ connectPieces &= pieces(~sideToMove);
+
// Connect-n
if (connect_n() > 0)
{
for (Direction d : var->connect_directions)
{
- b = pieces(~sideToMove);
+ b = connectPieces;
for (int i = 1; i < connect_n() && b; i++)
b &= shift(d, b);
if (b)
}
}
- if ((var->connectRegion1[~sideToMove] & pieces(~sideToMove)) && (var->connectRegion2[~sideToMove] & pieces(~sideToMove)))
+ if ((var->connectRegion1[~sideToMove] & connectPieces) && (var->connectRegion2[~sideToMove] & connectPieces))
{
Bitboard target = var->connectRegion2[~sideToMove];
- Bitboard current = var->connectRegion1[~sideToMove] & pieces(~sideToMove);
+ Bitboard current = var->connectRegion1[~sideToMove] & connectPieces;
while (true) {
Bitboard newBitboard = 0;
for (Direction d : var->connect_directions) {
- newBitboard |= shift(d, current | newBitboard) & pieces(~sideToMove); // the "| newBitboard" here probably saves a few loops
+ newBitboard |= shift(d, current | newBitboard) & connectPieces; // the "| newBitboard" here probably saves a few loops
}
if (newBitboard & target) {
if (connect_nxn())
{
- Bitboard connectors = pieces(~sideToMove);
+ Bitboard connectors = connectPieces;
for (int i = 1; i < connect_nxn() && connectors; i++)
connectors &= shift<SOUTH>(connectors) & shift<EAST>(connectors) & shift<SOUTH_EAST>(connectors);
if (connectors)
}
}
+ // Collinear-n
+ if (collinear_n() > 0) {
+ Bitboard allPieces = connectPieces;
+ for (Direction d : var->connect_directions) {
+ Bitboard b = allPieces;
+ while (b) {
+ Square s = pop_lsb(b);
+
+ int total_count = 1; // Start with the current piece
+
+ // Check in both directions
+ for (int sign : {-1, 1}) {
+ Bitboard shifted = shift(sign * d, square_bb(s));
+ while (shifted) {
+ if (shifted & b) {
+ total_count++;
+ b &= ~shifted; // Remove this piece from further consideration
+ }
+ shifted = shift(sign * d, shifted);
+ }
+ }
+
+ if (total_count >= collinear_n()) {
+ result = convert_mate_value(-var->connectValue, ply);
+ return true;
+ }
+ }
+ }
+ }
+
// Check for bikjang rule (Janggi), double passing, or board running full
if ( (st->pliesFromNull > 0 && ((st->bikjang && st->previous->bikjang) || (st->pass && st->previous->pass)))
|| (var->adjudicateFullBoard && !(~pieces() & board_bb())))
bool flag_reached(Color c) const;
bool check_counting() const;
int connect_n() const;
+ PieceSet connect_piece_types() const;
bool connect_horizontal() const;
bool connect_vertical() const;
bool connect_diagonal() const;
const std::vector<Direction>& getConnectDirections() const;
int connect_nxn() const;
+ int collinear_n() const;
CheckCount checks_remaining(Color c) const;
MaterialCounting material_counting() const;
return var->connectN;
}
+inline PieceSet Position::connect_piece_types() const {
+ assert(var != nullptr);
+ return var->connectPieceTypes;
+}
+
inline bool Position::connect_horizontal() const {
assert(var != nullptr);
return var->connectHorizontal;
return var->connectNxN;
}
+inline int Position::collinear_n() const {
+ assert(var != nullptr);
+ return var->collinearN;
+}
+
inline CheckCount Position::checks_remaining(Color c) const {
return st->checksRemaining[c];
}
connect_directions.push_back(SOUTH_EAST);
}
+ // If not a connect variant, set connectPieceTypes to no pieces.
+ if ( !(connectRegion1[WHITE] || connectRegion1[BLACK] || connectN || connectNxN || collinearN) )
+ {
+ connectPieceTypes = NO_PIECE_SET;
+ }
+ //Otherwise optimize to pieces actually in the game.
+ else
+ {
+ connectPieceTypes = connectPieceTypes & pieceTypes;
+ };
+
return this;
}
bool flagPieceSafe = false;
bool checkCounting = false;
int connectN = 0;
+ PieceSet connectPieceTypes = ~NO_PIECE_SET;
bool connectHorizontal = true;
bool connectVertical = true;
bool connectDiagonal = true;
Bitboard connectRegion1[COLOR_NB] = {};
Bitboard connectRegion2[COLOR_NB] = {};
int connectNxN = 0;
+ int collinearN = 0;
Value connectValue = VALUE_MATE;
MaterialCounting materialCounting = NO_MATERIAL_COUNTING;
bool adjudicateFullBoard = false;
# flagPieceSafe: the flag piece must be safe to win [bool] (default: false)
# checkCounting: enable check count win rule (check count is communicated via FEN, see 3check) [bool] (default: false)
# connectN: number of aligned pieces for win [int] (default: 0)
+# connectPieceTypes: pieces evaluated for connection rule [PieceSet] (default: *)
# connectVertical: connectN looks at Vertical rows [bool] (default: true)
# connectHorizontal: connectN looks at Horizontal rows [bool] (default: true)
# connectDiagonal: connectN looks at Diagonal rows [bool] (default: true)
# connectRegion1Black: "
# connectRegion2Black: "
# connectNxN: connect a tight NxN square for win [int] (default: 0)
+# collinearN: arrange N pieces collinearly (other squares can be between pieces) [int] (default: 0)
# connectValue: result in case of connect [Value] (default: win)
# materialCounting: enable material counting rules [MaterialCounting] (default: none)
# adjudicateFullBoard: apply material counting immediately when board is full [bool] (default: false)
#https://ludii.games/details.php?keyword=Djara-Badakh
#https://ludii.games/details.php?keyword=Tuk%20Tak
customPiece1 = p:mKmNmAmD
-#moves anywhere on the board, KNAD is an list of all possible moves on a 3x3
+#moves anywhere on the board, KNAD is a list of all possible moves on a 3x3
startFen = 3/3/3[PPPppp] w - - 0 1
mustDrop = true
nMoveRule = 0
#http://gamescrafters.berkeley.edu/games.php?game=connect4
[cfour-misere:cfour]
connectValue = loss
+
+#https://www.ludii.games/details.php?keyword=Three%20Musketeers
+[three-musketeers]
+pieceToCharTable = P......M..............p......m..............
+startFen = ppppM/ppppp/ppMpp/ppppp/Mpppp
+maxRank = 5
+maxFile = 5
+collinearN = 3
+connectDiagonal = false
+customPiece1 = m:cW
+customPiece2 = p:mW
+connectValue = loss
+stalemateValue = win
+connectPieceTypes = m