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

Fixes for PR #762 (Musketeer variant) #772

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
bddaaf2
added custom pieces and commit gates
alperatalayn Feb 12, 2024
5dd721b
fixed gating and initializing
alperatalayn Feb 20, 2024
06a794f
cleaned up debug logs and comments
alperatalayn Mar 5, 2024
d6ba9bd
Merge branch 'master' into musketeer-variant
alperatalayn Mar 5, 2024
e93e91f
Merge pull request #1 from alperatalayn/musketeer-variant
cross-of-north Mar 28, 2024
9d1d1a4
typos fixed
cross-of-north Mar 28, 2024
bbb0bf1
uninitialized removedGatingType fix
cross-of-north Mar 29, 2024
0ba2501
Position regression bugfixes
cross-of-north Mar 29, 2024
fa7b1da
musketeer board geometry override
cross-of-north Mar 29, 2024
27f2c23
more musketeer board geometry fixes
cross-of-north Mar 29, 2024
6e98eec
formatting
cross-of-north Mar 29, 2024
c434d42
fixed Leopard betza
cross-of-north Mar 30, 2024
74c4693
musketeers / expanding board size when setting up xboard
cross-of-north Mar 30, 2024
a3ac488
musketeer initial position
cross-of-north Mar 31, 2024
8f117dd
musketeer position processing fixes
cross-of-north Apr 1, 2024
26bcf6e
musketeer xboard commit gate suffix processing
cross-of-north Apr 1, 2024
44b00de
musketeer validation fix
cross-of-north Apr 1, 2024
065c1b5
musketeer highlight fix for winboard
cross-of-north Apr 1, 2024
33fec65
musketeer piece codes made standard, processing of non-committed musk…
cross-of-north Apr 4, 2024
a7a51b0
adequate musketeer castling support
cross-of-north Apr 4, 2024
f484cfd
musketeer xboard castling fixes
cross-of-north Apr 13, 2024
39eff95
Merge branch 'upstream_master' into musketeer_variant
cross-of-north Apr 25, 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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ The games currently supported besides chess are listed below. Fairy-Stockfish ca
- [Crazyhouse](https://en.wikipedia.org/wiki/Crazyhouse), [Loop](https://en.wikipedia.org/wiki/Crazyhouse#Variations), [Chessgi](https://en.wikipedia.org/wiki/Crazyhouse#Variations), [Pocket Knight](http://www.chessvariants.com/other.dir/pocket.html), Capablanca-Crazyhouse
- [Bughouse](https://en.wikipedia.org/wiki/Bughouse_chess), [Koedem](http://schachclub-oetigheim.de/wp-content/uploads/2016/04/Koedem-rules.pdf)
- [Seirawan](https://en.wikipedia.org/wiki/Seirawan_chess), Seirawan-Crazyhouse, [Dragon Chess](https://www.edami.com/dragonchess/)
- [Musketeer](https://www.musketeerchess.net)
- [Amazon](https://www.chessvariants.com/diffmove.dir/amazone.html), [Chigorin](https://www.chessvariants.com/diffsetup.dir/chigorin.html), [Almost chess](https://en.wikipedia.org/wiki/Almost_Chess)
- [Hoppel-Poppel](http://www.chessvariants.com/diffmove.dir/hoppel-poppel.html), New Zealand
- [Antichess](https://lichess.org/variant/antichess), [Giveaway](http://www.chessvariants.com/diffobjective.dir/giveaway.old.html), [Suicide](https://www.freechess.org/Help/HelpFiles/suicide_chess.html), [Losers](https://www.chessclub.com/help/Wild17), [Codrus](http://www.binnewirtz.com/Schlagschach1.htm)
Expand Down
34 changes: 27 additions & 7 deletions src/apiutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -558,14 +558,22 @@ inline std::vector<std::string> get_fen_parts(const std::string& fullFen, char d
inline Validation fill_char_board(CharBoard& board, const std::string& fenBoard, const std::string& validSpecialCharactersFirstField, const Variant* v) {
int rankIdx = 0;
int fileIdx = 0;
bool firstRankSkipped = false;

char prevChar = '?';
for (char c : fenBoard)
{
if (c == ' ' || c == '[')
break;
if (c == '*')
++fileIdx;
if (c == '*') {
if (v->commitGates)
{
// just ignore?
}
else {
++fileIdx;
}
}
else if (isdigit(c))
{
fileIdx += c - '0';
Expand All @@ -575,14 +583,26 @@ inline Validation fill_char_board(CharBoard& board, const std::string& fenBoard,
}
else if (c == '/')
{
++rankIdx;
if (fileIdx != board.get_nb_files())
{
std::cerr << "curRankWidth != nbFiles: " << fileIdx << " != " << board.get_nb_files() << std::endl;
return NOK;
if (v->commitGates && rankIdx == 0 && !firstRankSkipped) {
firstRankSkipped = true;
// ignore starting 'xx******/'
}
else {
++rankIdx;
if (fileIdx != board.get_nb_files())
{
std::cerr << "curRankWidth != nbFiles: " << fileIdx << " != " << board.get_nb_files() << std::endl;
return NOK;
}
}
if (rankIdx == board.get_nb_ranks())
{
if (v->commitGates)
{
rankIdx--; // pretend we didn't see the ending '/xx******'
}
break;
}
fileIdx = 0;
}
else if (!contains(validSpecialCharactersFirstField, c))
Expand Down
3 changes: 2 additions & 1 deletion src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,8 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("wallingRegion", v->wallingRegion[WHITE]);
parse_attribute("wallingRegion", v->wallingRegion[BLACK]);
parse_attribute("wallOrMove", v->wallOrMove);
parse_attribute("seirawanGating", v->seirawanGating);
parse_attribute("seirawanGating", v->seirawanGating);
parse_attribute("commitGates", v->commitGates);
parse_attribute("cambodianMoves", v->cambodianMoves);
parse_attribute("diagonalLines", v->diagonalLines);
parse_attribute("pass", v->pass[WHITE]);
Expand Down
156 changes: 140 additions & 16 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,13 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,
Rank r = max_rank();
Square sq = SQ_A1 + r * NORTH;

int commitFile = 0;
int rank = 0;

// 1. Piece placement
while ((ss >> token) && !isspace(token))
{
if (isdigit(token))
if (isdigit(token) && (!commit_gates() || (rank != 0 && rank != max_rank() + 2)))
{
#ifdef LARGEBOARDS
if (isdigit(ss.peek()))
Expand All @@ -284,7 +287,20 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,

else if (token == '/')
{
sq = SQ_A1 + --r * NORTH;
if(commit_gates())
{
if(rank != 0 && rank <= max_rank()){
sq += 2 * SOUTH + (FILE_MAX - max_file()) * EAST;
}
else if (rank == max_rank() + 1) {
sq = SQ_A1; // dummy to proceed with white musketeer pieces setup
}
++rank;
commitFile = 0;
}
else {
sq = SQ_A1 + --r * NORTH;
}
if (!is_ok(sq))
break;
}
Expand All @@ -297,28 +313,49 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,
else if (!is_ok(sq) || file_of(sq) > max_file() || rank_of(sq) > r)
continue;

// Wall square
else if (token == '*')
{
st->wallSquares |= sq;
byTypeBB[ALL_PIECES] |= sq;
++sq;
if(commit_gates())
{
// musketeer
++commitFile;
}
else {
// Wall square
st->wallSquares |= sq;
byTypeBB[ALL_PIECES] |= sq;
++sq;
}
}

else if ((idx = piece_to_char().find(token)) != string::npos || (idx = piece_to_char_synonyms().find(token)) != string::npos)
{
if (ss.peek() == '~')
ss >> token;
put_piece(Piece(idx), sq, token == '~');
++sq;

if(v->commitGates && (rank == 0 || rank == max_rank() + 2))
{
commit_piece(Piece(idx), File(commitFile));
++commitFile;
}
else{
put_piece(Piece(idx), sq, token == '~');
++sq;
}
}

// Promoted shogi pieces
else if (token == '+' && (idx = piece_to_char().find(ss.peek())) != string::npos && promoted_piece_type(type_of(Piece(idx))))
{
ss >> token;
put_piece(make_piece(color_of(Piece(idx)), promoted_piece_type(type_of(Piece(idx)))), sq, true, Piece(idx));
++sq;
if(v->commitGates && (rank == 0 || rank == max_rank() + 2)){
commit_piece(Piece(idx), File(commitFile));
++commitFile;
}
else {
put_piece(make_piece(color_of(Piece(idx)), promoted_piece_type(type_of(Piece(idx)))), sq, true, Piece(idx));
++sq;
}
}
}
// Pieces in hand
Expand Down Expand Up @@ -377,7 +414,7 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,
}

// Set gates (and skip castling rights)
if (gating())
if (gating() && !commit_gates())
{
st->gatesBB[c] |= rsq;
if (token == 'K' || token == 'Q')
Expand Down Expand Up @@ -604,6 +641,9 @@ void Position::set_state(StateInfo* si) const {
si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO;
si->checkersBB = count<KING>(sideToMove) ? attackers_to(square<KING>(sideToMove), ~sideToMove) : Bitboard(0);
si->move = MOVE_NONE;
si->removedGatingType = NO_PIECE_TYPE;
si->removedCastlingGatingType = NO_PIECE_TYPE;
si->capturedGatingType = NO_PIECE_TYPE;

set_check_info(si);

Expand Down Expand Up @@ -680,6 +720,13 @@ string Position::fen(bool sfen, bool showPromoted, int countStarted, std::string

int emptyCnt;
std::ostringstream ss;
if(commit_gates()){
for(File f = FILE_A; f <= max_file(); ++f){
if(has_committed_piece(BLACK, f)) ss << piece_to_char()[make_piece(BLACK, committedGates[BLACK][f])];
else ss << "*";
}
ss << "/";
}

for (Rank r = max_rank(); r >= RANK_1; --r)
{
Expand Down Expand Up @@ -713,7 +760,13 @@ string Position::fen(bool sfen, bool showPromoted, int countStarted, std::string
if (r > RANK_1)
ss << '/';
}

if(commit_gates()){
ss << "/";
for(File f = FILE_A; f <= max_file(); ++f){
if(has_committed_piece(WHITE, f)) ss << piece_to_char()[make_piece(WHITE, committedGates[WHITE][f])];
else ss << "*";
}
}
// SFEN
if (sfen)
{
Expand All @@ -733,7 +786,7 @@ string Position::fen(bool sfen, bool showPromoted, int countStarted, std::string
}

// pieces in hand
if (!variant()->freeDrops && (piece_drops() || seirawan_gating()))
if (!variant()->freeDrops && (piece_drops() || seirawan_gating()) && !commit_gates())
{
ss << '[';
if (holdings != "-")
Expand All @@ -760,7 +813,7 @@ string Position::fen(bool sfen, bool showPromoted, int countStarted, std::string
if (can_castle(WHITE_OOO))
ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE_OOO))) : 'Q');

if (gating() && gates(WHITE) && (!seirawan_gating() || count_in_hand(WHITE, ALL_PIECES) > 0 || captures_to_hand()))
if (gating() && !commit_gates() && gates(WHITE) && (!seirawan_gating() || count_in_hand(WHITE, ALL_PIECES) > 0 || captures_to_hand()))
for (File f = FILE_A; f <= max_file(); ++f)
if ( (gates(WHITE) & file_bb(f))
// skip gating flags redundant with castling flags
Expand Down Expand Up @@ -788,7 +841,7 @@ string Position::fen(bool sfen, bool showPromoted, int countStarted, std::string
&& !(can_castle(BLACK_OOO) && f == file_of(castling_rook_square(BLACK_OOO))))
ss << char('a' + f);

if (!can_castle(ANY_CASTLING) && !(gating() && (gates(WHITE) | gates(BLACK))))
if (!can_castle(ANY_CASTLING) && !(gating() && !commit_gates() && (gates(WHITE) | gates(BLACK))))
ss << '-';

// Counting limit or ep-square
Expand Down Expand Up @@ -1536,6 +1589,11 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
st = &newSt;
st->move = m;

if (commit_gates()) {
st->removedGatingType = NO_PIECE_TYPE;
st->removedCastlingGatingType = NO_PIECE_TYPE;
st->capturedGatingType = NO_PIECE_TYPE;
}
// Increment ply counters. In particular, rule50 will be reset to zero later on
// in case of a capture or a pawn move.
++gamePly;
Expand Down Expand Up @@ -1945,6 +2003,26 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
st->nonPawnMaterial[us] += PieceValue[MG][gating_piece];
}

// Musketeer gating
if(commit_gates()){
{
Rank r = rank_of(from);
if(r == RANK_1 && has_committed_piece(WHITE, file_of(from))){
st->removedGatingType = drop_committed_piece(WHITE, file_of(from));
} else if(r == max_rank() && has_committed_piece(BLACK, file_of(from))){
st->removedGatingType = drop_committed_piece(BLACK, file_of(from));
}
}
if (captured) {
// remove uncommitted musketeer piece if piece at the front row is captured
Rank r = rank_of(to);
if (r == RANK_1 && color_of(captured) == WHITE){
st->capturedGatingType = uncommit_piece(WHITE, file_of(to));
} else if (r == max_rank() && color_of(captured) == BLACK) {
st->capturedGatingType = uncommit_piece(BLACK, file_of(to));
}
}
}
// Remove gates
if (gating())
{
Expand Down Expand Up @@ -2128,7 +2206,9 @@ void Position::undo_move(Move m) {

assert(type_of(m) == DROP || empty(from) || type_of(m) == CASTLING || is_gating(m)
|| (type_of(m) == PROMOTION && sittuyin_promotion())
|| (is_pass(m) && (pass(us) || var->wallOrMove)));
|| (is_pass(m) && (pass(us) || var->wallOrMove))
|| (commit_gates() && st->removedGatingType > NO_PIECE_TYPE)
);
assert(type_of(st->capturedPiece) != KING);

// Reset wall squares
Expand Down Expand Up @@ -2169,6 +2249,15 @@ void Position::undo_move(Move m) {
st->gatesBB[us] |= gating_square(m);
}

if(commit_gates() && st->removedGatingType > NO_PIECE_TYPE){
commit_piece(piece_on(from), file_of(from));
remove_piece( from );
}
if (commit_gates() && st->capturedPiece && st->capturedGatingType > NO_PIECE_TYPE){
// return musketeer piece fronted by the captured piece
commit_piece(make_piece(color_of(st->capturedPiece), st->capturedGatingType), file_of(to));
}

if (type_of(m) == PROMOTION)
{
assert((promotion_zone(us) & to) || sittuyin_promotion());
Expand Down Expand Up @@ -2259,6 +2348,11 @@ void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Squ
to = make_square(kingSide ? castling_kingside_file() : castling_queenside_file(), castling_rank(us));
rto = to + (kingSide ? WEST : EAST);

if (!Do && commit_gates() && st->removedCastlingGatingType > NO_PIECE_TYPE) {
commit_piece(piece_on(rfrom), file_of(rfrom));
remove_piece(rfrom);
}

Piece castlingKingPiece = piece_on(Do ? from : to);
Piece castlingRookPiece = piece_on(Do ? rfrom : rto);

Expand All @@ -2280,6 +2374,11 @@ void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Squ
board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do it for us
put_piece(castlingKingPiece, Do ? to : from);
put_piece(castlingRookPiece, Do ? rto : rfrom);

if (Do && commit_gates() && has_committed_piece(us, file_of(rfrom))) {
st->removedCastlingGatingType = drop_committed_piece(us, file_of(rfrom));
}

}


Expand Down Expand Up @@ -3280,4 +3379,29 @@ bool Position::pos_is_ok() const {
return true;
}

PieceType Position::committed_piece_type(Move m, bool castlingRook) const {
PieceType result = NO_PIECE_TYPE;
if (commit_gates()) {
Square from = from_sq(m);
Rank r = rank_of(from);
if (castlingRook){
if (type_of(m) == CASTLING){
from = to_sq(m);
} else {
from = SQ_NONE;
}
}
if (from != SQ_NONE){
if (r == RANK_1){
result = committed_piece_type(WHITE, file_of(from));
} else if (r == max_rank()){
result = committed_piece_type(BLACK, file_of(from));
} else{
assert(false);
}
}
}
return result;
}

} // namespace Stockfish
Loading
Loading