fixed stockfish interpretation of smaller and larger boards

This commit is contained in:
2ManyProjects 2025-03-07 14:04:40 -06:00
parent 401d915a0b
commit 1cce2fe244
9 changed files with 148 additions and 25 deletions

View file

@ -108,7 +108,15 @@ class ChessEngine extends EventEmitter {
this.engine.stdin.write(cmd + '\n'); this.engine.stdin.write(cmd + '\n');
} }
} }
async startPos() {
if (!this.isReady) throw new Error('Engine not ready');
this.sendCommand(`position startpos`);
// Ensure engine is ready after position set
this.sendCommand('isready');
await new Promise(resolve => this.once('ready', resolve));
}
async setBoardPosition(fen) { async setBoardPosition(fen) {
if (!this.isReady) throw new Error('Engine not ready'); if (!this.isReady) throw new Error('Engine not ready');

View file

@ -94,6 +94,7 @@ ffish.onRuntimeInitialized = async () => {
engine.sendCommand('setoption name Hash value 128'); engine.sendCommand('setoption name Hash value 128');
engine.sendCommand('setoption name MultiPV value 1'); engine.sendCommand('setoption name MultiPV value 1');
engine.sendCommand('setoption name UCI_LimitStrength value true'); engine.sendCommand('setoption name UCI_LimitStrength value true');
engine.sendCommand('uci');
} }
} catch (error) { } catch (error) {
console.log('Initialization error:', error); console.log('Initialization error:', error);
@ -209,13 +210,10 @@ app.post('/new', async (req, res) => {
}); });
// Set position endpoint // Set position endpoint
app.post('/position', (req, res) => { app.post('/position', async(req, res) => {
lastResponse = new Date().getTime() lastResponse = new Date().getTime()
const { fen, variant = 'chess' } = req.body; const { fen, variant = 'chess', start } = req.body;
if (!fen) {
return res.status(400).json({ error: 'FEN string required' });
}
try { try {
//we have a lot of funky rules lets not validate //we have a lot of funky rules lets not validate
@ -232,7 +230,13 @@ app.post('/position', (req, res) => {
// // } // // }
// board.setFen(fen); // board.setFen(fen);
// } // }
if(start){
await engine.startPos()
engine.sendCommand('d');
}else if(fen){
board.setFen(fen); board.setFen(fen);
await engine.setBoardPosition(fen)
}
res.json({ res.json({
status: 'ok', status: 'ok',
@ -246,7 +250,7 @@ app.post('/position', (req, res) => {
moveStack: board.moveStack() moveStack: board.moveStack()
}); });
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message, poserr: true });
} }
}); });

View file

@ -34,7 +34,7 @@ func connect_to_engine(_path: String, g: ChessGame) -> bool:
if ServerManager.is_server_running(): if ServerManager.is_server_running():
print("**************SERVER RUNNING ****************") print("**************SERVER RUNNING ****************")
running = true running = true
start_game(2100) # start_game(2100)
return true return true
await get_tree().create_timer(delay).timeout await get_tree().create_timer(delay).timeout
@ -74,7 +74,7 @@ func load_fen(fen: String):
http_request.request(server_url + "/position", headers, HTTPClient.METHOD_POST, body) http_request.request(server_url + "/position", headers, HTTPClient.METHOD_POST, body)
await http_request.request_completed await http_request.request_completed
func start_board(elo: int): func start_board(elo: int, variant: String = "8x8"):
if not running: if not running:
return return
var headers = ["Content-Type: application/json"] var headers = ["Content-Type: application/json"]
@ -85,7 +85,7 @@ func start_board(elo: int):
print(body) print(body)
http_request.request(server_url + "/new", headers, HTTPClient.METHOD_POST, body) http_request.request(server_url + "/new", headers, HTTPClient.METHOD_POST, body)
await http_request.request_completed await http_request.request_completed
setElo(elo) setElo(elo, variant)
func _exit_tree(): func _exit_tree():
ServerManager.stop_server() ServerManager.stop_server()
@ -107,7 +107,40 @@ func get_globalDir() -> String:
return OS.get_environment("HOME").path_join("Library/ChessBuilder") return OS.get_environment("HOME").path_join("Library/ChessBuilder")
func setElo(elo: int = 1350) -> void: func setVariant(variant: String = "8x8"):
if not running:
return
print("####################################")
print("####################################")
print("chessbuilder" + variant)
print("####################################")
print("####################################")
print("####################################")
var headers = ["Content-Type: application/json"]
var data = {
"options": [
{
"name": "VariantPath",
"value": get_globalDir() + "/Assets" + "/ChessEngines/Fairy-Stockfish/src/variants.ini"
},
{
"name": "UCI_Variant",
"value": "chessbuilder" + variant
},
]
}
var body = JSON.new().stringify(data)
# Request engine move
http_request.request(
server_url + "/setoptions",
headers,
HTTPClient.METHOD_POST,
body
)
func setElo(elo: int = 1350, variant: String = "8x8") -> void:
if not running: if not running:
return return
var headers = ["Content-Type: application/json"] var headers = ["Content-Type: application/json"]
@ -127,7 +160,7 @@ func setElo(elo: int = 1350) -> void:
}, },
{ {
"name": "UCI_Variant", "name": "UCI_Variant",
"value": "chessbuilder" # Convert int to string "value": "chessbuilder" + variant
}, },
] ]
} }
@ -144,11 +177,18 @@ func setElo(elo: int = 1350) -> void:
HTTPClient.METHOD_POST, HTTPClient.METHOD_POST,
body body
) )
await elo_req.request_completed
http_request.request(
server_url + "/position",
headers,
HTTPClient.METHOD_POST,
JSON.new().stringify({"start": true})
)
func generateMove(think_time_ms: int = 1000) -> void: func generateMove(think_time_ms: int = 1000) -> void:
if not running: if not running:
return return
print("&&&&&&&&&&&&&&&GENERATING MOVE&&&&&&&&&&&&&&&&&&&&&&") print("&&&&&&&&&&&&&&&GENERATING MOVE&&&&&&&&&&&&&&&&&&&&&&", str(game.getCurrentFen()))
move_time = think_time_ms move_time = think_time_ms

View file

@ -107,6 +107,8 @@ func _on_new_game_requested(options = {}):
cpuElo = options.elo cpuElo = options.elo
if cameraController: if cameraController:
cameraController.reset_view() cameraController.reset_view()
print("ChessGame FEN ", currentFen)
print("ChessGame DIMENSIONS ", get_board_dimensions(currentFen))
if is_initialized: if is_initialized:
resetBoard() resetBoard()
initializeDeckSystem() initializeDeckSystem()
@ -117,8 +119,10 @@ func _on_new_game_requested(options = {}):
stateMachine.transitionToNextState(Constants.WHITE_TURN) stateMachine.transitionToNextState(Constants.WHITE_TURN)
else: else:
initialize_game_system() initialize_game_system()
stockfishController.start_board(cpuElo) if currentFen:
stockfishController.start_board(cpuElo, get_board_dimensions(currentFen))
else:
stockfishController.start_board(cpuElo, "8x8")
func initialize_game_system(): func initialize_game_system():
print("Initializing game system") print("Initializing game system")
# Set up basic styles first # Set up basic styles first
@ -896,3 +900,20 @@ func updateHalfMoveClock(fromIdx: int, toIdx: int) -> void:
halfMoveClock = 0 halfMoveClock = 0
else: else:
halfMoveClock += 1 halfMoveClock += 1
func get_board_dimensions(fen_string: String) -> String:
var board_part: String = fen_string.split(" ")[0]
var ranks: Array = board_part.split("/")
var height: int = ranks.size()
var width: int = 0
var first_rank: String = ranks[0]
for character in first_rank:
if character.is_valid_int():
width += int(character)
else:
width += 1
return str(width) + "x" + str(height)

View file

@ -2,6 +2,7 @@ extends Control
class_name DeckManagerScreen class_name DeckManagerScreen
signal back_pressed signal back_pressed
signal deck_manager_visibility_changed(isvisible)
# Node references # Node references
@onready var deckGrid = $MainContainer/GridScrollContainer/GridContainer @onready var deckGrid = $MainContainer/GridScrollContainer/GridContainer

View file

@ -12,6 +12,9 @@ var max_nodes_per_level = 4
var positions_per_level = 6 var positions_per_level = 6
var starting_elo = 1000 var starting_elo = 1000
var final_elo = 2100 var final_elo = 2100
var current_max_level = 0;
# var level_unit_distribution = ["", "", "", "nkr", "rnkr", "rnkbr", "rnqkbr", "rnqkbnr", "rnbqkbnr", "rbnqknbnr", "rnbnqknbnr", "rnbnqknbnbr", "rbnbnqknbnbr"]
var level_unit_distribution = ["", "", "nkr", "rnkr", "rnkr", "rnkbr", "rnqkbr", "rnqkbnr", "rnbqkbnr", "rbnqknbnr", "rnbnqknbnr", "rnbnqknbnbr", "rbnbnqknbnbr"]
var _rng = RandomNumberGenerator.new() var _rng = RandomNumberGenerator.new()
var _next_id = 0 var _next_id = 0
@ -29,7 +32,7 @@ func generate_map():
_next_id = 0 _next_id = 0
var num_levels = _rng.randi_range(min_levels, max_levels) var num_levels = _rng.randi_range(min_levels, max_levels)
current_max_level = num_levels;
var elo_step = float(final_elo - starting_elo) / (num_levels - 1) var elo_step = float(final_elo - starting_elo) / (num_levels - 1)
var start_node = { var start_node = {
@ -307,10 +310,53 @@ func generate_event_data(node):
} }
# "rnbqkbnr1/pppppppp1/9/9/9/9/9/PPPPPPPP1/RNBQKBNR1 w KQkq - 0 1" # "rnbqkbnr1/pppppppp1/9/9/9/9/9/PPPPPPPP1/RNBQKBNR1 w KQkq - 0 1"
func generate_chess_data(node): func generate_chess_data(node):
# level_unit_distribution
# current_max_level
var rng = float(node.level) / int(current_max_level)
var index = map_to_array_index(node.level, 2, current_max_level - 2, 3, level_unit_distribution.size() - 1);
var unit_string = level_unit_distribution[index]
var pawn_string = ""
for x in unit_string.length():
pawn_string += "p"
var height = 6;
# "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"
var fen = "";
if node.level > 7 and node.level <= 10:
height = node.level
elif node.level > 10:
height = 10
for x in height - 2:
if x == 0:
fen += unit_string + "/"
elif x == 1:
fen += pawn_string + "/"
else:
fen += str(unit_string.length()) + "/"
fen += pawn_string.to_upper() + "/" + unit_string.to_upper()
var fen_ending = " w KQkq - 0 1"
# print("generate_chess_data ", fen + fen_ending)
return { return {
"is_escape": node.metadata.is_escape if node.metadata.has("is_escape") else false, "is_escape": node.metadata.is_escape if node.metadata.has("is_escape") else false,
"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", "fen": fen + fen_ending,
"game_type": "chess", "game_type": "chess",
"win_condition": Utils.WinCondition.King, "win_condition": Utils.WinCondition.King,
"elo": node.elo, "elo": node.elo,
} }
func map_to_array_index(current_value, min_value, max_value, min_index, max_index):
# Ensure the current value is within bounds
var clamped_value = clamp(current_value, min_value, max_value)
# Calculate how far along the input range we are (0.0 to 1.0)
var normalized_position = float(clamped_value - min_value) / float(max_value - min_value)
# Map this to our target index range
var index_range = max_index - min_index
var mapped_index = min_index + round(normalized_position * index_range)
# Ensure we're returning an integer within the valid array index range
return int(clamp(mapped_index, min_index, max_index))

View file

@ -38,5 +38,3 @@ func _on_state_delay_timeout() -> void:
finished.emit(Constants.HAND_SETUP) finished.emit(Constants.HAND_SETUP)
func exit() -> void: func exit() -> void:
moveTimer.stop() moveTimer.stop()

View file

@ -48,16 +48,19 @@ func enter(_previous: String, _data := {}) -> void:
print("GENERATED MOVE ", move) print("GENERATED MOVE ", move)
if move: if move:
var move_str = move.move # e.g., "e2e4" var move_str = move.move # e.g., "e2e4"
if "," in move_str:
move_str = move.move.split(",")[0]
var source_square = move_str.substr(0, 2) # "e2" var source_square = move_str.substr(0, 2) # "e2"
var target_square = move_str.substr(2, 2) # "e4" var target_square = move_str.substr(2, 2) # "e4"
# First select the piece # First select the piece
var source_location = Utils.convert_algebraic_to_location(source_square) var source_location = Utils.convert_algebraic_to_location(source_square, game.boardYSize)
game.selectedNode = source_location game.selectedNode = source_location
print("source_location ", source_location) print("source_location ", source_location)
# Then make the move # Then make the move
var target_location = Utils.convert_algebraic_to_location(target_square) var target_location = Utils.convert_algebraic_to_location(target_square, game.boardYSize)
print("target_location ", target_location) print("target_location ", target_location)
handleMovement(target_location, true) handleMovement(target_location, true)
return return
@ -94,8 +97,10 @@ func handleMovement(location: String, generated: bool = false) -> void:
var sourceContainer = game.get_node("Flow/" + game.selectedNode) as PieceContainer var sourceContainer = game.get_node("Flow/" + game.selectedNode) as PieceContainer
var piece = sourceContainer.get_piece() var piece = sourceContainer.get_piece()
if piece == null: if piece == null:
# print("No Piece") print("No Piece")
return return
else:
print("Selected ", piece.name)
# print("SColor ", sourcePiece.Item_Color, " tColor ", piece.Item_Color) # print("SColor ", sourcePiece.Item_Color, " tColor ", piece.Item_Color)
var piece_id = piece.get_instance_id() var piece_id = piece.get_instance_id()

View file

@ -23,7 +23,7 @@ static func generate_guid() -> String:
return guid return guid
static func convert_algebraic_to_location(square: String) -> String: static func convert_algebraic_to_location(square: String, maxRank: int) -> String:
var file = square[0] # letter (a-h) var file = square[0] # letter (a-h)
var rank = int(square[1]) # number (1-8) var rank = int(square[1]) # number (1-8)
@ -33,7 +33,7 @@ static func convert_algebraic_to_location(square: String) -> String:
# Since we're working with black's moves and our board is oriented with white at bottom: # Since we're working with black's moves and our board is oriented with white at bottom:
# 1. Flip rank: 8 - rank to mirror vertically # 1. Flip rank: 8 - rank to mirror vertically
file_num = file_num file_num = file_num
var rank_num = 8 - rank var rank_num = maxRank - rank
return "%d-%d" % [file_num, rank_num] return "%d-%d" % [file_num, rank_num]