Partially implement 50-move rule & 'samepos' rule
Using textures from PixelBOX
This commit is contained in:
parent
fa762dded5
commit
7c27bb75ed
199
src/chess.lua
199
src/chess.lua
@ -1102,7 +1102,7 @@ local fs_init = [[
|
||||
]]
|
||||
.."bgcolor[#080808BB;true]"
|
||||
.."background[0,0;16,10.7563;chess_bg.png;true]"
|
||||
.."style_type[button,item_image_button;bgcolor=#8f3000]"
|
||||
.."style_type[button,image_button,item_image_button;bgcolor=#8f3000]"
|
||||
.."label[2.2,0.652;"..minetest.colorize("#404040", FS("Select a game mode")).."]"
|
||||
.."label[2.2,10.21;"..minetest.colorize("#404040", FS("Select a game mode")).."]"
|
||||
.."label["..fs_gamemode_x..",1.8;"..FS("Select a mode:").."]"
|
||||
@ -1119,7 +1119,7 @@ local fs = [[
|
||||
no_prepend[]
|
||||
bgcolor[#080808BB;true]
|
||||
background[0,0;16,10.7563;chess_bg.png;true]
|
||||
style_type[button,item_image_button;bgcolor=#8f3000]
|
||||
style_type[button,image_button,item_image_button;bgcolor=#8f3000]
|
||||
style_type[list;spacing=0.1;size=0.975]
|
||||
listcolors[#00000000;#00000000;#00000000;#30434C;#FFF]
|
||||
list[context;board;0.47,1.155;8,8;]
|
||||
@ -1359,6 +1359,33 @@ local function get_positions_history(meta)
|
||||
return positions_list
|
||||
end
|
||||
|
||||
-- Returns the highest number of positions that are repeated
|
||||
-- in the given positions history list.
|
||||
-- Arguments:
|
||||
-- * positions: positions history list returned by get_position_history()
|
||||
-- * stop_counting_at: stop counting when this many repetitons have been found (optional)
|
||||
local function count_repeated_positions(positions, stop_counting_at)
|
||||
-- Count how often each position occurred
|
||||
local positions_counter = {}
|
||||
local maxRepeatedPositions = 0
|
||||
for p = 1, #positions do
|
||||
local position = positions[p]
|
||||
if positions_counter[position] == nil then
|
||||
positions_counter[position] = 1
|
||||
else
|
||||
positions_counter[position] = positions_counter[position] + 1
|
||||
end
|
||||
|
||||
if positions_counter[position] > maxRepeatedPositions then
|
||||
maxRepeatedPositions = positions_counter[position]
|
||||
end
|
||||
if stop_counting_at and maxRepeatedPositions >= stop_counting_at then
|
||||
break
|
||||
end
|
||||
end
|
||||
return maxRepeatedPositions
|
||||
end
|
||||
|
||||
-- Create the full formspec string for the sequence of moves.
|
||||
-- Uses Figurine Algebraic Notation.
|
||||
local function get_moves_formstring(meta)
|
||||
@ -1673,13 +1700,54 @@ local function update_formspec(meta)
|
||||
end
|
||||
end
|
||||
|
||||
local game_buttons
|
||||
if mode ~= "bot_vs_bot" and (gameResult == "" and (playerWhite ~= "" and playerBlack ~= "")) then
|
||||
game_buttons = "button[13.36,0.26;2,0.8;resign;"..FS("Resign").."]"
|
||||
else
|
||||
game_buttons = "button[13.36,0.26;2,0.8;new;"..FS("New game").."]"
|
||||
-- Resign / Start new game
|
||||
local game_buttons = ""
|
||||
game_buttons = game_buttons .. "button[13.36,0.26;2,0.8;new;"..FS("New game").."]"
|
||||
|
||||
local playerActionsAvailable = mode ~= "bot_vs_bot" and gameResult == ""
|
||||
|
||||
if playerActionsAvailable and (playerWhite ~= "" and playerBlack ~= "") then
|
||||
game_buttons = game_buttons .. "image_button[14.56,9.7;0.8,0.8;chess_resign.png;resign;]" ..
|
||||
"tooltip[resign;"..FS("Resign").."]"
|
||||
end
|
||||
|
||||
if playerActionsAvailable then
|
||||
-- 50-move rule
|
||||
local halfmoveClock = meta:get_int("halfmoveClock")
|
||||
if halfmoveClock == 99 then
|
||||
-- when the 50 moves without capture / pawn move is about to occur
|
||||
game_buttons = game_buttons .. "image_button[13.36,9.7;0.8,0.8;chess_draw_50move_next.png;draw_50_moves;]"..
|
||||
"tooltip[draw_50_moves;"..
|
||||
FS("Invoke the 50-move rule and try to draw the game in your next move.").."\n"..
|
||||
FS("If your next move is the 50th consecutive move of both players where no pawn moved and no piece was captured, the game will be drawn.").."]"
|
||||
elseif halfmoveClock >= 100 then
|
||||
-- when the 50 moves without capture / pawn move have occured occur
|
||||
game_buttons = game_buttons .. "image_button[13.36,9.7;0.8,0.8;chess_draw_50move.png;draw_50_moves;]"..
|
||||
"tooltip[draw_50_moves;"..
|
||||
FS("Invoke the 50-move rule and draw the game.").."\n"..
|
||||
FS("(In the last 50 moves of both players, no pawn moved and no piece was captured.)").."]"
|
||||
end
|
||||
|
||||
-- "same position has occured 3 times" rule
|
||||
-- Count how often each position occurred
|
||||
local positions = get_positions_history(meta)
|
||||
local maxRepeatedPositions = count_repeated_positions(positions, 3)
|
||||
if maxRepeatedPositions == 2 then
|
||||
-- If the same position is about to occur 3 times
|
||||
game_buttons = game_buttons .. "image_button[12.36,9.7;0.8,0.8;chess_draw_repeat3_next.png;draw_repeat_3;]"..
|
||||
"tooltip[draw_repeat_3;"..
|
||||
FS("Invoke the 'same position' rule and try to draw the game in your next move.").."\n"..
|
||||
S("If your next move causes the same position to occur a 3rd time, the game will be drawn.").."]"
|
||||
elseif maxRepeatedPositions >= 3 then
|
||||
-- If the same position has already occured 3 times
|
||||
game_buttons = game_buttons .. "image_button[12.36,9.7;0.8,0.8;chess_draw_repeat3.png;draw_repeat_3;]"..
|
||||
"tooltip[draw_repeat_3;"..
|
||||
FS("Invoke the 'same position' rule and draw the game.").."\n"..
|
||||
S("(The same position has occured 3 times.)").."]"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local debug_formstring = ""
|
||||
if CHESS_DEBUG then
|
||||
-- Write a debug string in the formspec based on FEN
|
||||
@ -1711,7 +1779,7 @@ local function update_formspec(meta)
|
||||
local d_fullmove = tostring(get_current_fullmove(meta) + 1)
|
||||
|
||||
local debug_str = d_turn .. " " .. d_castling .. " " .. d_en_passant .. " " .. d_halfmove_clock .. " " .. d_fullmove
|
||||
debug_formstring = "label[9.9,10.2;DEBUG: "..debug_str.."]"
|
||||
debug_formstring = "label[6.9,10.2;DEBUG: "..debug_str.."]"
|
||||
end
|
||||
|
||||
local formspec = fs ..
|
||||
@ -1854,28 +1922,15 @@ local function update_game_result(meta)
|
||||
-- First, generate the position history
|
||||
local forceRepetitionDraw = false
|
||||
local positions = get_positions_history(meta)
|
||||
local positions_counter = {}
|
||||
-- Count how often each position occurred
|
||||
for p = 1, #positions do
|
||||
local position = positions[p]
|
||||
if positions_counter[position] == nil then
|
||||
positions_counter[position] = 1
|
||||
else
|
||||
positions_counter[position] = positions_counter[position] + 1
|
||||
end
|
||||
|
||||
if positions_counter[position] == 5 then
|
||||
forceRepetitionDraw = true
|
||||
break
|
||||
end
|
||||
-- Then count the repeated positions
|
||||
local maxRepeatedPositions = count_repeated_positions(positions, 5)
|
||||
if maxRepeatedPositions >= 5 then
|
||||
forceRepetitionDraw = true
|
||||
end
|
||||
if CHESS_DEBUG then
|
||||
-- Show message if last position occurred at least 2 times
|
||||
-- Show last position
|
||||
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)
|
||||
|
||||
-- Compare the last position with the actual chessboard
|
||||
@ -2677,6 +2732,98 @@ function realchess.fields(pos, _, fields, sender)
|
||||
return
|
||||
end
|
||||
|
||||
-- Claim or declare draw via the 50-move rule
|
||||
if fields.draw_50_moves then
|
||||
local botColor = meta:get_string("botColor")
|
||||
local lastMove = meta:get_string("lastMove")
|
||||
if playerWhite == "" and playerBlack == "" or lastMove == "" then
|
||||
return
|
||||
end
|
||||
local currentPlayer
|
||||
if lastMove == "black" or lastMove == "" then
|
||||
currentPlayer = "white"
|
||||
else
|
||||
currentPlayer = "black"
|
||||
end
|
||||
|
||||
local claimer, other
|
||||
if (currentPlayer == "white" and playerWhite == playerName) then
|
||||
claimer = playerWhite
|
||||
other = playerBlack
|
||||
elseif (currentPlayer == "black" and playerBlack == playerName) then
|
||||
claimer = playerBlack
|
||||
other = playerWhite
|
||||
else
|
||||
send_message(playerName, S("You can't claim a draw, it's not your turn!"))
|
||||
return
|
||||
end
|
||||
|
||||
local halfmoveClock = meta:get_int("halfmoveClock")
|
||||
if halfmoveClock == 99 then
|
||||
send_message(claimer, S("<not implemented>"), botColor)
|
||||
elseif halfmoveClock >= 100 then
|
||||
meta:set_string("gameResult", "draw")
|
||||
meta:set_string("gameResultReason", "50_move_rule")
|
||||
add_special_to_moves_list(meta, "draw")
|
||||
update_formspec(meta)
|
||||
send_message(claimer, S("You have drawn the game by applying the 50-move rule."), botColor)
|
||||
if claimer ~= other then
|
||||
send_message(other, S("@1 has drawn the game by applying the 50-move rule.", claimer), botColor)
|
||||
end
|
||||
minetest.log("action", "[xdecor] Chess: A game between "..playerWhite.." and "..playerBlack.." ended in a draw because "..claimer.." has applied the 50-move rule")
|
||||
else
|
||||
send_message(claimer, S("Your draw claim is invalid!"), botColor)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- Claim or declare draw via the same position rule (same position occured >= 3 times)
|
||||
if fields.draw_repeat_3 then
|
||||
local botColor = meta:get_string("botColor")
|
||||
local lastMove = meta:get_string("lastMove")
|
||||
if playerWhite == "" and playerBlack == "" or lastMove == "" then
|
||||
return
|
||||
end
|
||||
local currentPlayer
|
||||
if lastMove == "black" or lastMove == "" then
|
||||
currentPlayer = "white"
|
||||
else
|
||||
currentPlayer = "black"
|
||||
end
|
||||
|
||||
local claimer, other
|
||||
if (currentPlayer == "white" and playerWhite == playerName) then
|
||||
claimer = playerWhite
|
||||
other = playerBlack
|
||||
elseif (currentPlayer == "black" and playerBlack == playerName) then
|
||||
claimer = playerBlack
|
||||
other = playerWhite
|
||||
else
|
||||
send_message(playerName, S("You can't claim a draw, it's not your turn!"))
|
||||
return
|
||||
end
|
||||
|
||||
local positions = get_positions_history(meta)
|
||||
local maxRepeatedPositions = count_repeated_positions(positions, 3)
|
||||
if maxRepeatedPositions == 2 then
|
||||
send_message(claimer, S("<not implemented>"), botColor)
|
||||
elseif maxRepeatedPositions >= 3 then
|
||||
meta:set_string("gameResult", "draw")
|
||||
meta:set_string("gameResultReason", "same_position_3")
|
||||
add_special_to_moves_list(meta, "draw")
|
||||
update_formspec(meta)
|
||||
send_message(claimer, S("You have drawn the game by applying the same position rule."), botColor)
|
||||
if claimer ~= other then
|
||||
send_message(other, S("@1 has drawn the game by applying the same position rule.", claimer), botColor)
|
||||
end
|
||||
minetest.log("action", "[xdecor] Chess: A game between "..playerWhite.." and "..playerBlack.." ended in a draw because "..claimer.." has applied the same position rule")
|
||||
else
|
||||
send_message(claimer, S("Your draw claim is invalid!"), botColor)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local promotions = {
|
||||
"queen_white", "rook_white", "bishop_white", "knight_white",
|
||||
"queen_black", "rook_black", "bishop_black", "knight_black",
|
||||
|
BIN
textures/chess_draw_50move.png
Normal file
BIN
textures/chess_draw_50move.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 472 B |
BIN
textures/chess_draw_50move_next.png
Normal file
BIN
textures/chess_draw_50move_next.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 466 B |
BIN
textures/chess_draw_repeat3.png
Normal file
BIN
textures/chess_draw_repeat3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 340 B |
BIN
textures/chess_draw_repeat3_next.png
Normal file
BIN
textures/chess_draw_repeat3_next.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 441 B |
BIN
textures/chess_resign.png
Normal file
BIN
textures/chess_resign.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 380 B |
Loading…
Reference in New Issue
Block a user