return OK;
}
+inline Validation check_lichess_check_count(const std::string& checkCountInfo) {
+ if (checkCountInfo.size() != 4)
+ {
+ std::cerr << "Invalid check count '" << checkCountInfo << "'. Expects 4 characters. Actual: " << checkCountInfo.size() << " character(s)." << std::endl;
+ return NOK;
+ }
+ if (!isdigit(checkCountInfo[1]) || checkCountInfo[1] - '0' > 3)
+ {
+ std::cerr << "Invalid check count '" << checkCountInfo << "'. Expects 2nd character to be a digit up to 3." << std::endl;
+ return NOK;
+ }
+ if (!isdigit(checkCountInfo[3]) || checkCountInfo[3] - '0' > 3) {
+ std::cerr << "Invalid check count '" << checkCountInfo << "'. Expects 4th character to be a digit up to 3." << std::endl;
+ return NOK;
+ }
+ return OK;
+}
inline Validation check_digit_field(const std::string& field) {
if (field.size() == 1 && field[0] == '-')
// 5) Part
// check check count
- unsigned int optionalFields = 2 * !skipCastlingAndEp;
- if (fenParts.size() >= 3 + optionalFields && v->checkCounting && fenParts.size() % 2)
+ unsigned int optionalInbetweenFields = 2 * !skipCastlingAndEp;
+ unsigned int optionalTrailingFields = 0;
+ if (fenParts.size() >= 3 + optionalInbetweenFields && v->checkCounting && fenParts.size() % 2)
{
- if (check_check_count(fenParts[2 + optionalFields]) == NOK)
- return FEN_INVALID_CHECK_COUNT;
- optionalFields++;
+ if (check_check_count(fenParts[2 + optionalInbetweenFields]) == NOK)
+ {
+ // allow valid lichess style check as alternative
+ if (fenParts.size() < 5 + optionalInbetweenFields || check_lichess_check_count(fenParts[fenParts.size() - 1]) == NOK)
+ return FEN_INVALID_CHECK_COUNT;
+ else
+ optionalTrailingFields++;
+ }
+ else
+ optionalInbetweenFields++;
}
// 6) Part
// check half move counter
- if (fenParts.size() >= 3 + optionalFields && !check_digit_field(fenParts[fenParts.size()-2]))
+ if (fenParts.size() >= 3 + optionalInbetweenFields && !check_digit_field(fenParts[fenParts.size() - 2 - optionalTrailingFields]))
{
std::cerr << "Invalid half move counter: '" << fenParts[fenParts.size()-2] << "'." << std::endl;
return FEN_INVALID_HALF_MOVE_COUNTER;
// 7) Part
// check move counter
- if (fenParts.size() >= 4 + optionalFields && !check_digit_field(fenParts[fenParts.size()-1]))
+ if (fenParts.size() >= 4 + optionalInbetweenFields && !check_digit_field(fenParts[fenParts.size() - 1 - optionalTrailingFields]))
{
std::cerr << "Invalid move counter: '" << fenParts[fenParts.size()-1] << "'." << std::endl;
return FEN_INVALID_MOVE_COUNTER;
"k7/p7/8/8/8/8/8/K7 w - - 0 1": (True, False), # K vs KP
"k7/q7/8/8/8/8/8/K7 w - - 0 1": (True, False), # K vs KQ
},
+ "crazyhouse": {
+ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR/ w KQkq - 0 1": (False, False), # lichess style startpos
+ },
"3check": {
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 3+3 0 1": (False, False), # startpos
+ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 +0+2": (False, False), # lichess style check count
"k7/n7/8/8/8/8/8/K7 w - - 1+2 0 1": (True, False), # K vs KN
"k7/b7/8/8/8/8/8/K7 w - - 3+1 0 1": (True, False), # K vs KB
},
),
"3check": (
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 3+a 0 1", # invalid check count
+ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 +a+2", # invalid lichess check count
+ "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 +1+4", # invalid lichess check count
),
"horde": (
"rnbqkbnr/pppppppp/8/1PP2PP1/PPPPPPPP/PPPPPPPP/PPPPPPPP/PPPPPPPK w kq - 0 1", # wrong king count