我正在做一个个人项目,在这一点上我需要验证FEN职位,我从一些基础检查开始,例如检查是否有国王,并确保没有多余的行或列,以及那种东西。
但是,我应该做哪些其他检查以完全确保FEN合法?
我正在做一个个人项目,在这一点上我需要验证FEN职位,我从一些基础检查开始,例如检查是否有国王,并确保没有多余的行或列,以及那种东西。
但是,我应该做哪些其他检查以完全确保FEN合法?
Answers:
这是一个井井有条的清单,可以验证99.99%+的普通职位:
板:
国王:
检查:
典当:
x3
或x6
等级上,并且它前面必须有一个棋子(使用正确的颜色),而无用的正方形和后面的那个是空的)extra_pieces = Math.max(0, num_queens-1) + Math.max(0, num_rooks-2)...
,然后extra_pieces <= (8-num_pawns)
),也应该对主教进行特殊计算。如果您有两个(或更多)同一个正方形的主教,则只能通过典当促销来创建这些主教,并且应包括将此信息以某种方式添加到上面的公式中B to G 2=1, 3=2, 4=4, 5=6, 6=9 ___ A and H 2=1, 3=3, 4=6, 5=10, 6=15
,例如,如果您在A或H中看到5个棋子,则其他玩家必须从他的15个可捕获棋子中至少丢失10个棋子卡斯特:
主教:
extra_pieces
可以确定是否可能发生这种情况)非跳线:
半/全动时钟:
HalfMoves <= ((FullMoves-1)*2)+(if BlackToMove 1 else 0)
,则+1或+0取决于移动的一侧x >= 0
和FullMovesx >= 1
其他:
注意:因为“不超过8个棋子” + “防止额外提升的棋子” + “恰好一个国王”的分数已经被覆盖,所以不需要进行“玩家的棋子不超过16件”的检查
注意2:这些规则旨在验证由正常国际象棋的起始位置引起的位置,某些规则将使Chess960中的某些位置无效(从N°518开始的情况除外),并且会生成拼图,因此请避免使用它们来获得功能验证器。
a
文件。
\s*([rnbqkpRNBQKP1-8]+\/){7}([rnbqkpRNBQKP1-8]+)\s[bw-]\s(([a-hkqA-HKQ]{1,4})|(-))\s(([a-h][36])|(-))\s\d+\s\d+\s*
这是一个用于确保FEN字符串实际上有效的正则表达式。它不会对合法/非法职位进行任何测试,但这是一个很好的起点。
-
),我认为半/全时钟有时是可选的。另外,我不了解a-h
有关轮转能力的部分,我将其重写为/^\s*([rnbqkpRNBQKP1-8]+\/){7}([rnbqkpRNBQKP1-8]+)\s[bw]\s(-|K?Q?k?q?)\s(-|[a-h][36])/
([rnbqkRNBQK1-8]+\/)([rnbqkpRNBQKP1-8]+\/){6}([rnbqkRNBQK1-8]+) ....
(0|[1-9][0-9]*)\s([1-9][0-9]*)
因为移动不能有前导零并且全动不能是0或以0开始(代码信用)
对于其他功能,Stockfish引擎中有一个简单的函数,可验证FEN字符串。
bool Position::is_valid_fen(const std::string &fen) {
std::istringstream iss(fen);
std::string board, side, castleRights, ep;
if (!iss) return false;
iss >> board;
if (!iss) return false;
iss >> side;
if (!iss) {
castleRights = "-";
ep = "-";
} else {
iss >> castleRights;
if (iss)
iss >> ep;
else
ep = "-";
}
// Let's check that all components of the supposed FEN are OK.
if (side != "w" && side != "b") return false;
if (castleRights != "-" && castleRights != "K" && castleRights != "Kk"
&& castleRights != "Kkq" && castleRights != "Kq" && castleRights !="KQ"
&& castleRights != "KQk" && castleRights != "KQq" && castleRights != "KQkq"
&& castleRights != "k" && castleRights != "q" && castleRights != "kq"
&& castleRights != "Q" && castleRights != "Qk" && castleRights != "Qq"
&& castleRights != "Qkq")
return false;
if (ep != "-") {
if (ep.length() != 2) return false;
if (!(ep[0] >= 'a' && ep[0] <= 'h')) return false;
if (!((side == "w" && ep[1] == '6') || (side == "b" && ep[1] == '3')))
return false;
}
// The tricky part: The board.
// Seven slashes?
if (std::count(board.begin(), board.end(), '/') != 7) return false;
// Only legal characters?
for (int i = 0; i < board.length(); i++)
if (!(board[i] == '/' || (board[i] >= '1' && board[i] <= '8')
|| piece_type_is_ok(piece_type_from_char(board[i]))))
return false;
// Exactly one king per side?
if (std::count(board.begin(), board.end(), 'K') != 1) return false;
if (std::count(board.begin(), board.end(), 'k') != 1) return false;
// Other piece counts reasonable?
size_t wp = std::count(board.begin(), board.end(), 'P'),
bp = std::count(board.begin(), board.end(), 'p'),
wn = std::count(board.begin(), board.end(), 'N'),
bn = std::count(board.begin(), board.end(), 'n'),
wb = std::count(board.begin(), board.end(), 'B'),
bb = std::count(board.begin(), board.end(), 'b'),
wr = std::count(board.begin(), board.end(), 'R'),
br = std::count(board.begin(), board.end(), 'r'),
wq = std::count(board.begin(), board.end(), 'Q'),
bq = std::count(board.begin(), board.end(), 'q');
if (wp > 8 || bp > 8 || wn > 10 || bn > 10 || wb > 10 || bb > 10
|| wr > 10 || br > 10 || wq > 9 || bq > 10
|| wp + wn + wb + wr + wq > 15 || bp + bn + bb + br + bq > 15)
return false;
// OK, looks close enough to a legal position. Let's try to parse
// the FEN and see!
Position p;
p.from_fen(board + " " + side + " " + castleRights + " " + ep);
return p.is_ok(true);
}
position.is_okay()
。此处的代码仅进行了一些基本检查,以确保其格式正确,并且值得进行真正的验证(即,显然不是非法的)。
这是一个简单的回溯算法,只要您具有可以检查每个董事会状态(也称为头寸)的反向合法移动的功能:
function is_legal_state(state,move)
//Terminate if a starting state was found. This immediately implies there
//was a legal game that generated this state, in fact the backtracking
//can tell you precisely such a game
if (state in starting board state)
return true
//Apply some move to get to a new state, state is a persistent object
apply_reverse_move(state,move)
//Generate all legal "reverse" moves, that is, moves that could have
//been performed to get to the current state from another position,
//provided the previous position was valid. You do not have to check the
//validness of the previous state, you just have to make sure the
//transitioning move was valid
legalmoves = enumerate_all_reverse_moves( state )
for local_move in legalmoves:
return is_legal_state(state,local_move)
//Reverse the move that was previously applied so backtracking can
//work properly
reverse_reverse_move(state,move)
return false