(Stats Tracking Wins and Not losses, adding a point to wins instead of losses)

Godot Version

Godot 4.3

Question

Hello, it's me again.... sorry i ask so many questions lol but basically My stats are starting to work, it tracks wins, but when I lose, it adds a point to wins and not to loses... Any ideas?

Here is the video to show:


StatsPopUp.tscn SceneTree
image

Here is miniboard.gd (The game that updates when I lose or win (ultimate tic tac toe)

extends Control  # Change this to the appropriate base class, if needed


var current_player = "X"  # Keep track of the current player
var cells = []  # Store references to buttons
var small_board_wins = []  # Track wins for small boards
var overall_winner = ""  # Track overall winner
var is_initialized = false  # Track if the board is initialized
var stats: Dictionary = load_stats()  # Load or initialize stats at the start

@onready var winner_label = $WinnerLabel  # General winner label
@onready var home_button = $HomeTownButton  # Reference to the HomeButton
@onready var rematch_button = $RematchYourselfButton  # Reference to the Rematch button

# Declare the variable for your AudioStreamPlayer
var button5_click_player: AudioStreamPlayer = null  # Reference to the AudioStreamPlayer for Button5

# Declare labels for each column
var x_win_labels = []
var o_win_labels = []
var tie_labels = []  # Array to hold tie labels for each column

# 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 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.")

func _ready():
	if is_initialized:  # Prevent re-initialization
		return
	is_initialized = true  # Mark as initialized
	
	stats = load_stats()  # Load existing stats

# Initialize AudioStreamPlayer reference and set the sound stream
	button5_click_player = $Button5ClickPlayer  # Make sure this node exists in the scene
	button5_click_player.stream = load("res://sounds/click.ogg")  # Set the path to your sound file

	cells.clear()
	small_board_wins = [null, null, null, null, null, null, null, null, null]  # Initialize small board wins
	winner_label.visible = false
	home_button.visible = false  # Hide the HomeButton initially
	rematch_button.visible = false  # Hide the Rematch button initially

	# Initialize labels for each column
	for i in range(1, 10):
		# Use 'get_node_safe' or check if the node exists
		var x_label = get_node("XWinLabelColumn" + str(i))
		var o_label = get_node("OWinLabelColumn" + str(i))
		var tie_label = get_node("ItsATieLabelColumn" + str(i))

		if x_label and o_label and tie_label:
			x_win_labels.append(x_label)
			o_win_labels.append(o_label)
			tie_labels.append(tie_label)
			x_win_labels[i - 1].visible = false
			o_win_labels[i - 1].visible = false
			tie_labels[i - 1].visible = false
		else:
			print("One or more labels not found for column: ", i)

	# 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_Cell_pressed").bind(column_index - 1, cell_index))
			
			# Function to connect buttons safely
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 play button click sound
func _play_button_click_sound():
	print("Playing button click sound")  # Debugging statement
	button5_click_player.play()  # Play the button click sound

# Single handler for all Cells (1-81)
func _on_Cell_pressed(column_index: int, cell_index: int) -> void:
	if overall_winner != "":  # Ignore input if the game is won
		return 

	var cell: Button = get_node("GridContainerColumn" + str(column_index + 1)).get_child(cell_index)
	if cell.text == "":  # Ensure cell is empty before marking
		cell.text = current_player  # Set the cell text to the current player
		if check_winner(column_index):  # Check if the current player won the small board
			small_board_wins[column_index] = current_player  # Mark the small board as won
			update_column_win_label(column_index)  # Update the specific win label
			lock_column(column_index)  # Lock the column after winning
			if check_overall_winner():  # Check for overall winner
				display_winner(current_player)  # Display the overall winner
				lock_game()  # Lock the entire game
				return  # Ensure we exit after declaring the winner

		if is_column_full(column_index):  # Check if the column is full and no winner
			tie_labels[column_index].visible = true  # Show the tie label for the column
			lock_column(column_index)  # Lock the column as it's full

		current_player = "O" if current_player == "X" else "X"  # Switch player
		
func update_stats(is_win: bool, player: String):
	# Ensure the necessary keys are present in the stats dictionary
	if not stats.has("Ultimate_Tic_Tac_Toe_Yourself_Won"):
		stats["Ultimate_Tic_Tac_Toe_Yourself_Won"] = 0  # Initialize wins for Player X
	if not stats.has("Ultimate_Tic_Tac_Toe_Yourself_Lost"):
		stats["Ultimate_Tic_Tac_Toe_Yourself_Lost"] = 0  # Initialize losses for Player X

	# Update stats logic
	if player == "X":  # Assuming "X" is the player
		if is_win:
			stats["Ultimate_Tic_Tac_Toe_Yourself_Won"] += 1  # Increment wins for Player X
		else:
			stats["Ultimate_Tic_Tac_Toe_Yourself_Lost"] += 1  # Increment losses for Player X

	save_stats(stats)  # Save the updated stats

func display_winner(player: String) -> void:
	if player == "X":
		update_stats(true, player)  # Player wins
		update_stats(false, "O")  # AI loses
	else:
		update_stats(false, player)  # Player loses
		update_stats(true, "X")  # AI wins

	# Other display logic remains the same
	for label in x_win_labels:
		label.visible = false
	for label in o_win_labels:
		label.visible = false
	
	# Show the general winner label
	winner_label.text = player + " wins!"
	winner_label.visible = true
	home_button.visible = true
	rematch_button.visible = true

	# Call reset game state to prepare for the next game
	reset_game_state()

func end_game(is_player_win: bool):
	if is_player_win:  # If the player won
		update_stats(true, "X")  # Call with is_win true
	else:  # Player lost
		update_stats(false, "X")  # Call with is_win false 


# Update loss stats if the AI (or "O") wins
func update_stats_loss():
	if current_player == "O":  # Update loss if "O" wins
		stats["Ultimate_Tic_Tac_Toe_Yourself_Lost"] += 1
	save_stats(stats)  # Pass the updated stats dictionary

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


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)

func check_winner(column_index: int) -> bool:
	var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
	for i in range(3):
		if grid_container.get_child(i * 3).text == current_player and \
		   grid_container.get_child(i * 3 + 1).text == current_player and \
		   grid_container.get_child(i * 3 + 2).text == current_player:
			return true
	
	for i in range(3):
		if grid_container.get_child(i).text == current_player and \
		   grid_container.get_child(i + 3).text == current_player and \
		   grid_container.get_child(i + 6).text == current_player:
			return true
	
	return false

func check_overall_winner() -> bool:
	for i in range(3):
		if (small_board_wins[i * 3] == current_player and \
			small_board_wins[i * 3 + 1] == current_player and \
			small_board_wins[i * 3 + 2] == current_player) or \
		   (small_board_wins[i] == current_player and \
			small_board_wins[i + 3] == current_player and \
			small_board_wins[i + 6] == current_player):
			return true
	if (small_board_wins[0] == current_player and \
		small_board_wins[4] == current_player and \
		small_board_wins[8] == current_player) or \
	   (small_board_wins[2] == current_player and \
		small_board_wins[4] == current_player and \
		small_board_wins[6] == current_player):
		return true
	return false


func _on_hometown_button_pressed() -> void:
	button5_click_player.play()  # Play the button click sound
	print("HomeButton pressed")
	await get_tree().create_timer(0.1).timeout  # Add a delay
	get_tree().change_scene_to_file("res://UI.tscn")  # Update with your actual main menu scene path

func _on_minihomepage_pressed() -> void:
	button5_click_player.play()  # Play the button click sound
	print("MiniHomepage pressed")
	await get_tree().create_timer(0.1).timeout  # Add a delay
	get_tree().change_scene_to_file("res://UI.tscn")  # Update with your actual main menu scene path

func _on_rematchyourselfbutton_pressed() -> void:
	button5_click_player.play()  # Play the button click sound
	print("Rematch button pressed")
	await get_tree().create_timer(0.1).timeout  # Add a delay
	# Call functions to reset the game
	clear_board()
	reset_labels()
	reset_game_state()
	rematch_button.visible = false  # Hide the rematch button after pressing it
	home_button.visible = false # hide after pressed


func clear_board() -> void:
	for column_index in range(9):
		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.text = ""
			cell.disabled = false  # Re-enable the cells

func reset_labels() -> void:
	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
	winner_label.visible = false  # Hide the winner label

StatsPopUp.gd (if needed, just to show what the stats are.)

extends Popup

var stats: Dictionary = {}  # To store the stats
var stats_file_path = "user://Stats.cfg"  # Use consistent filename

func _ready():
	load_stats()  # Load stats when ready
	display_stats()  # Display stats on the label

	# Connect the reset button signal if not already connected
	if not $ResetButton.is_connected("pressed", Callable(self, "_on_ResetButton_pressed")):
		$ResetButton.connect("pressed", Callable(self, "_on_ResetButton_pressed"))

func load_stats():
	var file = FileAccess.open(stats_file_path, FileAccess.READ)  # Use consistent file name
	if file:
		stats.clear()  # Clear current stats before loading new ones
		while not file.eof_reached():
			var line = file.get_line()
			if line.begins_with("["):
				continue  # Skip section headers
			var key_value = line.split("=")
			if key_value.size() == 2:
				stats[key_value[0].strip_edges()] = int(key_value[1].strip_edges())
		file.close()
	else:
		print("Failed to open stats file for reading.")

func display_stats():
	var stats_text = "--WON--\n"
	stats_text += "Ultimate Tic Tac Toe AI Won: %d\n" % stats.get("Ultimate_Tic_Tac_Toe_AI_Won", 0)
	stats_text += "Ultimate Tic Tac Toe Yourself Won: %d\n" % stats.get("Ultimate_Tic_Tac_Toe_Yourself_Won", 0)
	stats_text += "Simple Tic Tac Toe AI Won: %d\n" % stats.get("Simple_Tic_Tac_Toe_AI_Won", 0)
	stats_text += "Simple Tic Tac Toe Won: %d\n\n" % stats.get("Simple_Tic_Tac_Toe_Won", 0)
	stats_text += "--LOST--\n"
	stats_text += "Ultimate Tic Tac Toe AI Lost: %d\n" % stats.get("Ultimate_Tic_Tac_Toe_AI_Lost", 0)
	stats_text += "Ultimate Tic Tac Toe Yourself Lost: %d\n" % stats.get("Ultimate_Tic_Tac_Toe_Yourself_Lost", 0)
	stats_text += "Simple Tic Tac Toe AI Lost: %d\n" % stats.get("Simple_Tic_Tac_Toe_AI_Lost", 0)
	stats_text += "Simple Tic Tac Toe Lost: %d\n" % stats.get("Simple_Tic_Tac_Toe_Lost", 0)

	$StatsLabel.text = stats_text  # Assuming you have a Label node named StatsLabel

func _on_CloseButton_pressed():
	queue_free()  # Close the popup when button is pressed

func _on_ResetButton_pressed():
	reset_stats()  # Call the reset_stats function

func reset_stats():
	# Reset all values in the dictionary to 0
	stats = {
		"Ultimate_Tic_Tac_Toe_AI_Won": 0,
		"Ultimate_Tic_Tac_Toe_Yourself_Won": 0,
		"Simple_Tic_Tac_Toe_AI_Won": 0,
		"Simple_Tic_Tac_Toe_Won": 0,
		"Ultimate_Tic_Tac_Toe_AI_Lost": 0,
		"Ultimate_Tic_Tac_Toe_Yourself_Lost": 0,
		"Simple_Tic_Tac_Toe_AI_Lost": 0,
		"Simple_Tic_Tac_Toe_Lost": 0
	}
	save_stats()  # Save the reset stats back to file
	display_stats()  # Refresh the display after reset

func save_stats():
	# Write current stats to the stats file
	var file = FileAccess.open(stats_file_path, FileAccess.WRITE)  # Use WRITE to overwrite
	if file:
		for key in stats.keys():
			file.store_line("%s=%d" % [key, stats[key]])
		file.close()
	else:
		print("Failed to open stats file for writing.")

Any help would be very appreciated, thank you so much! :slight_smile:

when exactly will this function be executed?


and try to debug this function:

print(is_win, player) If you lose, what are the values ​​of these variables?

func update_stats(is_win: bool, player: String):
	# Ensure the necessary keys are present in the stats dictionary
	if not stats.has("Ultimate_Tic_Tac_Toe_Yourself_Won"):
		stats["Ultimate_Tic_Tac_Toe_Yourself_Won"] = 0  # Initialize wins for Player X
	if not stats.has("Ultimate_Tic_Tac_Toe_Yourself_Lost"):
		stats["Ultimate_Tic_Tac_Toe_Yourself_Lost"] = 0  # Initialize losses for Player X

	# Update stats logic
	if player == "X":  # Assuming "X" is the player
		if is_win:
			stats["Ultimate_Tic_Tac_Toe_Yourself_Won"] += 1  # Increment wins for Player X
		else:
			stats["Ultimate_Tic_Tac_Toe_Yourself_Lost"] += 1  #
1 Like

thank you so much for responding and trying to help me! So basically, I did what you said and debugged it, When “X” wins it outputs:
trueX
falseO

And when “O” wins it outputs:
falseO
trueX

I did delete update_stats_loss because it basically did absolutely nothing, still ran the same when functioned without it… And it still will update 1 point to win whenever you lose (which is not good.)

BUT THE WIN works perfectly fine (updating 1 point to win, when you win!)

here is update_stats in miniboard.gd for u to reference:

func update_stats(is_win: bool, player: String):
	print(is_win, player) # Debugging output
	# Ensure the necessary keys are present in the stats dictionary
	if not stats.has("Ultimate_Tic_Tac_Toe_Yourself_Won"):
		stats["Ultimate_Tic_Tac_Toe_Yourself_Won"] = 0
	if not stats.has("Ultimate_Tic_Tac_Toe_Yourself_Lost"):
		stats["Ultimate_Tic_Tac_Toe_Yourself_Lost"] = 0

	# Update stats logic
	if player == "X":
		if is_win:
			stats["Ultimate_Tic_Tac_Toe_Yourself_Won"] += 1
		else:
			stats["Ultimate_Tic_Tac_Toe_Yourself_Lost"] += 1

	save_stats(stats)

Is “Yourself” always “X”? And “AI” is always “O”?

So if “O” wins, then the function is executed twice?

  1. is_win = false for player = “O”
  2. is_win = true for player “X” → it adds a point to wins and not to loses...

  1. is then the bug
	if player == "X":
		if is_win:
			stats["Ultimate_Tic_Tac_Toe_Yourself_Won"] += 1
1 Like

Yes, so basically there are two options to play, AI or yourself, like local multiplayer on the same screen, you click one, someone else on the same screen clicks it… But yes “X” always starts first and “O” always goes next, and in terms of AI “X” is me, “O” is AI.

And for some odd reason it outputs that when I lose, it outputs that I win in the stats. Here’s some picture examples:



image
See the winning part works perfectly fine with no issues…
But as soon as “O” wins:
image
image

Here is miniboard.gd for referencing:

extends Control  # Change this to the appropriate base class, if needed


var current_player = "X"  # Keep track of the current player
var cells = []  # Store references to buttons
var small_board_wins = []  # Track wins for small boards
var overall_winner = ""  # Track overall winner
var is_initialized = false  # Track if the board is initialized
var stats: Dictionary = load_stats()  # Load or initialize stats at the start

@onready var winner_label = $WinnerLabel  # General winner label
@onready var home_button = $HomeTownButton  # Reference to the HomeButton
@onready var rematch_button = $RematchYourselfButton  # Reference to the Rematch button

# Declare the variable for your AudioStreamPlayer
var button5_click_player: AudioStreamPlayer = null  # Reference to the AudioStreamPlayer for Button5

# Declare labels for each column
var x_win_labels = []
var o_win_labels = []
var tie_labels = []  # Array to hold tie labels for each column

# 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 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.")

func _ready():
	if is_initialized:  # Prevent re-initialization
		return
	is_initialized = true  # Mark as initialized
	
	stats = load_stats()  # Load existing stats

# Initialize AudioStreamPlayer reference and set the sound stream
	button5_click_player = $Button5ClickPlayer  # Make sure this node exists in the scene
	button5_click_player.stream = load("res://sounds/click.ogg")  # Set the path to your sound file

	cells.clear()
	small_board_wins = [null, null, null, null, null, null, null, null, null]  # Initialize small board wins
	winner_label.visible = false
	home_button.visible = false  # Hide the HomeButton initially
	rematch_button.visible = false  # Hide the Rematch button initially

	# Initialize labels for each column
	for i in range(1, 10):
		# Use 'get_node_safe' or check if the node exists
		var x_label = get_node("XWinLabelColumn" + str(i))
		var o_label = get_node("OWinLabelColumn" + str(i))
		var tie_label = get_node("ItsATieLabelColumn" + str(i))

		if x_label and o_label and tie_label:
			x_win_labels.append(x_label)
			o_win_labels.append(o_label)
			tie_labels.append(tie_label)
			x_win_labels[i - 1].visible = false
			o_win_labels[i - 1].visible = false
			tie_labels[i - 1].visible = false
		else:
			print("One or more labels not found for column: ", i)

	# 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_Cell_pressed").bind(column_index - 1, cell_index))
			
			# Function to connect buttons safely
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 play button click sound
func _play_button_click_sound():
	print("Playing button click sound")  # Debugging statement
	button5_click_player.play()  # Play the button click sound

# Single handler for all Cells (1-81)
func _on_Cell_pressed(column_index: int, cell_index: int) -> void:
	if overall_winner != "":  # Ignore input if the game is won
		return 

	var cell: Button = get_node("GridContainerColumn" + str(column_index + 1)).get_child(cell_index)
	if cell.text == "":  # Ensure cell is empty before marking
		cell.text = current_player  # Set the cell text to the current player
		if check_winner(column_index):  # Check if the current player won the small board
			small_board_wins[column_index] = current_player  # Mark the small board as won
			update_column_win_label(column_index)  # Update the specific win label
			lock_column(column_index)  # Lock the column after winning
			if check_overall_winner():  # Check for overall winner
				display_winner(current_player)  # Display the overall winner
				lock_game()  # Lock the entire game
				return  # Ensure we exit after declaring the winner

		if is_column_full(column_index):  # Check if the column is full and no winner
			tie_labels[column_index].visible = true  # Show the tie label for the column
			lock_column(column_index)  # Lock the column as it's full

		current_player = "O" if current_player == "X" else "X"  # Switch player
		
func update_stats(is_win: bool, player: String):
	print(is_win, player) # Debugging output
	# Ensure the necessary keys are present in the stats dictionary
	if not stats.has("Ultimate_Tic_Tac_Toe_Yourself_Won"):
		stats["Ultimate_Tic_Tac_Toe_Yourself_Won"] = 0
	if not stats.has("Ultimate_Tic_Tac_Toe_Yourself_Lost"):
		stats["Ultimate_Tic_Tac_Toe_Yourself_Lost"] = 0

	# Update stats based on win/loss and player
	if player == "X":
		if is_win:
			stats["Ultimate_Tic_Tac_Toe_Yourself_Won"] += 1
	elif player == "O":
		if is_win:
			stats["Ultimate_Tic_Tac_Toe_Yourself_Lost"] += 1

	save_stats(stats)

func display_winner(player: String) -> void:
	if player == "X":
		update_stats(true, player)  # Player wins
		update_stats(false, "O")  # AI loses
	else:
		update_stats(false, player)  # Player loses
		update_stats(true, "X")  # AI wins

	# Other display logic remains the same
	for label in x_win_labels:
		label.visible = false
	for label in o_win_labels:
		label.visible = false
	
	# Show the general winner label
	winner_label.text = player + " wins!"
	winner_label.visible = true
	home_button.visible = true
	rematch_button.visible = true

	# Call reset game state to prepare for the next game
	reset_game_state()

func end_game(is_player_win: bool):
	if is_player_win:  # If the player won
		update_stats(true, "X")  # Call with is_win true
	else:  # Player lost
		update_stats(false, "X")  # Call with is_win false 

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


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)

func check_winner(column_index: int) -> bool:
	var grid_container: GridContainer = get_node("GridContainerColumn" + str(column_index + 1))
	for i in range(3):
		if grid_container.get_child(i * 3).text == current_player and \
		   grid_container.get_child(i * 3 + 1).text == current_player and \
		   grid_container.get_child(i * 3 + 2).text == current_player:
			return true
	
	for i in range(3):
		if grid_container.get_child(i).text == current_player and \
		   grid_container.get_child(i + 3).text == current_player and \
		   grid_container.get_child(i + 6).text == current_player:
			return true
	
	return false

func check_overall_winner() -> bool:
	for i in range(3):
		if (small_board_wins[i * 3] == current_player and \
			small_board_wins[i * 3 + 1] == current_player and \
			small_board_wins[i * 3 + 2] == current_player) or \
		   (small_board_wins[i] == current_player and \
			small_board_wins[i + 3] == current_player and \
			small_board_wins[i + 6] == current_player):
			return true
	if (small_board_wins[0] == current_player and \
		small_board_wins[4] == current_player and \
		small_board_wins[8] == current_player) or \
	   (small_board_wins[2] == current_player and \
		small_board_wins[4] == current_player and \
		small_board_wins[6] == current_player):
		return true
	return false


func _on_hometown_button_pressed() -> void:
	button5_click_player.play()  # Play the button click sound
	print("HomeButton pressed")
	await get_tree().create_timer(0.1).timeout  # Add a delay
	get_tree().change_scene_to_file("res://UI.tscn")  # Update with your actual main menu scene path

func _on_minihomepage_pressed() -> void:
	button5_click_player.play()  # Play the button click sound
	print("MiniHomepage pressed")
	await get_tree().create_timer(0.1).timeout  # Add a delay
	get_tree().change_scene_to_file("res://UI.tscn")  # Update with your actual main menu scene path

func _on_rematchyourselfbutton_pressed() -> void:
	button5_click_player.play()  # Play the button click sound
	print("Rematch button pressed")
	await get_tree().create_timer(0.1).timeout  # Add a delay
	# Call functions to reset the game
	clear_board()
	reset_labels()
	reset_game_state()
	rematch_button.visible = false  # Hide the rematch button after pressing it
	home_button.visible = false # hide after pressed


func clear_board() -> void:
	for column_index in range(9):
		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.text = ""
			cell.disabled = false  # Re-enable the cells

func reset_labels() -> void:
	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
	winner_label.visible = false  # Hide the winner label

let me know if u want other scripts or scene trees…

I have been experimenting with it left and right and idk where it’s doing it… But also thank you so much for helping me! :slight_smile:

func display_winner(player: String) -> void:
	if player == "X":
		update_stats(true, player)  # Player wins
		update_stats(false, "O")  # AI loses
	else:
		update_stats(false, player)  # Player loses
		update_stats(true, "X")  # AI wins

update_stats(true, "X") # AI wins

this line is then wrong?

1 Like

yep… that was it! Thank you so much… i didnt even realize that at all :sob:
but again thank you for helping me, i appreciate it! :smile:

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.