Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement in Tic Tac Toe game #920

Merged
merged 1 commit into from
Oct 29, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 72 additions & 37 deletions Game_Development/Tic_Tac_Toe/tic_tac_toe.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import tkinter as tk
from tkinter import messagebox
from tkinter import messagebox, simpledialog
import time
import threading
import winsound # For Windows sound effects

class TicTacToe:
def __init__(self, root):
Expand All @@ -8,37 +11,27 @@ def __init__(self, root):
self.board = [''] * 9
self.current_player = 'X'
self.buttons = []
self.scores = {'X': 0, 'O': 0} # Scoreboard for both players

# Display current player's turn
self.turn_label = tk.Label(self.root, text=f"Player {self.current_player}'s Turn", font='Arial 15')
self.turn_label.grid(row=3, column=0, columnspan=3)

# Add Menu Bar
self.scores = {'X': 0, 'O': 0}
self.player_names = {'X': "Player 1", 'O': "Player 2"}
self.game_start_time = time.time()
self.timer_label = tk.Label(self.root, text="Time: 0s", font='Arial 12')
self.timer_label.grid(row=6, column=0, columnspan=3)
self.running = True
self.create_menu_bar()

# Display score
self.score_label = tk.Label(self.root, text=f"Score: X = {self.scores['X']} | O = {self.scores['O']}", font='Arial 12')
self.score_label.grid(row=4, column=0, columnspan=3)

# Reset Game Button
self.reset_button = tk.Button(self.root, text="Reset Game", font='Arial 12', command=self.reset_board)
self.reset_button.grid(row=5, column=0, columnspan=3)

self.create_buttons()
self.update_turn_label()
self.update_score_label()
self.start_timer()

def create_menu_bar(self):
menu_bar = tk.Menu(self.root)
self.root.config(menu=menu_bar)
game_menu = tk.Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="Settings", menu=game_menu)

# Add New Game option to the menu
game_menu.add_command(label="New Game", command=self.reset_board)

# Add Exit option to the menu
game_menu.add_command(label="Change Players", command=self.change_players)
game_menu.add_separator()
game_menu.add_command(label="Exit", command=self.root.quit)
game_menu.add_command(label="Exit", command=self.quit_game)

def create_buttons(self):
for i in range(3):
Expand All @@ -52,36 +45,46 @@ def create_buttons(self):
row.append(btn)
self.buttons.append(row)

def update_turn_label(self):
self.turn_label = tk.Label(self.root, text=f"{self.player_names[self.current_player]}'s Turn ({self.current_player})", font='Arial 15')
self.turn_label.grid(row=3, column=0, columnspan=3)

def update_score_label(self):
self.score_label = tk.Label(self.root, text=f"Score: {self.player_names['X']} (X) = {self.scores['X']} | {self.player_names['O']} (O) = {self.scores['O']}", font='Arial 12')
self.score_label.grid(row=4, column=0, columnspan=3)

def on_enter(self, event):
button = event.widget
if button['text'] == '':
button['bg'] = '#D3D3D3' # Light grey on hover when empty
button['bg'] = '#D3D3D3' # Light grey on hover

def on_leave(self, event):
button = event.widget
if button['text'] == '':
button['bg'] = 'lightgray' # Reset to normal color when leaving
button['bg'] = 'lightgray'

def make_move(self, idx):
if self.board[idx] == '':
self.play_sound("move")
self.board[idx] = self.current_player
button = self.buttons[idx // 3][idx % 3]
button.config(text=self.current_player, state='disabled', disabledforeground='red' if self.current_player == 'X' else 'blue')


# Check for winner
winner_combination = self.check_winner()
if winner_combination:
self.highlight_winner(winner_combination) #Highlight the winning line
messagebox.showinfo("Game Over", f"Player {self.current_player} wins!")
self.highlight_winner(winner_combination)
messagebox.showinfo("Game Over", f"{self.player_names[self.current_player]} ({self.current_player}) wins!")
self.update_score(self.current_player)
self.reset_board() #Reset board after highlighting the winner
self.reset_board(keep_scores=True)
elif '' not in self.board:
messagebox.showinfo("Game Over", "It's a tie!")
self.reset_board()
self.reset_board(keep_scores=True)
else:
self.current_player = 'O' if self.current_player == 'X' else 'X'
self.turn_label.config(text=f"Player {self.current_player}'s Turn")
self.switch_player()

def switch_player(self):
self.current_player = 'O' if self.current_player == 'X' else 'X'
self.update_turn_label()

def check_winner(self):
winning_combinations = [
Expand All @@ -91,25 +94,57 @@ def check_winner(self):
]
for combo in winning_combinations:
if self.board[combo[0]] == self.board[combo[1]] == self.board[combo[2]] != '':
return combo #Return the winning combination
return combo
return None

def highlight_winner(self, winner_combination):
#Highlight the winning combination by changing the background color
for idx in winner_combination:
self.buttons[idx // 3][idx % 3].config(bg='green')

def update_score(self, winner):
self.scores[winner] += 1
self.score_label.config(text=f"Score: X = {self.scores['X']} | O = {self.scores['O']}")
self.update_score_label()

def reset_board(self):
def reset_board(self, keep_scores=False):
self.board = [''] * 9
self.current_player = 'X'
for row in self.buttons:
for btn in row:
btn.config(text='', state='normal', bg='lightgray')
self.turn_label.config(text=f"Player {self.current_player}'s Turn")
self.update_turn_label()
if not keep_scores:
self.scores = {'X': 0, 'O': 0}
self.update_score_label()
self.game_start_time = time.time()

def change_players(self):
x_name = simpledialog.askstring("Player X", "Enter Player X's name:", initialvalue=self.player_names['X'])
o_name = simpledialog.askstring("Player O", "Enter Player O's name:", initialvalue=self.player_names['O'])
if x_name:
self.player_names['X'] = x_name
if o_name:
self.player_names['O'] = o_name
self.update_turn_label()
self.update_score_label()

def start_timer(self):
def update_time():
while self.running:
elapsed_time = int(time.time() - self.game_start_time)
self.timer_label.config(text=f"Time: {elapsed_time}s")
time.sleep(1)

timer_thread = threading.Thread(target=update_time)
timer_thread.daemon = True
timer_thread.start()

def quit_game(self):
self.running = False
self.root.quit()

def play_sound(self, sound_type):
if sound_type == "move":
winsound.Beep(500, 100)

if __name__ == "__main__":
root = tk.Tk()
Expand Down