Chess: Verify position history in debug mode
This commit is contained in:
parent
f843797f81
commit
fbd55700e0
161
src/chess.lua
161
src/chess.lua
@ -140,14 +140,13 @@ local function send_message_2(playerName1, playerName2, message, botColor, isDeb
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local letters = {'a','b','c','d','e','f','g','h'}
|
local notation_letters = {'a','b','c','d','e','f','g','h'}
|
||||||
|
|
||||||
local function index_to_notation(idx)
|
local function index_to_notation(idx)
|
||||||
local x, y = index_to_xy(idx)
|
local x, y = index_to_xy(idx)
|
||||||
if not x or not y then
|
if not x or not y then
|
||||||
return "??"
|
return "??"
|
||||||
end
|
end
|
||||||
local xstr = letters[x+1] or "?"
|
local xstr = notation_letters[x+1] or "?"
|
||||||
local ystr = tostring(9 - (y+1)) or "?"
|
local ystr = tostring(9 - (y+1)) or "?"
|
||||||
return xstr .. ystr
|
return xstr .. ystr
|
||||||
end
|
end
|
||||||
@ -161,7 +160,6 @@ local function board_to_table(inv)
|
|||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local piece_values = {
|
local piece_values = {
|
||||||
pawn = 10,
|
pawn = 10,
|
||||||
knight = 30,
|
knight = 30,
|
||||||
@ -1165,6 +1163,63 @@ local function add_special_to_moves_list(meta, special)
|
|||||||
add_move_to_moves_list(meta, "", "", "", "", special)
|
add_move_to_moves_list(meta, "", "", "", "", special)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- abbreviation for each piece for the string
|
||||||
|
-- representation of the board (like in FEN)
|
||||||
|
local piece_letters = {
|
||||||
|
white = {
|
||||||
|
pawn = "P",
|
||||||
|
knight = "N",
|
||||||
|
bishop = "B",
|
||||||
|
rook = "R",
|
||||||
|
queen = "Q",
|
||||||
|
king = "K",
|
||||||
|
},
|
||||||
|
black = {
|
||||||
|
pawn = "p",
|
||||||
|
knight = "n",
|
||||||
|
bishop = "b",
|
||||||
|
rook = "r",
|
||||||
|
queen = "q",
|
||||||
|
king = "k",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local function piece_to_letter(piece)
|
||||||
|
if piece == "" then
|
||||||
|
return "."
|
||||||
|
elseif piece:find("white") then
|
||||||
|
for k,v in pairs(piece_letters.white) do
|
||||||
|
if piece:find(k) then
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif piece:find("black") then
|
||||||
|
for k,v in pairs(piece_letters.black) do
|
||||||
|
if piece:find(k) then
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function letter_to_piece(letter)
|
||||||
|
if letter == "." then
|
||||||
|
return ""
|
||||||
|
else
|
||||||
|
for k,v in pairs(piece_letters.white) do
|
||||||
|
if v == letter then
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for k,v in pairs(piece_letters.black) do
|
||||||
|
if v == letter then
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
-- Returns a list of all positions so far, for the purposes
|
-- Returns a list of all positions so far, for the purposes
|
||||||
-- of determining position equality under the "same position
|
-- of determining position equality under the "same position
|
||||||
-- repeated X times" draw rule.
|
-- repeated X times" draw rule.
|
||||||
@ -1199,37 +1254,7 @@ local function get_positions_history(meta)
|
|||||||
for b=1, #board do
|
for b=1, #board do
|
||||||
local piece = board[b]
|
local piece = board[b]
|
||||||
local append
|
local append
|
||||||
if piece == "" then
|
str = str .. piece_to_letter(piece)
|
||||||
str = str .. "."
|
|
||||||
elseif piece:find("white") then
|
|
||||||
if piece:find("pawn") then
|
|
||||||
str = str .. "P"
|
|
||||||
elseif piece:find("bishop") then
|
|
||||||
str = str .. "B"
|
|
||||||
elseif piece:find("knight") then
|
|
||||||
str = str .. "N"
|
|
||||||
elseif piece:find("rook") then
|
|
||||||
str = str .. "R"
|
|
||||||
elseif piece:find("queen") then
|
|
||||||
str = str .. "Q"
|
|
||||||
elseif piece:find("king") then
|
|
||||||
str = str .. "K"
|
|
||||||
end
|
|
||||||
elseif piece:find("black") then
|
|
||||||
if piece:find("pawn") then
|
|
||||||
str = str .. "p"
|
|
||||||
elseif piece:find("bishop") then
|
|
||||||
str = str .. "b"
|
|
||||||
elseif piece:find("knight") then
|
|
||||||
str = str .. "n"
|
|
||||||
elseif piece:find("rook") then
|
|
||||||
str = str .. "r"
|
|
||||||
elseif piece:find("queen") then
|
|
||||||
str = str .. "q"
|
|
||||||
elseif piece:find("king") then
|
|
||||||
str = str .. "k"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
return str
|
return str
|
||||||
end
|
end
|
||||||
@ -1839,9 +1864,12 @@ local function update_game_result(meta)
|
|||||||
minetest.log("action", "[xdecor] Chess: A game between "..playerWhite.." and "..playerBlack.." ended in a draw via the 75-move rule")
|
minetest.log("action", "[xdecor] Chess: A game between "..playerWhite.." and "..playerBlack.." ended in a draw via the 75-move rule")
|
||||||
end
|
end
|
||||||
|
|
||||||
local repetitionDraw = false
|
-- Draw if same position appeared 5 times
|
||||||
|
-- First, generate the position history
|
||||||
|
local forceRepetitionDraw = false
|
||||||
local positions = get_positions_history(meta)
|
local positions = get_positions_history(meta)
|
||||||
local positions_counter = {}
|
local positions_counter = {}
|
||||||
|
-- Count how often each position occurred
|
||||||
for p = 1, #positions do
|
for p = 1, #positions do
|
||||||
local position = positions[p]
|
local position = positions[p]
|
||||||
if positions_counter[position] == nil then
|
if positions_counter[position] == nil then
|
||||||
@ -1850,21 +1878,60 @@ local function update_game_result(meta)
|
|||||||
positions_counter[position] = positions_counter[position] + 1
|
positions_counter[position] = positions_counter[position] + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
if CHESS_DEBUG and p == #positions then
|
|
||||||
local msg = "Current position: \"" .. position .. "\""
|
|
||||||
if positions_counter[position] > 1 then
|
|
||||||
msg = msg .. " (occurred "..positions_counter[position].." times)"
|
|
||||||
end
|
|
||||||
--send_message_2(playerWhite, playerBlack, msg, botColor)
|
|
||||||
end
|
|
||||||
|
|
||||||
if positions_counter[position] == 5 then
|
if positions_counter[position] == 5 then
|
||||||
repetitionDraw = true
|
forceRepetitionDraw = true
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if CHESS_DEBUG then
|
||||||
|
-- Show message if last position occurred at least 2 times
|
||||||
|
local last_position = positions[#positions]
|
||||||
|
local msg = "Current position: \"" .. last_position .. "\""
|
||||||
|
if positions_counter[last_position] >= 2 then
|
||||||
|
msg = msg .. " (occurred "..positions_counter[last_position].." times)"
|
||||||
|
end
|
||||||
|
send_message_2(playerWhite, playerBlack, msg, botColor)
|
||||||
|
|
||||||
if repetitionDraw then
|
-- Compare the last position with the actual chessboard
|
||||||
|
-- to automatically test if the position history is still valid
|
||||||
|
local pos_split = last_position:split(" ")
|
||||||
|
local p_board = pos_split[1]
|
||||||
|
local p_player = pos_split[2]
|
||||||
|
local p_castling = pos_split[3]
|
||||||
|
local p_en_passant = pos_split[4]
|
||||||
|
local errors = 0
|
||||||
|
for b=1, #board_t do
|
||||||
|
local piece = board_t[b]
|
||||||
|
local letter_real = piece_to_letter(piece)
|
||||||
|
local letter_pos = string.sub(p_board, b, b)
|
||||||
|
if letter_real ~= letter_pos then
|
||||||
|
minetest.log("error", "[xdecor] Chess: Position history inconsistency on board index "..b..": '"..letter_pos.."' seen but '"..letter_real.."' expected")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Compare current player
|
||||||
|
if (lastMove == "black" or lastMove == "") and p_player ~= "w" then
|
||||||
|
minetest.log("error", "[xdecor] Chess: Position history inconsistency: Wrong player! '"..p_player.."' seen but 'w' expected")
|
||||||
|
elseif (lastMove == "white") and p_player ~= "b" then
|
||||||
|
minetest.log("error", "[xdecor] Chess: Position history inconsistency: Wrong player! '"..p_player.."' seen but 'b' expected")
|
||||||
|
end
|
||||||
|
-- Compare castling rights
|
||||||
|
local d_castling = castling_to_string(
|
||||||
|
meta:get_int("castlingWhiteR") == 1,
|
||||||
|
meta:get_int("castlingWhiteL") == 1,
|
||||||
|
meta:get_int("castlingBlackR") == 1,
|
||||||
|
meta:get_int("castlingBlackL") == 1)
|
||||||
|
if d_castling ~= p_castling then
|
||||||
|
minetest.log("error", "[xdecor] Chess: Position history inconsistency: Castling rights mismatch! '"..p_castling.."' seen but '"..d_castling.."' expected")
|
||||||
|
end
|
||||||
|
-- Compare en passant status
|
||||||
|
local double_step = meta:get_int("prevDoublePawnStepTo")
|
||||||
|
local d_en_passant = en_passant_to_string(double_step)
|
||||||
|
if d_en_passant ~= p_en_passant then
|
||||||
|
minetest.log("error", "[xdecor] Chess: Position history inconsistency: En passant status mismatch! '"..p_en_passant.."' seen but '"..d_en_passant.."' expected")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if forceRepetitionDraw then
|
||||||
meta:set_string("gameResult", "draw")
|
meta:set_string("gameResult", "draw")
|
||||||
meta:set_string("gameResultReason", "same_position_5")
|
meta:set_string("gameResultReason", "same_position_5")
|
||||||
add_special_to_moves_list(meta, "draw")
|
add_special_to_moves_list(meta, "draw")
|
||||||
@ -2608,7 +2675,7 @@ local function bot_move(inv, meta)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function bot_promote(inv, meta, pawnIndex)
|
local function bot_promote(inv, meta, pawnIndex)
|
||||||
minetest.after(BOT_DELAY_MOVE, function()
|
minetest.after(BOT_DELAY_PROMOTE, function()
|
||||||
local lastMove = meta:get_string("lastMove")
|
local lastMove = meta:get_string("lastMove")
|
||||||
local color
|
local color
|
||||||
if lastMove == "black" or lastMove == "" then
|
if lastMove == "black" or lastMove == "" then
|
||||||
|
Loading…
Reference in New Issue
Block a user