Godot Version
godot 4.3
Question
Ok so i've been working on my ultimate tic tac toe game and I'm having an issue, I will show a video which will explain everything
So yeah....The colorPicker closes when I try to choose a color and I have to reclick to change the color, I have tried to find fixs and tried to fix it myself, but it does absolutely nothing...
Here are my SceneTree of AIminiboard.tscn to help:
Here is my AIminiboard.gd script to help with this:
extends Control
@export var tween_intensity: float
@export var tween_duration: float
@export var button_size: Vector2 = Vector2(80, 80) # Adjust these values to make buttons bigger/smaller
@export var grid_spacing: int = 5 # Space between buttons in each grid
@export var column_spacing: int = 20 # Space between different 3x3 grids
var current_player = "X" # Player is "X", AI is "O"
var cells = [] # Store references to buttons
var is_ai_turn = false # Track if it's AI's turn
var small_board_wins = [] # Track wins for small boards
var overall_winner = "" # Track overall winner
var x_win_labels = [] # Declare labels for each column
var o_win_labels = [] # Declare labels for each column
var tie_labels = [] # Array to hold tie labels for each column
var stats: Dictionary = load_stats() # Load or initialize stats at the start
var active_column = -1 # Initialize with -1 to allow any board on the first move
var ai_difficulty = "Hard" # Can be "Easy", "Medium", or "Hard"
var player_goes_first: bool = true
var x_first_count = 0
var o_first_count = 0
var focusable_buttons: Array = []
var current_focus_index: int = 0
@onready var winner_label = $WinnerLabel # General winner label
@onready var ai_home_button = $AIHomeButton # Reference to the AIHomeButton
@onready var ai_rematch_button = $AIRematchUltimateButton # Reference to the rematch button
@onready var stating_labels = [
$Stating1, $Stating2, $Stating3, $Stating4, $Stating5, $Stating6, $Stating7, $Stating8, $Stating9
]
@onready var rematch: Button = $AIRematchUltimateButton
@onready var homepage: Button = $Miniboardhomepage
@onready var aihome: Button = $AIHomeButton
@onready var grid_button_settings: Button = $GridButtonSettings
@onready var grid_settings_label: Label = $GridSettingsLabel
@onready var cell_settings_label: Label = $CellSettingsLabel
func _ready():
$BackgroundColorOption.text = "Background Color Options:"
$BackgroundColorOption.add_theme_font_size_override("font_size", 45)
$CellButtonColor.text = "Cell Color Options:"
$CellButtonColor.add_theme_font_size_override("font_size", 45)
$GridColorOption.text = "Grid Color Options:"
$GridColorOption.add_theme_font_size_override("font_size", 44)
if has_node("CanvasLayer/Control/FPS_COUNTER_AIminiboard"):
$CanvasLayer/Control/FPS_COUNTER_AIminiboard.add_to_group("fps_counters")
$CanvasLayer/Control/FPS_COUNTER_AIminiboard.visible = FpsManager.fps_enabled
create_styled_panel()
setup_grid_containers()
var saved_color = load_grid_color("grid_color")
$GridColor.color = saved_color
update_grid_color(saved_color)
for label in stating_labels:
label.visible = false
cells.clear()
small_board_wins = [null, null, null, null, null, null, null, null, null] # Initialize small board wins
winner_label.visible = false
ai_home_button.visible = false # Hide the AIHomeButton initially
ai_rematch_button.visible = false # Hide rematch button initially
# Initialize labels for each column
for i in range(1, 10):
x_win_labels.append(get_node("XWinLabelColumn" + str(i)))
o_win_labels.append(get_node("OWinLabelColumn" + str(i)))
tie_labels.append(get_node("ItsATieLabelColumn" + str(i)))
x_win_labels[i - 1].visible = false
o_win_labels[i - 1].visible = false
tie_labels[i - 1].visible = false
# Initialize cells for columns and connect all buttons
for column_index in range(1, 10): # Columns 1 to 9
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index))
for cell_index in range(9): # Cells 1 to 9 in each column
var cell: Button = grid_container.get_child(cell_index)
cells.append(cell)
cell.connect("pressed", Callable(self, "_on_AICell_pressed").bind(column_index - 1, cell_index))
focusable_buttons.append(cell) # Add each cell to focusable buttons
# Add specific buttons to focusable buttons
focusable_buttons.append_array([ai_rematch_button, homepage, ai_home_button])
for button in focusable_buttons:
button.focus_mode = Control.FOCUS_ALL
# Set initial focus
set_initial_focus()
# Determine who goes first
player_goes_first = randf() < 0.5
current_player = "X" if player_goes_first else "O"
# Update UI to show who's playing
$XIsPlaying.visible = player_goes_first
$OIsPlaying.visible = !player_goes_first
# If AI goes first, trigger its turn
if !player_goes_first:
call_deferred("ai_turn")
var button10_click_player: AudioStreamPlayer = $Button10ClickPlayer
button10_click_player.stream = load("res://Sounds/click.ogg")
cell_settings_label.visible = false
grid_settings_label.visible = false # Make the label invisible on start
if not grid_button_settings.is_connected("pressed", Callable(self, "_on_gridsettings_pressed")):
grid_button_settings.connect("pressed", Callable(self, "_on_gridsettings_pressed"))
$GridColorOption.visible = false
$GridColor.visible = false
if not $GridColorOption.is_connected("item_selected", Callable(self, "_on_grid_color_option_toggled")):
$GridColorOption.connect("item_selected", Callable(self, "_on_grid_color_option_toggled"))
if not $GridColor.is_connected("color_changed", Callable(self, "_on_grid_color_changed")):
$GridColor.connect("color_changed", Callable(self, "_on_grid_color_changed"))
$CellButtonColor.connect("toggled", Callable(self, "_on_cell_button_color_toggled"))
if not $CellButtonColor.is_connected("toggled", Callable(self, "_on_cell_button_color_toggled")):
$CellButtonColor.connect("toggled", Callable(self, "_on_cell_button_color_toggled"))
if not $CellColor.is_connected("color_changed", Callable(self, "_on_cell_color_changed")):
$CellColor.connect("color_changed", Callable(self, "_on_cell_color_changed"))
$CellButtonColor.visible = false
$CellColor.visible = false
$BackgroundSettingsLabel.visible = false
$BackgroundColorOption.visible = false
$BackgroundColor.visible = false
if not $BackgroundColorOption.is_connected("toggled", Callable(self, "_on_background_color_option_toggled")):
$BackgroundColorOption.connect("toggled", Callable(self, "_on_background_color_option_toggled"))
if not $BackgroundColor.is_connected("color_changed", Callable(self, "_on_background_color_changed")):
$BackgroundColor.connect("color_changed", Callable(self, "_on_background_color_changed"))
var saved_background_color = load_grid_color("background_color")
update_background_color(saved_background_color)
var saved_cell_color = load_grid_color("cell_color")
update_cell_colors(saved_cell_color)
# Connect input events
set_process_input(true)
# Add this function to create and style panels
func create_styled_panel() -> Panel:
var panel = Panel.new()
# Create and setup background style
var bg_style = StyleBoxFlat.new()
bg_style.bg_color = Color(1, 1, 1, 1) # White color
bg_style.set_corner_radius_all(0)
bg_style.set_border_width_all(0)
# Create and setup border style
var border_style = StyleBoxFlat.new()
border_style.bg_color = Color("99999900")
border_style.set_border_width_all(2) # Set all borders to 2
border_style.border_color = Color(1, 1, 1, 1) # White border
border_style.set_corner_radius_all(0)
# Apply styles to panel
panel.add_theme_stylebox_override("panel", border_style)
panel.modulate = Color(1, 1, 1, 1) # White modulate
panel.self_modulate = Color(1, 1, 1, 1) # White self_modulate
return panel
# Add this new function to set up the grid containers
# Modify your setup_grid_containers function to add panels to cells
func setup_grid_containers():
# Setup the main grid containers (columns)
for i in range(1, 10):
var grid: GridContainer = get_node("GridContainerColumn" + str(i))
if grid:
grid.columns = 3 # Ensure 3 columns for 3x3 grid
grid.add_theme_constant_override("h_separation", grid_spacing)
grid.add_theme_constant_override("v_separation", grid_spacing)
# Setup each button in the grid
for cell in grid.get_children():
if cell is Button:
# Add panel as child of button
var panel = create_styled_panel()
cell.add_child(panel)
# Make buttons bigger by setting a larger custom minimum size
cell.custom_minimum_size = Vector2(80, 80)
cell.text = " "
cell.add_theme_font_size_override("font_size", 60)
# Optional: Add some styling to make buttons look better
var style = StyleBoxFlat.new()
style.bg_color = Color(0.2, 0.2, 0.2, 1)
style.corner_radius_top_left = 8
style.corner_radius_top_right = 8
style.corner_radius_bottom_left = 8
style.corner_radius_bottom_right = 8
cell.add_theme_stylebox_override("normal", style.duplicate())
# Create hover style
var hover_style = style.duplicate()
hover_style.bg_color = Color(0.3, 0.3, 0.3, 1)
cell.add_theme_stylebox_override("hover", hover_style)
# Create pressed style
var pressed_style = style.duplicate()
pressed_style.bg_color = Color(0.15, 0.15, 0.15, 1)
cell.add_theme_stylebox_override("pressed", pressed_style)
func set_initial_focus():
if not focusable_buttons.is_empty():
focusable_buttons[0].grab_focus()
current_focus_index = 0
func _input(_event):
if Input.is_action_just_pressed("ui_right"):
change_focus(1, 0)
get_viewport().set_input_as_handled()
elif Input.is_action_just_pressed("ui_left"):
change_focus(-1, 0)
get_viewport().set_input_as_handled()
elif Input.is_action_just_pressed("ui_down"):
change_focus(0, 1)
get_viewport().set_input_as_handled()
elif Input.is_action_just_pressed("ui_up"):
change_focus(0, -1)
get_viewport().set_input_as_handled()
elif Input.is_action_just_pressed("ui_accept"):
if focusable_buttons[current_focus_index].has_focus():
focusable_buttons[current_focus_index].emit_signal("pressed")
get_viewport().set_input_as_handled() # Prevent double input
elif Input.is_action_pressed("ui_cancel"): # Check for cancel action
_on_miniboardhomepage_pressed() # Call the back button function
func change_focus(dx: int, dy: int):
var grid_size = 3 # 3x3 grid for each small board
@warning_ignore("integer_division")
var current_grid = int(current_focus_index / (grid_size * grid_size))
var position_in_grid = current_focus_index % (grid_size * grid_size)
@warning_ignore("integer_division")
var row = int(position_in_grid / grid_size)
var col = position_in_grid % grid_size
row += dy
col += dx
if row < 0:
if current_grid >= 3:
current_grid -= 3
row = 2
else:
row = 0
elif row > 2:
if current_grid < 6:
current_grid += 3
row = 0
else:
row = 2
if col < 0:
if current_grid % 3 > 0:
current_grid -= 1
col = 2
else:
col = 0
elif col > 2:
if current_grid % 3 < 2:
current_grid += 1
col = 0
else:
col = 2
var new_index = (current_grid * grid_size * grid_size) + (row * grid_size) + col
new_index = clamp(new_index, 0, focusable_buttons.size() - 1)
if new_index != current_focus_index:
current_focus_index = new_index
focusable_buttons[current_focus_index].grab_focus()
func update_stating_labels() -> void:
for i in range(stating_labels.size()):
stating_labels[i].visible = (i == active_column and is_column_playable(i))
if active_column != -1 and is_column_playable(active_column):
# Move focus to the first empty cell in the active column
var grid_container: GridContainer = get_node("GridContainerColumn" + str(active_column + 1))
for i in range(9):
var cell: Button = grid_container.get_child(i)
if cell.text == "":
cell.grab_focus()
current_focus_index = focusable_buttons.find(cell)
break
else:
# If the active column is full or not playable, find the next available column
active_column = find_next_unwon_column()
if active_column != -1:
update_stating_labels() # Recursively update labels and focus
func _process(_delta: float) -> void:
for button in focusable_buttons:
button_hovered(button)
func start_tween(object: Object, property: String, final_val: Variant, duration: float):
var tween = create_tween()
tween.tween_property(object, property, final_val, duration)
func button_hovered(button: Button):
button.pivot_offset = button.size / 2
if button.is_hovered() or button.has_focus():
start_tween(button, "scale", Vector2.ONE * tween_intensity, tween_duration)
else:
start_tween(button, "scale", Vector2.ONE, tween_duration)
func _connect_button(button: Button, handler: String):
if button and !button.is_connected("pressed", Callable(self, handler)):
button.connect("pressed", Callable(self, handler))
else:
print(button.name + " not found or already connected.")
# Function to save stats
func load_stats() -> Dictionary:
var file_path = "user://Stats.cfg"
if not FileAccess.file_exists(file_path):
print("Stats file does not exist. Initializing with default values.")
return {
"Ultimate_Tic_Tac_Toe_Yourself_Won": 0,
"Ultimate_Tic_Tac_Toe_Yourself_Lost": 0,
"Ultimate_Tic_Tac_Toe_AI_Won": 0,
"Ultimate_Tic_Tac_Toe_AI_Lost": 0,
"Simple_Tic_Tac_Toe_AI_Won": 0,
"Simple_Tic_Tac_Toe_Won": 0,
"Simple_Tic_Tac_Toe_AI_Lost": 0,
"Simple_Tic_Tac_Toe_Lost": 0
}
var file = FileAccess.open(file_path, FileAccess.READ)
if file:
var local_stats = {} # Renamed the local variable
while not file.eof_reached():
var line = file.get_line().strip_edges()
var parts = line.split("=")
if parts.size() == 2:
local_stats[parts[0]] = int(parts[1]) # Convert the value to an int
file.close()
return local_stats # Return the renamed variable
else:
print("Failed to open file for reading.")
return {}
func update_stats(is_win: bool, player: String):
print("Updating stats - is_win:", is_win, "player:", player) # Debugging output
# Ensure the necessary keys are present in the stats dictionary
if not stats.has("Ultimate_Tic_Tac_Toe_AI_Won"):
stats["Ultimate_Tic_Tac_Toe_AI_Won"] = 0
if not stats.has("Ultimate_Tic_Tac_Toe_AI_Lost"):
stats["Ultimate_Tic_Tac_Toe_AI_Lost"] = 0
# Update stats based on win/loss and player
if player == "X":
if is_win:
stats["Ultimate_Tic_Tac_Toe_AI_Won"] += 1
elif player == "O":
if is_win:
stats["Ultimate_Tic_Tac_Toe_AI_Lost"] += 1
save_stats(stats)
func save_stats(new_stats: Dictionary) -> void:
var file_path = "user://Stats.cfg"
var file = FileAccess.open(file_path, FileAccess.WRITE)
if file:
for key in new_stats.keys():
var line = key + "=" + str(new_stats[key]) # Create the line for each key-value pair
file.store_line(line) # Store the line in the file
file.close()
else:
print("Failed to open file for writing.")
#handler for cells 1-81
func _on_AICell_pressed(column_index: int, cell_index: int) -> void:
if current_player != "X" or overall_winner != "" or (active_column != -1 and column_index != active_column) or not is_column_playable(column_index):
print("Invalid move attempt")
return
var cell: Button = get_node("GridContainerColumn" + str(column_index + 1)).get_child(cell_index)
if cell.text == "":
make_move(cell, column_index, cell_index)
func make_move(cell: Button, column_index: int, _cell_index: int):
cell.text = current_player
cell.add_theme_font_size_override("font_size", 60) # Makes the X larger
print("Player X moved")
stating_labels[column_index].visible = false
# Update active_column to the column the player just moved in
active_column = column_index
if check_winner(column_index, current_player):
small_board_wins[column_index] = current_player
update_column_win_label(column_index)
lock_column(column_index)
if check_overall_winner():
display_winner(current_player)
lock_game()
return
if is_column_full(column_index):
tie_labels[column_index].visible = true
lock_column(column_index)
# Switch to AI's turn
current_player = "O"
is_ai_turn = true
$XIsPlaying.visible = false
$OIsPlaying.visible = true
print("Triggering AI turn")
call_deferred("trigger_ai_turn")
func trigger_ai_turn():
print("AI turn started")
var ai_column = await ai_turn()
print("AI turn completed, played in column: ", ai_column + 1)
# Recheck valid columns after AI's turn
active_column = find_next_unwon_column()
update_stating_labels()
# If the AI won the game, we don't need to continue
if overall_winner != "":
return
# If the AI played in the same column as the player, we need to find a new active column
if ai_column == -1 or not is_column_playable(ai_column):
active_column = find_next_unwon_column()
update_stating_labels()
# Switch back to player's turn
current_player = "X"
is_ai_turn = false
$XIsPlaying.visible = true
$OIsPlaying.visible = false
func find_next_unwon_column() -> int:
var columns = [0, 1, 2, 3, 4, 5, 6, 7, 8]
columns.shuffle()
for i in columns:
if is_column_playable(i):
return i
return -1
func is_column_full(column_index: int) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
for i in range(9):
var cell: Button = grid_container.get_child(i)
if cell.text == "":
return false # Return false if any cell is empty
return true # Return true if all cells are filled
func update_column_win_label(column_index: int) -> void:
# Show the appropriate win label for the column
if small_board_wins[column_index] == "X":
x_win_labels[column_index].visible = true
elif small_board_wins[column_index] == "O":
o_win_labels[column_index].visible = true
func lock_column(column_index: int) -> void:
# Ensure the column index is valid (0-8 for 1-9 in the UI)
if column_index < 0 or column_index >= 9:
return
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
for i in range(9):
var cell: Button = grid_container.get_child(i)
cell.disabled = true # Lock the buttons in this column
func lock_game() -> void:
for column_index in range(9): # Only loop through valid column indices (0-8)
lock_column(column_index) # Lock all columns
func ai_turn() -> int:
print("AI turn function called")
if current_player != "O" or overall_winner != "":
print("AI turn aborted: not O's turn or game over")
return -1
await get_tree().create_timer(0.35).timeout # Delay for AI's move
var column_to_play = find_valid_column_for_ai()
print("AI choosing column: ", column_to_play + 1)
if column_to_play == -1:
print("No valid moves available. Game might be over.")
check_for_overall_tie()
return -1
var move_made = false
match ai_difficulty:
"Easy":
move_made = play_easy_move(column_to_play)
"Medium":
move_made = play_medium_move(column_to_play)
"Hard":
move_made = play_hard_move(column_to_play)
if !move_made:
print("AI failed to make a move")
return -1
print("AI played in column: ", column_to_play + 1)
# Check if AI wins the small board
if check_winner(column_to_play, "O"):
small_board_wins[column_to_play] = "O"
update_column_win_label(column_to_play)
lock_column(column_to_play)
if check_overall_winner():
display_winner("O")
lock_game()
return column_to_play
# Switch turn to player
current_player = "X"
is_ai_turn = false
$XIsPlaying.visible = true
$OIsPlaying.visible = false
# Update active column for the player's next move
active_column = find_next_unwon_column()
update_stating_labels()
return column_to_play
func play_easy_move(column_index: int) -> bool:
return play_random_move(column_index)
func play_medium_move(column_index: int) -> bool:
if can_win(column_index, "O"):
return take_winning_move(column_index)
elif block_player(column_index):
return true
else:
return play_random_move(column_index)
func play_hard_move(column_index: int) -> bool:
if can_win(column_index, "O"):
return take_winning_move(column_index)
elif block_player(column_index):
return true
elif can_create_fork(column_index, "O"):
return create_fork(column_index, "O")
elif can_block_fork(column_index):
return create_fork(column_index, "O") # Block fork by creating our own fork
elif can_play_center(column_index):
return play_center(column_index)
elif can_play_opposite_corner(column_index):
return play_opposite_corner(column_index)
elif can_play_empty_corner(column_index):
return play_empty_corner(column_index)
elif can_play_empty_side(column_index):
return play_empty_side(column_index)
else:
return play_random_move(column_index)
func take_winning_move(column_index: int) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
for i in range(9):
var cell: Button = grid_container.get_child(i)
if cell.text == "":
cell.text = "O" # AI makes the winning move
return true
return false
func block_player(column_index: int) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
for i in range(9):
var cell: Button = grid_container.get_child(i)
if cell.text == "":
if can_win(column_index, "X"): # Check if player can win
cell.text = "O" # Block the player
return true # Block successful
return false # No blocking move necessary
func play_random_move(column_index: int) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
var empty_cells = []
for i in range(9):
var cell: Button = grid_container.get_child(i)
if cell.text == "":
empty_cells.append(cell) # Add empty cells to the list
if empty_cells.size() > 0:
var random_cell: Button = empty_cells[randi() % empty_cells.size()]
random_cell.text = "O" # AI plays randomly
return true
return false
func check_for_overall_tie() -> void:
for i in range(9):
if is_column_playable(i):
return # If any column is playable, the game is not a tie
# If we've reached here, no columns are playable
display_winner("Tie")
lock_game()
# Function to switch turns
func switch_turn():
current_player = "O" if current_player == "X" else "X"
$XIsPlaying.visible = (current_player == "X")
$OIsPlaying.visible = (current_player == "O")
# Call this function each time a turn is completed
func _on_turn_completed():
switch_turn()
func check_winner(column_index: int, player: String) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
print("Checking winner for player: ", player)
# Check rows
for i in range(3):
if grid_container.get_child(i * 3).text == player and \
grid_container.get_child(i * 3 + 1).text == player and \
grid_container.get_child(i * 3 + 2).text == player:
return true
# Check columns
for i in range(3):
if grid_container.get_child(i).text == player and \
grid_container.get_child(i + 3).text == player and \
grid_container.get_child(i + 6).text == player:
return true
# Check diagonals
if (grid_container.get_child(0).text == player and \
grid_container.get_child(4).text == player and \
grid_container.get_child(8).text == player) or \
(grid_container.get_child(2).text == player and \
grid_container.get_child(4).text == player and \
grid_container.get_child(6).text == player):
return true
return false
func check_overall_winner() -> bool:
for player in ["X", "O"]:
# Check rows
for i in range(3):
if small_board_wins[i * 3] == player and \
small_board_wins[i * 3 + 1] == player and \
small_board_wins[i * 3 + 2] == player:
return true
# Check columns
for i in range(3):
if small_board_wins[i] == player and \
small_board_wins[i + 3] == player and \
small_board_wins[i + 6] == player:
return true
# Check diagonals
if (small_board_wins[0] == player and \
small_board_wins[4] == player and \
small_board_wins[8] == player) or \
(small_board_wins[2] == player and \
small_board_wins[4] == player and \
small_board_wins[6] == player):
return true
return false
func display_winner(player: String) -> void:
if player == "Tie":
winner_label.text = "It's a Tie!"
else:
# Update stats for the winner and loser
if player == "X":
update_stats(true, "X") # Player wins
update_stats(false, "O") # AI loses
else:
update_stats(false, "X") # Player loses
update_stats(true, "O") # AI wins
# Show the appropriate win label for the overall winner
for i in range(9):
if small_board_wins[i] == player:
if player == "X":
x_win_labels[i].visible = true
else:
o_win_labels[i].visible = true
winner_label.text = player + " wins!"
print(winner_label.text) # Outputs the result to the console
winner_label.visible = true
ai_home_button.visible = true # Show the AIHomeButton when a player wins
ai_rematch_button.visible = true # Make the rematch button visible
# Move focus to the appropriate button based on the winner
if player == "X":
ai_rematch_button.grab_focus() # Focus on rematch button for X
else:
ai_home_button.grab_focus() # Focus on home button for O
reset_game_state()
func reset_game_state() -> void:
current_player = "X" # Reset current player
small_board_wins = [null, null, null, null, null, null, null, null, null] # Reset small board wins
overall_winner = "" # Reset overall winner
# AI Strategies
func can_win(column_index: int, player: String) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
for i in range(9):
var cell: Button = grid_container.get_child(i)
if cell.text == "":
cell.text = player # Try to make a move for the current player
if check_winner(column_index, player): # Pass the player as an argument
cell.text = "" # Reset move
return true # Winning move found
cell.text = "" # Reset move
return false # No winning move found
func reset_game() -> void:
# Reset game state
small_board_wins = [null, null, null, null, null, null, null, null, null]
overall_winner = ""
# Randomly decide who goes first
player_goes_first = randf() < 0.5
current_player = "X" if player_goes_first else "O"
# Update UI accordingly
$XIsPlaying.visible = player_goes_first
$OIsPlaying.visible = !player_goes_first
# Clear all cell texts and other resets
for column_index in range(1, 10):
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index))
for cell_index in range(9):
var cell: Button = grid_container.get_child(cell_index)
cell.text = "" # Clear the cell text
cell.disabled = false # Enable the button again
winner_label.visible = false
ai_home_button.visible = false
ai_rematch_button.visible = false
# Hide all win labels and tie labels
for label in x_win_labels:
label.visible = false
for label in o_win_labels:
label.visible = false
for label in tie_labels:
label.visible = false
# If AI goes first, trigger its turn
if current_player == "O":
call_deferred("ai_turn")
func _on_aihomebutton_pressed() -> void:
$Button10ClickPlayer.play() # Play the button click sound
await get_tree().create_timer(0.1).timeout # Wait for a short duration
print("AI Home button clicked") # Log button click to the console
Transition.load_scene("res://Scenes/UI.tscn")
func _on_miniboardhomepage_pressed() -> void:
$Button10ClickPlayer.play() # Play the button click sound
await get_tree().create_timer(0.1).timeout # Wait for a short duration
print("Mini Board Home button clicked") # Log button click to the console
Transition.load_scene("res://Scenes/UI.tscn")
func _on_airematchultimatebutton_pressed() -> void:
$Button10ClickPlayer.play() # Play the button click sound
await get_tree().create_timer(0.1).timeout # Wait for a short duration
print("AI Rematch Ultimate button clicked") # Log button click to the console
reset_game() # Call your reset function
ai_rematch_button.visible = false # Hide the rematch button after it's clicked
func can_create_fork(column_index: int, player: String) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
var fork_opportunities = 0
for i in range(9):
if grid_container.get_child(i).text == "":
grid_container.get_child(i).text = player
if count_winning_lines(column_index, player) >= 2:
fork_opportunities += 1
grid_container.get_child(i).text = ""
return fork_opportunities >= 2
func create_fork(column_index: int, player: String) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
for i in range(9):
if grid_container.get_child(i).text == "":
grid_container.get_child(i).text = player
if count_winning_lines(column_index, player) >= 2:
return true
grid_container.get_child(i).text = ""
return false
func can_block_fork(column_index: int) -> bool:
return can_create_fork(column_index, "X")
func block_fork(column_index: int) -> bool:
return create_fork(column_index, "O")
func can_play_center(column_index: int) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
return grid_container.get_child(4).text == ""
func play_center(column_index: int) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
if grid_container.get_child(4).text == "":
grid_container.get_child(4).text = "O"
return true
return false
func can_play_opposite_corner(column_index: int) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
var corners = [0, 2, 6, 8]
for i in corners:
if grid_container.get_child(i).text == "X" and grid_container.get_child(8 - i).text == "":
return true
return false
func play_opposite_corner(column_index: int) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
var corners = [0, 2, 6, 8]
for i in corners:
if grid_container.get_child(i).text == "X" and grid_container.get_child(8 - i).text == "":
grid_container.get_child(8 - i).text = "O"
return true
return false
func can_play_empty_corner(column_index: int) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
var corners = [0, 2, 6, 8]
for i in corners:
if grid_container.get_child(i).text == "":
return true
return false
func play_empty_corner(column_index: int) -> bool:
var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
var corners = [0, 2, 6, 8]
for i in corners:
if grid_container.get_child(i).text == "":
grid_container.get_child(i).text = "O"
return true
return false
Any help would be very much appreciated, let me know if you need anything specific, thank you, have a great day!
Also had an error so sending rest of code in reply