implemented maze

This commit is contained in:
2ManyProjects 2025-03-08 23:25:49 -06:00
parent 5d04deae9f
commit ef6cee7883
7 changed files with 263 additions and 104 deletions

View file

@ -42,6 +42,7 @@ var highlightStyle = null
var cpuElo = 1500
var is_initialized: bool = false
var currentNode = null;
var has_opponent = true;
# Node references
@onready var turnIndicator: ColorRect = $TurnIndicator
@ -60,9 +61,7 @@ var currentNode = null;
var captured_pieces_this_turn: Array = []
var player_pieces_lost_this_turn: Array = []
var winConditionManager: WinConditionManager
var currentWinCondition = Utils.WinConditionType.CAPTURE_UNIT
var currentLossCondition = Utils.LossConditionType.UNIT_LOST
var winConditionManager: WinConditionManager = null
# Export parameters
@ -109,13 +108,21 @@ func _on_new_game_requested(options = {}):
captured_pieces_this_turn = []
player_pieces_lost_this_turn = []
turnIndicator.visible = true
if options and "fen" in options.metadata:
currentFen = options.metadata.fen
if "elo" in options:
has_opponent = true
if cameraController:
cameraController.reset_view()
if options:
if "fen" in options.metadata:
currentFen = options.metadata.fen
if "elo" in options.metadata:
cpuElo = options.metadata.elo
if cameraController:
cameraController.reset_view()
if options and "metadata" in options:
if "has_opponent" in options.metadata:
has_opponent = options.metadata.has_opponent
if winConditionManager == null:
winConditionManager = WinConditionManager.new(self)
add_child(winConditionManager)
winConditionManager.connect("win_condition_met", Callable(self, "_on_win_condition_met"))
winConditionManager.connect("loss_condition_met", Callable(self, "_on_loss_condition_met"))
if winConditionManager:
winConditionManager.load_condition_from_metadata(options.metadata)
@ -126,6 +133,7 @@ func _on_new_game_requested(options = {}):
resetBoard()
initializeDeckSystem()
initializeBoard()
initializeTiles()
if cardDisplay:
cardDisplay.visible = true
if stateMachine:
@ -150,11 +158,11 @@ func initialize_game_system():
stockfishController = StockfishController.new()
add_child(stockfishController)
stockfishController.connect_to_engine(stockfishPath, self)
winConditionManager = WinConditionManager.new(self)
add_child(winConditionManager)
winConditionManager.connect("win_condition_met", Callable(self, "_on_win_condition_met"))
winConditionManager.connect("loss_condition_met", Callable(self, "_on_loss_condition_met"))
if winConditionManager == null:
winConditionManager = WinConditionManager.new(self)
add_child(winConditionManager)
winConditionManager.connect("win_condition_met", Callable(self, "_on_win_condition_met"))
winConditionManager.connect("loss_condition_met", Callable(self, "_on_loss_condition_met"))
# Start the state machine
if stateMachine:
@ -621,11 +629,14 @@ func resolveMoveEffects() -> void:
func endTurn() -> void:
print("turn_changed")
emit_signal("turn_changed")
Turn = 1 if Turn == 0 else 0
if has_opponent:
Turn = 1 if Turn == 0 else 0
updateTurnIndicator()
if (isPlayerTurn()):
updateEffectDurations()
check_captured_pieces_conditions()
if winConditionManager.win_condition == Utils.WinConditionType.CAPTURE_UNIT || winConditionManager.loss_condition == Utils.LossConditionType.UNIT_LOST:
check_captured_pieces_conditions()
func togglePieceChessEffect() -> void:

View file

@ -198,7 +198,7 @@ func _get_random_room_type(level, total_levels):
return Utils.RoomType.BOSS
elif roll < boss_chance + shop_chance:
return Utils.RoomType.SHOP
elif roll < boss_chance + shop_chance + event_chance and level > 5:
elif roll < boss_chance + shop_chance + event_chance:
return Utils.RoomType.EVENT
else:
return Utils.RoomType.NORMAL
@ -341,12 +341,39 @@ func generate_starting_data(node):
}
func generate_event_data(node):
var index = map_to_array_index(node.level, 2, current_max_level - 2, 1, level_unit_distribution.size() - 1);
var unit_string = level_unit_distribution[index]
var height = 6
var width = unit_string.length()
if node.level > 7 and node.level <= 10:
height = node.level
elif node.level > 10:
height = 10
# var mazedata = generate_maze(width, height)
var mazedata = generate_maze(16, 16)
# print("**************************")
# print("**************************")
# print("**************************")
# print(mazedata)
# print("**************************")
# print("**************************")
# print("**************************")
return {
"is_escape": node.metadata.is_escape if node.metadata.has("is_escape") else false,
"fen": "8/4p3/8/8/8/8 w KQkq - 0 1",
"fen": mazedata.fen + " w KQkq - 0 1",
"game_type": "maze",
"has_opponent": false,
"win_condition": Utils.WinConditionType.TILE_REACHED,
"win_target": [mazedata.end],
"win_target_unit": "King",
"elo": node.elo,
"reward": {
"gold": 150 * node.level,
"cards": [],
"selection": generate_shop_cards(5),
"selection_limit": 1
},
}
# "rnbqkbnr1/pppppppp1/9/9/9/9/9/PPPPPPPP1/RNBQKBNR1 w KQkq - 0 1"
func generate_chess_data(node):
@ -475,3 +502,101 @@ func map_to_array_index(current_value, min_value, max_value, min_index, max_inde
# Ensure we're returning an integer within the valid array index range
return int(clamp(mapped_index, min_index, max_index))
func generate_maze(width: int, height: int) -> Dictionary:
# Ensure dimensions are odd to have proper walls
if width % 2 == 0:
width += 1
if height % 2 == 0:
height += 1
# Initialize the maze with all walls
var maze = []
for y in range(height):
var row = []
for x in range(width):
row.append("*") # * represents wall
maze.append(row)
# Use a recursive backtracking algorithm to generate the maze
var rng = RandomNumberGenerator.new()
rng.randomize()
# Start at a random odd position
var start_x = rng.randi_range(0, width/2-1) * 2 + 1
var start_y = rng.randi_range(0, height/2-1) * 2 + 1
# Carve the maze recursively
_carve_maze(maze, start_x, start_y, width, height, rng)
# Pick a random end point (far from start point)
var end_x = 0
var end_y = 0
var max_distance = 0
for y in range(1, height, 2):
for x in range(1, width, 2):
if maze[y][x] == " ": # Only consider path cells
var distance = abs(x - start_x) + abs(y - start_y)
if distance > max_distance:
max_distance = distance
end_x = x
end_y = y
maze[start_y][start_x] = "k"
# Mark the end position with a space (keep it as a path)
# It's already a space, but we ensure it here
maze[end_y][end_x] = " "
# Convert the maze to a FEN-like string
var fen_string = ""
for y in range(height):
var empty_count = 0
for x in range(width):
if maze[y][x] == " ": # Empty space
empty_count += 1
else:
if empty_count > 0:
fen_string += str(empty_count)
empty_count = 0
fen_string += maze[y][x]
# Add any remaining empty count
if empty_count > 0:
fen_string += str(empty_count)
# Add row separator (except for the last row)
if y < height - 1:
fen_string += "/"
return {
"fen": fen_string,
"start": str(start_x) + "-"+ str(start_y),
"end": str(end_x) + "-"+ str(end_y)
}
# Recursive function to carve out the maze
func _carve_maze(maze, x, y, width, height, rng):
# Mark the current cell as a path
maze[y][x] = " "
# Define the four possible directions (up, right, down, left)
var directions = [[0, -2], [2, 0], [0, 2], [-2, 0]]
# Shuffle directions for randomness
directions.shuffle()
# Try each direction
for dir in directions:
var nx = x + dir[0]
var ny = y + dir[1]
# Check if the new position is valid and unvisited
if nx > 0 and nx < width-1 and ny > 0 and ny < height-1 and maze[ny][nx] == "*":
# Carve a path between the current cell and the new cell
maze[y + dir[1]/2][x + dir[0]/2] = " "
# Recursively carve from the new cell
_carve_maze(maze, nx, ny, width, height, rng)

View file

@ -304,6 +304,15 @@ func _on_map_node_selected(node_data):
mapScreen.visible = false
back_to_map = true
_on_start_game_pressed(node_data)
elif node_data.type == Utils.RoomType.EVENT:
if gameMenuScreen:
gameMenuScreen.visible = false
if deckManagerScreen:
deckManagerScreen.visible = false
if mapScreen:
mapScreen.visible = false
back_to_map = true
_on_start_game_pressed(node_data)
func _on_node_completed(options):
var node_data = options.node

View file

@ -31,9 +31,11 @@ func _init(game: ChessGame):
chess_game.connect("game_initialized", Callable(self, "_on_game_initialized"))
func _on_game_initialized():
reset_conditions()
# reset_conditions()
print("_on_game_initialized")
func reset_conditions():
print("reset_conditions")
captured_pieces.clear()
turn_count = 0
target_tiles.clear()
@ -81,12 +83,11 @@ func highlight_target_tiles():
func set_win_condition(type: Utils.WinConditionType, data: Dictionary = {}):
win_condition = type
win_condition_data = data
reset_conditions()
func set_loss_condition(type: Utils.LossConditionType, data: Dictionary = {}):
loss_condition = type
loss_condition_data = data
reset_conditions()
# reset_conditions()
func _on_turn_changed():
turn_count += 1
@ -112,7 +113,7 @@ func _on_turn_changed():
check_conditions()
func on_piece_captured(piece):
print("on_piece_captured ISEnemy ", piece)
# print("on_piece_captured ISEnemy ", piece)
var is_enemy_piece = piece.Item_Color == (1 if chess_game.Turn == 1 else 0)
print("on_piece_captured ISEnemy ", is_enemy_piece)
if is_enemy_piece:
@ -220,14 +221,17 @@ func count_enemy_pieces() -> int:
# Helper methods for game integration
func load_condition_from_metadata(metadata: Dictionary):
# print("load_condition_from_metadata ", metadata)
if metadata.has("win_condition"):
match metadata["win_condition"]:
Utils.WinConditionType.CAPTURE_UNIT:
set_win_condition(Utils.WinConditionType.CAPTURE_UNIT, {"unit": "King"})
Utils.WinConditionType.TILE_REACHED:
# Get target tiles from metadata if available
var target_tiles = metadata.get("target_tiles", [])
set_win_condition(Utils.WinConditionType.TILE_REACHED, {"target_tiles": target_tiles, "unit": metadata.get("target_unit", "")})
target_tiles = metadata.get("win_target", [])
# print("load_condition_from_metadata ", " target_tiles ", target_tiles)
set_win_condition(Utils.WinConditionType.TILE_REACHED, {"target_tiles": target_tiles, "unit": metadata.get("win_target_unit", "")})
Utils.WinConditionType.BOARD_CLEARED:
set_win_condition(Utils.WinConditionType.BOARD_CLEARED)
Utils.WinConditionType.TURN_NUMBER:

View file

@ -5,7 +5,7 @@ func enter(_previous: String, data := {}) -> void:
if "endCondition" in data:
finished.emit(Constants.ROUND_END)
elif game.currentPlayer == game.WHITE:
elif game.currentPlayer == game.WHITE and game.has_opponent:
finished.emit(Constants.BLACK_TURN)
else:
finished.emit(Constants.WHITE_TURN)

View file

@ -20,6 +20,7 @@ func enter(_previous: String, _data := {}) -> void:
func check_win_conditions() -> bool:
match game.winConditionManager.win_condition:
Utils.WinConditionType.CAPTURE_UNIT:
print("check_win_conditions ", "Utils.WinConditionType.CAPTURE_UNIT")
# Directly check if king/target unit was captured
var target_unit = game.winConditionManager.win_condition_data.get("unit", "King")
@ -35,6 +36,7 @@ func check_win_conditions() -> bool:
return true
game.captured_pieces_this_turn = []
Utils.WinConditionType.BOARD_CLEARED:
print("check_win_conditions ", "Utils.WinConditionType.BOARD_CLEARED")
var remaining_enemy_pieces = game.winConditionManager.count_enemy_pieces()
if remaining_enemy_pieces <= 0:
var condition_data = {
@ -46,6 +48,7 @@ func check_win_conditions() -> bool:
return true
Utils.WinConditionType.TURN_NUMBER:
print("check_win_conditions ", "Utils.WinConditionType.TURN_NUMBER")
var target_turn = game.winConditionManager.win_condition_data.get("target_turn", 0)
if game.winConditionManager.turn_count >= target_turn:
var condition_data = {
@ -57,15 +60,18 @@ func check_win_conditions() -> bool:
return true
Utils.WinConditionType.TILE_REACHED:
var target_tiles = game.winConditionManager.target_tiles
var required_unit = game.winConditionManager.win_condition_data.get("unit", "")
print("check_win_conditions ", "Utils.WinConditionType.TILE_REACHED", game.winConditionManager.win_condition_data)
var target_tiles = game.winConditionManager.win_condition_data.get("target_tiles", [])
var required_unit = game.winConditionManager.win_condition_data.get("unit", "King")
var all_targets_reached = true
# print("check_win_conditions ", required_unit, " ", target_tiles)
for tile_loc in target_tiles:
if !game.is_tile_reached(tile_loc, required_unit):
all_targets_reached = false
break
# print("all_targets_reached ", all_targets_reached,)
if all_targets_reached and target_tiles.size() > 0:
var condition_data = {
"type": Utils.WinConditionType.TILE_REACHED,

View file

@ -5,88 +5,92 @@ class_name King
var Castling = true
func _ready():
self.texture = load("res://addons/Chess/Textures/WKing.svg")
Points = 10
self.texture = load("res://addons/Chess/Textures/WKing.svg")
Points = 10
func _process(_delta):
if Item_Color != Temp_Color:
Temp_Color = Item_Color
if Item_Color == 0:
self.texture = load("res://addons/Chess/Textures/WKing.svg")
elif Item_Color == 1:
self.texture = load("res://addons/Chess/Textures/BKing.svg")
if Item_Color != Temp_Color:
Temp_Color = Item_Color
if Item_Color == 0:
self.texture = load("res://addons/Chess/Textures/WKing.svg")
elif Item_Color == 1:
self.texture = load("res://addons/Chess/Textures/BKing.svg")
# King.gd
func getValidMoves(board_flow, current_location: String) -> Dictionary:
var moves = {
"regular_moves": [],
"special_moves": []
}
var moves = {
"regular_moves": [],
"special_moves": []
}
var loc = current_location.split("-")
var x = int(loc[0])
var y = int(loc[1])
var loc = current_location.split("-")
var x = int(loc[0])
var y = int(loc[1])
# Regular king moves (unchanged)
var king_dirs = [[0,1], [0,-1], [1,0], [-1,0], [1,1], [1,-1], [-1,1], [-1,-1]]
for dir in king_dirs:
var new_loc = str(x + dir[0]) + "-" + str(y + dir[1])
if is_valid_cell(board_flow, new_loc):
if can_move_to_cell(board_flow, new_loc) || can_move_to_cell(board_flow, new_loc, true):
moves.regular_moves.append(new_loc)
# Regular king moves (unchanged)
var king_dirs = [[0,1], [0,-1], [1,0], [-1,0], [1,1], [1,-1], [-1,1], [-1,-1]]
for dir in king_dirs:
var new_loc = str(x + dir[0]) + "-" + str(y + dir[1])
if is_valid_cell(board_flow, new_loc):
if can_move_to_cell(board_flow, new_loc) || can_move_to_cell(board_flow, new_loc, true):
moves.regular_moves.append(new_loc)
# Castling logic
if Castling:
# Kingside castling (right side)
if check_kingside_castle(board_flow, x, y):
# Add rook's current position to regular moves
moves.regular_moves.append(str(x + 3) + "-" + str(y))
# Add king and rook destinations to special moves as individual items
moves.special_moves.append(str(x + 1) + "-" + str(y)) # Rook's destination
moves.special_moves.append(str(x + 2) + "-" + str(y)) # King's destination
# Castling logic
if Castling:
# Kingside castling (right side)
if check_kingside_castle(board_flow, x, y):
# Add rook's current position to regular moves
moves.regular_moves.append(str(x + 3) + "-" + str(y))
# Add king and rook destinations to special moves as individual items
moves.special_moves.append(str(x + 1) + "-" + str(y)) # Rook's destination
moves.special_moves.append(str(x + 2) + "-" + str(y)) # King's destination
# Queenside castling (left side)
if check_queenside_castle(board_flow, x, y):
# Add rook's current position to regular moves
moves.regular_moves.append(str(x - 4) + "-" + str(y))
# Add king and rook destinations to special moves as individual items
moves.special_moves.append(str(x - 1) + "-" + str(y)) # Rook's destination
moves.special_moves.append(str(x - 2) + "-" + str(y)) # King's destination
# Queenside castling (left side)
if check_queenside_castle(board_flow, x, y):
# Add rook's current position to regular moves
moves.regular_moves.append(str(x - 4) + "-" + str(y))
# Add king and rook destinations to special moves as individual items
moves.special_moves.append(str(x - 1) + "-" + str(y)) # Rook's destination
moves.special_moves.append(str(x - 2) + "-" + str(y)) # King's destination
return moves
return moves
func check_kingside_castle(board_flow, x: int, y: int) -> bool:
# Check if path is clear
for i in range(1, 3):
var check_pos = str(x + i) + "-" + str(y)
if !is_valid_cell(board_flow, check_pos) || !can_move_to_cell(board_flow, check_pos):
return false
var container = board_flow.get_node(check_pos) as PieceContainer
if container.has_piece():
return false
# Check if path is clear
for i in range(1, 3):
var check_pos = str(x + i) + "-" + str(y)
if !is_valid_cell(board_flow, check_pos) || !can_move_to_cell(board_flow, check_pos):
return false
var container = board_flow.get_node(check_pos) as PieceContainer
if container.has_piece():
return false
var rook_pos = str(x + 3) + "-" + str(y)
if !is_valid_cell(board_flow, rook_pos):
return false
var rook_container = board_flow.get_node(rook_pos) as PieceContainer
var rook = rook_container.get_piece()
return rook.name == "Rook" && rook.Castling && rook.Item_Color == self.Item_Color
var rook_pos = str(x + 3) + "-" + str(y)
if !is_valid_cell(board_flow, rook_pos):
return false
var rook_container = board_flow.get_node(rook_pos) as PieceContainer
if !rook_container.has_piece():
return false
var rook = rook_container.get_piece()
return rook.name == "Rook" && rook.Castling && rook.Item_Color == self.Item_Color
func check_queenside_castle(board_flow, x: int, y: int) -> bool:
# Check if path is clear
for i in range(1, 4):
var check_pos = str(x - i) + "-" + str(y)
if !is_valid_cell(board_flow, check_pos) || !can_move_to_cell(board_flow, check_pos):
return false
var container = board_flow.get_node(check_pos) as PieceContainer
if container.has_piece():
return false
# Check if path is clear
for i in range(1, 4):
var check_pos = str(x - i) + "-" + str(y)
if !is_valid_cell(board_flow, check_pos) || !can_move_to_cell(board_flow, check_pos):
return false
var container = board_flow.get_node(check_pos) as PieceContainer
if container.has_piece():
return false
# Check if rook is in position and hasn't moved
var rook_pos = str(x - 4) + "-" + str(y)
if !is_valid_cell(board_flow, rook_pos):
return false
# Check if rook is in position and hasn't moved
var rook_pos = str(x - 4) + "-" + str(y)
if !is_valid_cell(board_flow, rook_pos):
return false
var rook_container = board_flow.get_node(rook_pos) as PieceContainer
var rook = rook_container.get_piece()
return rook.name == "Rook" && rook.Castling && rook.Item_Color == self.Item_Color
var rook_container = board_flow.get_node(rook_pos) as PieceContainer
if !rook_container.has_piece():
return false
var rook = rook_container.get_piece()
return rook.name == "Rook" && rook.Castling && rook.Item_Color == self.Item_Color