Shafaq25's picture
Update app.py
91268bb verified
import gradio as gr
import random
import time
class TicTacToeGradio:
def __init__(self):
self.reset_game()
def reset_game(self, vs_computer=False):
self.board = [' '] * 9
self.current_player = "X"
self.vs_computer = vs_computer
self.game_over = False
self.winner = None
self.players = {"X": "Player 1", "O": "Computer" if vs_computer else "Player 2"}
def make_move(self, position):
if self.game_over or self.board[position] != ' ':
return False
self.board[position] = self.current_player
return True
def computer_move(self):
time.sleep(0.8)
if self.game_over:
return
empty_positions = [i for i, val in enumerate(self.board) if val == ' ']
if empty_positions:
move = random.choice(empty_positions)
self.board[move] = "O"
def check_winner(self):
wins = [(0,1,2),(3,4,5),(6,7,8),
(0,3,6),(1,4,7),(2,5,8),
(0,4,8),(2,4,6)]
for i,j,k in wins:
if self.board[i] == self.board[j] == self.board[k] and self.board[i] != ' ':
return self.board[i]
return None
def is_draw(self):
return ' ' not in self.board
def switch_player(self):
self.current_player = "O" if self.current_player == "X" else "X"
def get_button_style(self, value):
return "โŒ" if value == "X" else "โญ•" if value == "O" else ""
def get_status_message(self):
if self.winner:
emoji = "๐Ÿ”ฅ" if self.winner == "X" else "๐Ÿค–" if self.vs_computer else "๐Ÿ’ซ"
return f"๐ŸŽ‰ **{self.players[self.winner]}** wins! {emoji}"
elif self.is_draw():
return "๐Ÿค **It's a draw!** Well played!"
else:
emoji = "๐Ÿ”ฅ" if self.current_player == "X" else "๐Ÿค–" if self.vs_computer else "๐Ÿ’ซ"
return f"๐ŸŽฎ **{self.players[self.current_player]}'s Turn** {emoji}"
game = TicTacToeGradio()
def handle_click(btn_index):
if game.game_over or not game.make_move(btn_index):
return update_interface()
winner = game.check_winner()
if winner:
game.winner = winner
game.game_over = True
return update_interface()
if game.is_draw():
game.game_over = True
return update_interface()
game.switch_player()
if game.vs_computer and game.current_player == "O":
game.computer_move()
winner = game.check_winner()
if winner:
game.winner = winner
game.game_over = True
elif game.is_draw():
game.game_over = True
else:
game.switch_player()
return update_interface()
def update_interface():
buttons = [
gr.update(value=game.get_button_style(game.board[i]), interactive=(not game.game_over and game.board[i] == ' '))
for i in range(9)
]
status = game.get_status_message()
return buttons + [status]
def start_vs_friend():
game.reset_game(vs_computer=False)
return update_interface()
def start_vs_computer():
game.reset_game(vs_computer=True)
return update_interface()
def reset_current_game():
game.reset_game(game.vs_computer)
return update_interface()
CSS = """
body, .gradio-container {
background: #fff0f5 !important;
padding: 1rem 1.5rem;
box-sizing: border-box;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: #5b021f;
}
/* Heading and subtext */
h1 {
font-size: clamp(1.8rem, 5vw, 2.5rem);
color: #db2777;
margin-bottom: 0.2rem;
text-align: center;
font-weight: 700;
user-select: none;
}
.subtext {
font-size: clamp(1rem, 3vw, 1.1rem);
color: #9d174d;
text-align: center;
margin-bottom: 1.5rem;
user-select: none;
}
/* Board container: perfect square, responsive */
#board-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 12px;
width: 90vw;
max-width: 480px;
height: 90vw;
max-height: 480px;
margin: 0 auto 1.5rem auto;
}
/* Buttons fill cells fully, keep perfect squares */
.game-btn {
width: 100%;
height: 100%;
font-size: clamp(2rem, 6vw, 3.5rem) !important;
border-radius: 12px !important;
background: #fff0f5 !important;
border: 2px solid #f9a8d4 !important;
transition: background 0.2s ease-in-out;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
user-select: none;
}
.game-btn:hover {
background: #fbcfe8 !important;
border-color: #ec4899 !important;
}
/* Mode Buttons */
.neat-button {
padding: 12px 16px;
border-radius: 8px;
font-size: clamp(0.9rem, 3vw, 1.1rem);
margin: 6px 0;
background: #fce7f3;
border: 1px solid #f472b6;
color: #be185d;
font-weight: 600;
width: 100%;
box-sizing: border-box;
user-select: none;
}
.neat-button:hover {
background: #f9a8d4;
border-color: #ec4899;
cursor: pointer;
}
/* Status */
#status {
font-size: clamp(1rem, 4vw, 1.2rem);
font-weight: bold;
color: #db2777;
text-align: center;
margin: 1rem 0;
user-select: none;
}
/* Player legend text */
.player-legend {
font-size: clamp(0.85rem, 3vw, 1rem);
color: #831843;
margin-top: 0.5rem;
user-select: none;
}
@media (max-width: 768px) {
#board-container {
width: 90vw;
height: 90vw;
max-width: 320px;
max-height: 320px;
gap: 8px;
}
.game-btn {
font-size: clamp(1.8rem, 7vw, 2.5rem) !important;
}
.neat-button {
font-size: clamp(0.85rem, 4vw, 1rem);
}
#status {
font-size: clamp(0.95rem, 4vw, 1.1rem);
}
}
"""
with gr.Blocks(title="Tic Tac Toe", css=CSS) as demo:
gr.Markdown("""
<h1>๐Ÿ’— TIC TAC TOE</h1>
<p class="subtext">Play solo or with a friend โ€” may the best player win!</p>
""")
with gr.Row():
with gr.Column(scale=1, min_width=220):
gr.Markdown("### ๐ŸŽฎ Choose Game Mode", elem_id="status")
vs_friend_btn = gr.Button("๐Ÿ‘ฅ Play vs Friend", elem_classes=["neat-button"])
vs_computer_btn = gr.Button("๐Ÿค– Play vs Computer", elem_classes=["neat-button"])
reset_btn = gr.Button("๐Ÿ”„ Reset Game", elem_classes=["neat-button"])
gr.Markdown("""
<div class="player-legend">
<ul>
<li><strong>Player 1:</strong> โŒ</li>
<li><strong>Player 2 / Computer:</strong> โญ•</li>
</ul>
</div>
""")
with gr.Column(scale=2, min_width=300):
status_display = gr.Markdown("๐ŸŽฎ Select a game mode to begin", elem_id="status")
with gr.Column(elem_id="board-container"):
btn0 = gr.Button("", elem_classes=["game-btn"])
btn1 = gr.Button("", elem_classes=["game-btn"])
btn2 = gr.Button("", elem_classes=["game-btn"])
btn3 = gr.Button("", elem_classes=["game-btn"])
btn4 = gr.Button("", elem_classes=["game-btn"])
btn5 = gr.Button("", elem_classes=["game-btn"])
btn6 = gr.Button("", elem_classes=["game-btn"])
btn7 = gr.Button("", elem_classes=["game-btn"])
btn8 = gr.Button("", elem_classes=["game-btn"])
buttons = [btn0, btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8]
all_outputs = buttons + [status_display]
for i, btn in enumerate(buttons):
btn.click(fn=lambda i=i: handle_click(i), outputs=all_outputs)
vs_friend_btn.click(fn=start_vs_friend, outputs=all_outputs)
vs_computer_btn.click(fn=start_vs_computer, outputs=all_outputs)
reset_btn.click(fn=reset_current_game, outputs=all_outputs)
demo.launch()