Chess: Simplify checks for king safe moves in bot

This commit is contained in:
Wuzzy 2023-07-19 18:00:07 +02:00
parent 2828e5644a
commit 9fd4bafee7
2 changed files with 25 additions and 54 deletions

View File

@ -884,7 +884,7 @@ end
-- * theoretical_moves: moves table returned by realchess.get_theoretical_moves_for() -- * theoretical_moves: moves table returned by realchess.get_theoretical_moves_for()
-- * board: board table -- * board: board table
-- * player: player color ("white" or "black") -- * player: player color ("white" or "black")
function realchess.get_king_safe_move(theoretical_moves, board, player) function realchess.get_king_safe_moves(theoretical_moves, board, player)
local safe_moves = {} local safe_moves = {}
local safe_moves_count = 0 local safe_moves_count = 0
-- create a virtual board -- create a virtual board
@ -1917,19 +1917,19 @@ local function update_game_result(meta)
king_idx = black_king_idx king_idx = black_king_idx
end end
-- King attacked? This reduces the list of available moves, -- King attacked?
-- so remove these, too and check if there are still any left.
local isKingAttacked = realchess.attacked(checkPlayer, king_idx, board_t) local isKingAttacked = realchess.attacked(checkPlayer, king_idx, board_t)
if isKingAttacked then if isKingAttacked then
meta:set_string(checkPlayer.."Attacked", "true") meta:set_string(checkPlayer.."Attacked", "true")
local _, save_moves = realchess.get_king_safe_move(checkMoves, board_t, checkPlayer) end
-- If not safe moves left, player can't move
if save_moves == 0 then -- If not safe moves left, player can't move
if checkPlayer == "black" then local safe_moves, safe_moves_count = realchess.get_king_safe_moves(checkMoves, board_t, checkPlayer)
blackCanMove = false if safe_moves_count == 0 then
else if checkPlayer == "black" then
whiteCanMove = false blackCanMove = false
end else
whiteCanMove = false
end end
end end

View File

@ -66,9 +66,13 @@ function chessbot.move(inv, meta)
botName = meta:get_string("playerBlack") botName = meta:get_string("playerBlack")
end end
if (lastMove == opponentColor or ((botColor == "white" or botColor == "both") and lastMove == "")) and gameResult == "" then if (lastMove == opponentColor or ((botColor == "white" or botColor == "both") and lastMove == "")) and gameResult == "" then
local moves = realchess.get_theoretical_moves_for(meta, board_t, currentBotColor)
local choice_from, choice_to = best_move(moves) local moves = realchess.get_theoretical_moves_for(meta, board_t, currentBotColor)
local safe_moves, safe_moves_count = realchess.get_king_safe_moves(moves, board_t, currentBotColor)
if safe_moves_count == 0 then
-- No safe move: stalemate or checkmate
end
local choice_from, choice_to = best_move(safe_moves)
if choice_from == nil then if choice_from == nil then
-- No best move: stalemate or checkmate -- No best move: stalemate or checkmate
return return
@ -77,26 +81,6 @@ function chessbot.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 black_king_idx, white_king_idx = realchess.locate_kings(board_t)
local bot_king_idx
if currentBotColor == "black" then
bot_king_idx = black_king_idx
else
bot_king_idx = white_king_idx
end
local botAttacked = realchess.attacked(currentBotColor, bot_king_idx, board_t)
local kingSafe = true
local bestMoveSaveFrom, bestMoveSaveTo
if botAttacked then
kingSafe = false
meta:set_string(currentBotColor.."Attacked", "true")
local safe_moves, save_moves_count = realchess.get_king_safe_move(moves, board_t, currentBotColor)
if save_moves_count >= 1 then
bestMoveSaveFrom, bestMoveSaveTo = best_move(safe_moves)
end
end
minetest.after(BOT_DELAY_MOVE, function() minetest.after(BOT_DELAY_MOVE, function()
local gameResult = meta:get_string("gameResult") local gameResult = meta:get_string("gameResult")
if gameResult ~= "" then if gameResult ~= "" then
@ -109,33 +93,20 @@ function chessbot.move(inv, meta)
local lastMove = meta:get_string("lastMove") local lastMove = meta:get_string("lastMove")
local lastMoveTime = meta:get_int("lastMoveTime") local lastMoveTime = meta:get_int("lastMoveTime")
if lastMoveTime > 0 or lastMove == "" then if lastMoveTime > 0 or lastMove == "" then
-- Set the bot name if not set already
if currentBotColor == "black" and meta:get_string("playerBlack") == "" then if currentBotColor == "black" and meta:get_string("playerBlack") == "" then
meta:set_string("playerBlack", botName) meta:set_string("playerBlack", botName)
elseif currentBotColor == "white" and meta:get_string("playerWhite") == "" then elseif currentBotColor == "white" and meta:get_string("playerWhite") == "" then
meta:set_string("playerWhite", botName) meta:set_string("playerWhite", botName)
end end
local moveOK = false
if not kingSafe then -- Make a move
-- Make a move to put the king out of check local moveOK = realchess.move(meta, "board", choice_from, "board", choice_to, botName)
if bestMoveSaveTo ~= nil then if not moveOK then
moveOK = realchess.move(meta, "board", bestMoveSaveFrom, "board", bestMoveSaveTo, botName) minetest.log("error", "[xdecor] Chess: Bot tried to make an invalid move from "..
if not moveOK then realchess.index_to_notation(choice_from).." to "..realchess.index_to_notation(choice_to))
minetest.log("error", "[xdecor] Chess: Bot tried to make an invalid move (to protect the king) from "..
realchess.index_to_notation(bestMoveSaveFrom).." to "..realchess.index_to_notation(bestMoveSaveTo))
end
else
-- No safe move left: checkmate or stalemate
return
end
else
-- Make a regular move
moveOK = realchess.move(meta, "board", choice_from, "board", choice_to, botName)
if not moveOK then
minetest.log("error", "[xdecor] Chess: Bot tried to make an invalid move from "..
realchess.index_to_notation(choice_from).." to "..realchess.index_to_notation(choice_to))
end
end end
-- Bot resigns if it made an incorrect move -- Bot resigns if it tried to make an invalid move
if not moveOK then if not moveOK then
realchess.resign(meta, currentBotColor) realchess.resign(meta, currentBotColor)
end end