parse_attribute("nFoldValue", v->nFoldValue);
parse_attribute("nFoldValueAbsolute", v->nFoldValueAbsolute);
parse_attribute("perpetualCheckIllegal", v->perpetualCheckIllegal);
+ parse_attribute("moveRepetitionIllegal", v->moveRepetitionIllegal);
parse_attribute("stalemateValue", v->stalemateValue);
parse_attribute("stalematePieceCount", v->stalematePieceCount);
parse_attribute("checkmateValue", v->checkmateValue);
std::memcpy(static_cast<void*>(&newSt), static_cast<void*>(st), offsetof(StateInfo, key));
newSt.previous = st;
st = &newSt;
+ st->move = m;
// Increment ply counters. In particular, rule50 will be reset to zero later on
// in case of a capture or a pawn move.
int cnt = 0;
bool perpetualThem = st->checkersBB && stp->checkersBB;
bool perpetualUs = st->previous->checkersBB && stp->previous->checkersBB;
+ int moveRepetition = var->moveRepetitionIllegal
+ && type_of(st->move) == NORMAL
+ && (board_bb(~side_to_move(), type_of(piece_on(to_sq(st->move)))) & board_bb(side_to_move(), KING))
+ ? (stp->move == reverse_move(st->move) ? 2 : is_pass(stp->move) ? 1 : 0) : 0;
for (int i = 4; i <= end; i += 2)
{
+ // Janggi repetition rule
+ if (moveRepetition > 0)
+ {
+ if (moveRepetition < 4)
+ {
+ if (stp->previous->previous->move == reverse_move((moveRepetition == 1 ? st : stp)->move))
+ moveRepetition++;
+ else
+ moveRepetition = 0;
+ }
+ else
+ {
+ assert(moveRepetition == 4);
+ if (!stp->previous->previous->capturedPiece && from_sq(stp->move) == to_sq(stp->previous->previous->move))
+ {
+ result = VALUE_MATE;
+ return true;
+ }
+ else
+ moveRepetition = 0;
+ }
+ }
stp = stp->previous->previous;
perpetualThem &= bool(stp->checkersBB);
// Return a draw score if a position repeats once earlier but strictly
// after the root, or repeats twice before or at the root.
if ( stp->key == st->key
- && ++cnt + 1 == (ply > i ? 2 : n_fold_rule()))
+ && ++cnt + 1 == (ply > i && !var->moveRepetitionIllegal ? 2 : n_fold_rule()))
{
result = convert_mate_value( var->perpetualCheckIllegal && perpetualThem ? VALUE_MATE
: var->perpetualCheckIllegal && perpetualUs ? -VALUE_MATE
int end = captures_to_hand() ? st->pliesFromNull : std::min(st->rule50, st->pliesFromNull);
- if (end < 3 || var->nFoldValue != VALUE_DRAW || var->perpetualCheckIllegal || var->materialCounting)
+ if (end < 3 || var->nFoldValue != VALUE_DRAW || var->perpetualCheckIllegal || var->materialCounting || var->moveRepetitionIllegal)
return false;
Key originalKey = st->key;
Variant* v = janggi_variant();
v->bikjangRule = false;
v->materialCounting = JANGGI_MATERIAL;
- v->nFoldValue = -VALUE_MATE;
+ v->moveRepetitionIllegal = true;
+ v->nFoldRule = 4; // avoid nFold being triggered before move repetition
return v;
}
// Casual rules of Janggi, where bikjang and material counting are not considered
Value nFoldValue = VALUE_DRAW;
bool nFoldValueAbsolute = false;
bool perpetualCheckIllegal = false;
+ bool moveRepetitionIllegal = false;
Value stalemateValue = VALUE_DRAW;
bool stalematePieceCount = false; // multiply stalemate value by sign(count(~stm) - count(stm))
Value checkmateValue = -VALUE_MATE;
# nFoldValue: result in case of 3/n-fold repetition [Value] (default: draw)
# nFoldValueAbsolute: result in case of 3/n-fold repetition is from white's point of view [bool] (default: false)
# perpetualCheckIllegal: prohibit perpetual checks [bool] (default: false)
+# moveRepetitionIllegal: prohibit moving back and forth with the same piece nFoldRule-1 times [bool] (default: false)
# stalemateValue: result in case of stalemate [Value] (default: draw)
# stalematePieceCount: count material in case of stalemate [bool] (default: false)
# checkmateValue: result in case of checkmate [Value] (default: loss)