219 lines
4.8 KiB
Plaintext
219 lines
4.8 KiB
Plaintext
|
extends Control
|
||
|
|
||
|
# DATA
|
||
|
# Holds board data such as x, o, and unmarked
|
||
|
var board : Array
|
||
|
|
||
|
# State of player, X or O
|
||
|
var player : String
|
||
|
|
||
|
# State for a winner or not
|
||
|
var is_winner: bool = false
|
||
|
|
||
|
# State for game over or not
|
||
|
var is_gameover: bool = false
|
||
|
|
||
|
# State for draw/tie or not
|
||
|
var is_draw: bool = false
|
||
|
|
||
|
# LOAD IMAGE FILES
|
||
|
# Button unpressed
|
||
|
var unpressed = preload("res://assets/unpressed-tile.png")
|
||
|
|
||
|
# Button for Player X
|
||
|
var player_x = preload("res://assets/player-x-tile.png")
|
||
|
|
||
|
# Button for Player O
|
||
|
var player_o = preload("res://assets/player-o-tile.png")
|
||
|
|
||
|
# Initiates board/game data
|
||
|
func initiate_board() -> void:
|
||
|
board = [
|
||
|
"0", "0", "0",
|
||
|
"0", "0", "0",
|
||
|
"0", "0", "0"
|
||
|
]
|
||
|
$Board/Row0/Button0.texture_normal = unpressed
|
||
|
$Board/Row0/Button1.texture_normal = unpressed
|
||
|
$Board/Row0/Button2.texture_normal = unpressed
|
||
|
$Board/Row1/Button3.texture_normal = unpressed
|
||
|
$Board/Row1/Button4.texture_normal = unpressed
|
||
|
$Board/Row1/Button5.texture_normal = unpressed
|
||
|
$Board/Row2/Button6.texture_normal = unpressed
|
||
|
$Board/Row2/Button7.texture_normal = unpressed
|
||
|
$Board/Row2/Button8.texture_normal = unpressed
|
||
|
is_gameover = false
|
||
|
is_winner = false
|
||
|
is_draw = false
|
||
|
|
||
|
# Initiates a player
|
||
|
func initiate_player() -> void:
|
||
|
player = "x"
|
||
|
|
||
|
# Runs automatically when scene is loaded
|
||
|
func _ready() -> void:
|
||
|
$GameOverMessage.hide()
|
||
|
initiate_board()
|
||
|
initiate_player()
|
||
|
|
||
|
# Next player's turn
|
||
|
func update_player() -> void:
|
||
|
if player == "x":
|
||
|
player = "o"
|
||
|
else:
|
||
|
player = "x"
|
||
|
|
||
|
# Check rows for a match 3
|
||
|
func is_row_matched() -> bool:
|
||
|
var offset = 0
|
||
|
for row in range(3):
|
||
|
for index in range(0 + offset, 3 + offset):
|
||
|
if board[index] == player:
|
||
|
is_winner = true
|
||
|
else:
|
||
|
is_winner = false
|
||
|
break
|
||
|
if is_winner:
|
||
|
return true
|
||
|
offset += 3
|
||
|
return false
|
||
|
|
||
|
# Check columns for a match 3
|
||
|
func is_col_matched() -> bool:
|
||
|
var offset = 0
|
||
|
for col in range(3):
|
||
|
for index in range(0 + offset, 7 + offset, 3):
|
||
|
if board[index] == player:
|
||
|
is_winner = true
|
||
|
else:
|
||
|
is_winner = false
|
||
|
break
|
||
|
if is_winner:
|
||
|
return true
|
||
|
offset += 1
|
||
|
return false
|
||
|
|
||
|
# Check diagonals for a match 3
|
||
|
func is_diag_matched() -> bool:
|
||
|
for i in range(0, 9, 4):
|
||
|
if board[i] == player:
|
||
|
is_winner = true
|
||
|
else:
|
||
|
is_winner = false
|
||
|
break
|
||
|
if is_winner:
|
||
|
return true
|
||
|
for i in range(2, 7, 2):
|
||
|
if board[i] == player:
|
||
|
is_winner = true
|
||
|
else:
|
||
|
is_winner = false
|
||
|
break
|
||
|
if is_winner:
|
||
|
return true
|
||
|
return false
|
||
|
|
||
|
# Check if board is full
|
||
|
func is_board_full() -> bool:
|
||
|
if board.has("0"):
|
||
|
return false
|
||
|
return true
|
||
|
|
||
|
# Check for win/draw conditions
|
||
|
func check_gameover() -> void:
|
||
|
if is_row_matched() || is_col_matched() || is_diag_matched():
|
||
|
is_gameover = true
|
||
|
add_gameover_message()
|
||
|
elif is_board_full():
|
||
|
is_gameover = true
|
||
|
is_draw = true
|
||
|
add_gameover_message()
|
||
|
|
||
|
# Show a gameover message
|
||
|
func add_gameover_message() -> void:
|
||
|
if is_draw:
|
||
|
$GameOverMessage/Container/Label.text = "Game is a draw!"
|
||
|
else:
|
||
|
$GameOverMessage/Container/Label.text = "Player " + player + " wins!"
|
||
|
$GameOverMessage.show()
|
||
|
|
||
|
# Mark player's move
|
||
|
func make_move(index: int) -> void:
|
||
|
board[index] = player
|
||
|
check_gameover()
|
||
|
|
||
|
# Check if button/square is free or open
|
||
|
func is_square_free(index: int) -> bool:
|
||
|
if board[index] == "0":
|
||
|
return true
|
||
|
return false
|
||
|
|
||
|
# Update board with X or O button image
|
||
|
func update_board(row: int, index: int) -> void:
|
||
|
var path = "Board/Row" + String(row) + "/Button" + String(index)
|
||
|
if player == "x":
|
||
|
get_node(path).texture_normal = player_x
|
||
|
elif player == "o":
|
||
|
get_node(path).texture_normal = player_o
|
||
|
update_player()
|
||
|
|
||
|
# SIGNALS
|
||
|
# Signal for button 0
|
||
|
func _on_Button0_button_up() -> void:
|
||
|
if is_square_free(0) && !is_gameover:
|
||
|
make_move(0)
|
||
|
update_board(0, 0)
|
||
|
|
||
|
# Signal for button 1
|
||
|
func _on_Button1_button_up() -> void:
|
||
|
if is_square_free(1) && !is_gameover:
|
||
|
make_move(1)
|
||
|
update_board(0, 1)
|
||
|
|
||
|
# Signal for button 2
|
||
|
func _on_Button2_button_up() -> void:
|
||
|
if is_square_free(2) && !is_gameover:
|
||
|
make_move(2)
|
||
|
update_board(0, 2)
|
||
|
|
||
|
# Signal for button 3
|
||
|
func _on_Button3_button_up() -> void:
|
||
|
if is_square_free(3) && !is_gameover:
|
||
|
make_move(3)
|
||
|
update_board(1, 3)
|
||
|
|
||
|
# Signal for button 4
|
||
|
func _on_Button4_button_up() -> void:
|
||
|
if is_square_free(4) && !is_gameover:
|
||
|
make_move(4)
|
||
|
update_board(1, 4)
|
||
|
|
||
|
# Signal for button 5
|
||
|
func _on_Button5_button_up() -> void:
|
||
|
if is_square_free(5) && !is_gameover:
|
||
|
make_move(5)
|
||
|
update_board(1, 5)
|
||
|
|
||
|
# Signal for button 6
|
||
|
func _on_Button6_button_up() -> void:
|
||
|
if is_square_free(6) && !is_gameover:
|
||
|
make_move(6)
|
||
|
update_board(2, 6)
|
||
|
|
||
|
# Signal for button 7
|
||
|
func _on_Button7_button_up() -> void:
|
||
|
if is_square_free(7) && !is_gameover:
|
||
|
make_move(7)
|
||
|
update_board(2, 7)
|
||
|
|
||
|
# Signal for button 8
|
||
|
func _on_Button8_button_up() -> void:
|
||
|
if is_square_free(8) && !is_gameover:
|
||
|
make_move(8)
|
||
|
update_board(2, 8)
|
||
|
|
||
|
# Signal for restart button
|
||
|
func _on_RestartButton_button_up() -> void:
|
||
|
$GameOverMessage.hide()
|
||
|
initiate_board()
|
||
|
initiate_player()
|