I tried to solve the following problem. For a program playing Fischer random chess, how to read the third field of a FEN string, without knowing what the notation style will be ("KQkq" or "HAha").
Here is my solution. I would be glad to know what you think about the method I found. I feel that it is too complicated, but I didn't find something simpler.
The function returns for each color and each side the position of the king and of the rook, or nil value if the castling isn't available.
Code: Select all
-- Lua function for an engine playing Fischer random chess.
-- Extracts castling data from a FEN string, accepting both notation style.
function EncodeCastling(
AFen3,
ABoard -- The chessboard is needed as second parameter
)
function GetRookFile(
AColor, -- Piece color
APattern, -- Regular expression for character detection
AFrom, -- Where to start searching for the rook
ATo, -- Where to stop
AStep, -- In which direction to search
AKey -- K, Q, k, q
)
local LResult = 0
for LMatch in string.gmatch(AFen3, APattern) do
local LRook = AColor and 'r' or 'R'
local LFile = AColor and 'a' or 'A'
local LRank = AColor and 8 or 1
for x = AFrom, ATo, AStep do
if LResult == 0 then
if (ABoard[x][LRank] == LRook) and (
(LMatch == string.char(string.byte(LFile) + x - 1)) -- B-H, A-G, b-h, a-g
or (LMatch == AKey) -- K, Q, k, q
) then
LResult = x
break
end
end
end
end
return LResult
end
local K, Q, k, q, X = nil, nil, nil, nil, nil
local IsWhiteCastlingAvailable = string.match(AFen3, "[ABCDEFGHKQ]")
if IsWhiteCastlingAvailable then
for x = 1, 8 do
if ABoard[x][1] == 'K' then
X = x
break
end
end
end
local IsBlackCastlingAvailable = string.match(AFen3, "[abcdefghkq]")
if IsBlackCastlingAvailable and (X == nil) then
for x = 1, 8 do
if ABoard[x][8] == 'k' then
X = x
break
end
end
end
if IsWhiteCastlingAvailable then
K = GetRookFile(false, "[BCDEFGHK]", 8, X, -1, "K")
Q = GetRookFile(false, "[ABCDEFGQ]", 1, X, 1, "Q")
end
if IsBlackCastlingAvailable then
k = GetRookFile(true, "[bcdefghk]", 8, X, -1, "k")
q = GetRookFile(true, "[abcdefgq]", 1, X, 1, "q")
end
return {K = K, Q = Q, k = k, q = q, X = X}
end
-- demo
require('chess')
function Test(AFen)
local LPos = EncodePosition(AFen)
local LCastling = EncodeCastling(LPos.castlingAvailability, LPos.piecePlacement)
print("white k. side", LCastling.K) -- Rook file or nil when no castling is available
print("white q. side", LCastling.Q) -- Idem
print("black k. side", LCastling.k) -- Idem
print("black q. side", LCastling.q) -- Idem
print("king", LCastling.X) -- King file or nil when no castling is available
end
local LSample = {
"rknbbqnr/pppppppp/8/8/8/8/PPPPPPPP/RKNBBQNR w HAha - 0 1",
"nrbkqbnr/pppppppp/8/8/8/8/PPPPPPPP/NRBKQBNR w KQkq - 0 1",
"qrbknbrn/pppppppp/8/8/8/8/PPPPPPPP/QRBKNBRN w GBgb - 0 1",
"nrbkqrnb/pppppppp/8/8/8/8/PPPPPPPP/NRBKQRNB w FBfb - 0 1",
"qnrbbknr/pppppppp/8/8/8/8/PPPPPPPP/QNRBBKNR w HChc - 0 1",
"rnb1k1nr/p1pp1ppp/4p3/1p6/1P6/P1N1PN2/2P2P1P/R1BQKB1q b Qkq - 1 10",
"rnb1k2r/pppp1pp1/4p2p/8/8/2bPPN2/P2B1PqP/R2QKR2 b Qkq - 1 13"
}
for i = 1, #LSample do
Test(LSample[i])
end
Code: Select all
white k. side 8
white q. side 1
black k. side 8
black q. side 1
king 2
white k. side 8
white q. side 2
black k. side 8
black q. side 2
king 4
white k. side 7
white q. side 2
black k. side 7
black q. side 2
king 4
white k. side 6
white q. side 2
black k. side 6
black q. side 2
king 4
white k. side 8
white q. side 3
black k. side 8
black q. side 3
king 6
white k. side 0
white q. side 1
black k. side 8
black q. side 1
king 5
white k. side 0
white q. side 1
black k. side 8
black q. side 1
king 5
Thank you.