Chess: Fix bot failing to move king out of check
This commit is contained in:
parent
063e346e7b
commit
5f113037e3
@ -884,37 +884,51 @@ end
|
|||||||
-- Given a table of theoretical moves and the king of the player is attacked,
|
-- Given a table of theoretical moves and the king of the player is attacked,
|
||||||
-- returns true if the player still has at least one move left,
|
-- returns true if the player still has at least one move left,
|
||||||
-- return false otherwise.
|
-- return false otherwise.
|
||||||
-- 2nd return value ist table of save moves
|
-- 2nd return value is table of save moves
|
||||||
-- * theoretical_moves: moves table returned by get_theoretical_moves_for()
|
-- * theoretical_moves: moves table returned by get_theoretical_moves_for()
|
||||||
-- * board: board table
|
-- * board: board table
|
||||||
-- * player: player color ("white" or "black")
|
-- * player: player color ("white" or "black")
|
||||||
local function has_king_safe_move(theoretical_moves, board, player)
|
local function has_king_safe_move(theoretical_moves, board, player)
|
||||||
local save_moves = {}
|
local safe_moves = {}
|
||||||
local s_board = table.copy(board)
|
-- create a virtual board
|
||||||
|
local v_board = table.copy(board)
|
||||||
|
|
||||||
for from_idx, _ in pairs(theoretical_moves) do
|
for from_idx, _ in pairs(theoretical_moves) do
|
||||||
for to_idx, value in pairs(_) do
|
for to_idx, value in pairs(_) do
|
||||||
from_idx = tonumber(from_idx)
|
from_idx = tonumber(from_idx)
|
||||||
s_board[to_idx] = s_board[from_idx]
|
|
||||||
s_board[from_idx] = ""
|
-- save the old board values before manipulating them
|
||||||
local black_king_idx, white_king_idx = locate_kings(s_board)
|
local bak_to = v_board[to_idx]
|
||||||
|
local bak_from = v_board[from_idx]
|
||||||
|
|
||||||
|
-- move the piece on the virtual board
|
||||||
|
v_board[to_idx] = v_board[from_idx]
|
||||||
|
v_board[from_idx] = ""
|
||||||
|
local black_king_idx, white_king_idx = locate_kings(v_board)
|
||||||
|
if not black_king_idx or not white_king_idx then
|
||||||
|
minetest.log("error", "[xdecor] Chess: Insufficient kings on chessboard!")
|
||||||
|
return false
|
||||||
|
end
|
||||||
local king_idx
|
local king_idx
|
||||||
if player == "black" then
|
if player == "black" then
|
||||||
king_idx = black_king_idx
|
king_idx = black_king_idx
|
||||||
else
|
else
|
||||||
king_idx = white_king_idx
|
king_idx = white_king_idx
|
||||||
end
|
end
|
||||||
if king_idx then
|
local playerAttacked = attacked(player, king_idx, v_board)
|
||||||
local playerAttacked = attacked(player, king_idx, s_board)
|
|
||||||
if not playerAttacked then
|
if not playerAttacked then
|
||||||
save_moves[from_idx] = save_moves[from_idx] or {}
|
safe_moves[from_idx] = safe_moves[from_idx] or {}
|
||||||
save_moves[from_idx][to_idx] = value
|
safe_moves[from_idx][to_idx] = value
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- restore the old state of the virtual board
|
||||||
|
v_board[to_idx] = bak_to
|
||||||
|
v_board[from_idx] = bak_from
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if next(save_moves) then
|
if next(safe_moves) then
|
||||||
return true, save_moves
|
return true, safe_moves
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@ -1711,15 +1725,11 @@ local function update_game_result(meta)
|
|||||||
|
|
||||||
local blackMoves = get_theoretical_moves_for(meta, board_t, "black")
|
local blackMoves = get_theoretical_moves_for(meta, board_t, "black")
|
||||||
local whiteMoves = get_theoretical_moves_for(meta, board_t, "white")
|
local whiteMoves = get_theoretical_moves_for(meta, board_t, "white")
|
||||||
local b = 0
|
if next(blackMoves) then
|
||||||
for k,v in pairs(blackMoves) do
|
|
||||||
blackCanMove = true
|
blackCanMove = true
|
||||||
b = b+1
|
|
||||||
end
|
end
|
||||||
b = 0
|
if next(whiteMoves) then
|
||||||
for k,v in pairs(whiteMoves) do
|
|
||||||
whiteCanMove = true
|
whiteCanMove = true
|
||||||
b = b+1
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- assume lastMove was updated *after* the player moved
|
-- assume lastMove was updated *after* the player moved
|
||||||
@ -1727,18 +1737,19 @@ local function update_game_result(meta)
|
|||||||
|
|
||||||
local black_king_idx, white_king_idx = locate_kings(board_t)
|
local black_king_idx, white_king_idx = locate_kings(board_t)
|
||||||
if not black_king_idx or not white_king_idx then
|
if not black_king_idx or not white_king_idx then
|
||||||
|
minetest.log("error", "[xdecor] Chess: Insufficient kings on chessboard!")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local checkPlayer, king_idx, checkMoves
|
local checkPlayer, king_idx, checkMoves
|
||||||
if lastMove == "white" then
|
if lastMove == "black" or lastMove == "" then
|
||||||
checkPlayer = "black"
|
|
||||||
checkMoves = blackMoves
|
|
||||||
king_idx = black_king_idx
|
|
||||||
else
|
|
||||||
checkPlayer = "white"
|
checkPlayer = "white"
|
||||||
checkMoves = whiteMoves
|
checkMoves = whiteMoves
|
||||||
king_idx = white_king_idx
|
king_idx = white_king_idx
|
||||||
|
else
|
||||||
|
checkPlayer = "black"
|
||||||
|
checkMoves = blackMoves
|
||||||
|
king_idx = black_king_idx
|
||||||
end
|
end
|
||||||
|
|
||||||
-- King attacked? This reduces the list of available moves,
|
-- King attacked? This reduces the list of available moves,
|
||||||
@ -2402,6 +2413,7 @@ function realchess.move(meta, from_list, from_index, to_list, to_index, playerNa
|
|||||||
|
|
||||||
local black_king_idx, white_king_idx = locate_kings(board)
|
local black_king_idx, white_king_idx = locate_kings(board)
|
||||||
if not black_king_idx or not white_king_idx then
|
if not black_king_idx or not white_king_idx then
|
||||||
|
minetest.log("error", "[xdecor] Chess: Insufficient kings on chessboard!")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local blackAttacked = attacked("black", black_king_idx, board)
|
local blackAttacked = attacked("black", black_king_idx, board)
|
||||||
@ -2513,22 +2525,21 @@ local function bot_move(inv, meta)
|
|||||||
local pieceFrom = inv:get_stack("board", choice_from):get_name()
|
local pieceFrom = inv:get_stack("board", choice_from):get_name()
|
||||||
local pieceTo = inv:get_stack("board", choice_to):get_name()
|
local pieceTo = inv:get_stack("board", choice_to):get_name()
|
||||||
|
|
||||||
local board = board_to_table(inv)
|
local black_king_idx, white_king_idx = locate_kings(board_t)
|
||||||
local black_king_idx, white_king_idx = locate_kings(board)
|
|
||||||
local bot_king_idx
|
local bot_king_idx
|
||||||
if currentBotColor == "black" then
|
if currentBotColor == "black" then
|
||||||
bot_king_idx = black_king_idx
|
bot_king_idx = black_king_idx
|
||||||
else
|
else
|
||||||
bot_king_idx = white_king_idx
|
bot_king_idx = white_king_idx
|
||||||
end
|
end
|
||||||
local botAttacked = attacked(currentBotColor, bot_king_idx, board)
|
local botAttacked = attacked(currentBotColor, bot_king_idx, board_t)
|
||||||
local kingSafe = true
|
local kingSafe = true
|
||||||
local bestMoveSaveFrom, bestMoveSaveTo
|
local bestMoveSaveFrom, bestMoveSaveTo
|
||||||
|
|
||||||
if botAttacked then
|
if botAttacked then
|
||||||
kingSafe = false
|
kingSafe = false
|
||||||
meta:set_string(currentBotColor.."Attacked", "true")
|
meta:set_string(currentBotColor.."Attacked", "true")
|
||||||
local is_safe, safe_moves = has_king_safe_move(moves, board, currentBotColor)
|
local is_safe, safe_moves = has_king_safe_move(moves, board_t, currentBotColor)
|
||||||
if is_safe then
|
if is_safe then
|
||||||
bestMoveSaveFrom, bestMoveSaveTo = best_move(safe_moves)
|
bestMoveSaveFrom, bestMoveSaveTo = best_move(safe_moves)
|
||||||
end
|
end
|
||||||
@ -2561,6 +2572,7 @@ local function bot_move(inv, meta)
|
|||||||
index_to_notation(bestMoveSaveFrom).." to "..index_to_notation(bestMoveSaveTo))
|
index_to_notation(bestMoveSaveFrom).." to "..index_to_notation(bestMoveSaveTo))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
-- No safe move left: checkmate or stalemate
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -2846,6 +2858,7 @@ function realchess.update_state(meta, from_index, to_index, thisMove, promoteFro
|
|||||||
|
|
||||||
local black_king_idx, white_king_idx = locate_kings(board)
|
local black_king_idx, white_king_idx = locate_kings(board)
|
||||||
if not black_king_idx or not white_king_idx then
|
if not black_king_idx or not white_king_idx then
|
||||||
|
minetest.log("error", "[xdecor] Chess: Insufficient kings on chessboard!")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local blackAttacked = attacked("black", black_king_idx, board)
|
local blackAttacked = attacked("black", black_king_idx, board)
|
||||||
|
Loading…
Reference in New Issue
Block a user