File size: 7,240 Bytes
4222196 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
import streamlit as st
import math
import random
class TicTacToe:
def __init__(self):
"""Initialize the game board"""
self.board = [[' ' for _ in range(3)] for _ in range(3)]
self.current_winner = None
def make_move(self, row, col, player):
"""Make a move on the board"""
if self.board[row][col] == ' ':
self.board[row][col] = player
return True
return False
def check_winner(self):
"""Check for a winner"""
# Check rows
for row in self.board:
if row[0] == row[1] == row[2] != ' ':
return row[0]
# Check columns
for col in range(3):
if self.board[0][col] == self.board[1][col] == self.board[2][col] != ' ':
return self.board[0][col]
# Check diagonals
if self.board[0][0] == self.board[1][1] == self.board[2][2] != ' ':
return self.board[0][0]
if self.board[0][2] == self.board[1][1] == self.board[2][0] != ' ':
return self.board[0][2]
return None
def is_board_full(self):
"""Check if the board is full"""
return all(cell != ' ' for row in self.board for cell in row)
def minimax(self, depth, is_maximizing, alpha, beta):
"""Minimax algorithm with Alpha-Beta pruning"""
winner = self.check_winner()
# Terminal states
if winner == 'X':
return 1
elif winner == 'O':
return -1
elif self.is_board_full():
return 0
if is_maximizing:
max_eval = -math.inf
for i in range(3):
for j in range(3):
if self.board[i][j] == ' ':
self.board[i][j] = 'X'
eval = self.minimax(depth + 1, False, alpha, beta)
self.board[i][j] = ' '
max_eval = max(max_eval, eval)
alpha = max(alpha, eval)
if beta <= alpha:
break
return max_eval
else:
min_eval = math.inf
for i in range(3):
for j in range(3):
if self.board[i][j] == ' ':
self.board[i][j] = 'O'
eval = self.minimax(depth + 1, True, alpha, beta)
self.board[i][j] = ' '
min_eval = min(min_eval, eval)
beta = min(beta, eval)
if beta <= alpha:
break
return min_eval
def find_best_move(self):
"""Find the best move for the AI"""
best_val = -math.inf
best_move = None
for i in range(3):
for j in range(3):
if self.board[i][j] == ' ':
self.board[i][j] = 'X'
move_val = self.minimax(0, False, -math.inf, math.inf)
self.board[i][j] = ' '
if move_val > best_val:
best_move = (i, j)
best_val = move_val
return best_move
def main():
# Set page configuration
st.set_page_config(
page_title="Tic-Tac-Toe AI",
page_icon=":game_die:",
layout="centered"
)
# Custom CSS for styling
st.markdown("""
<style>
.stButton>button {
width: 100px;
height: 100px;
font-size: 48px;
margin: 5px;
}
.title {
text-align: center;
color: #4a4a4a;
}
.subtitle {
text-align: center;
color: #6a6a6a;
}
</style>
""", unsafe_allow_html=True)
# Title and introduction
st.markdown("<h1 class='title'>π² Tic-Tac-Toe AI π€</h1>", unsafe_allow_html=True)
st.markdown("<h3 class='subtitle'>Can you beat the AI?</h3>", unsafe_allow_html=True)
# Initialize game state
if 'game' not in st.session_state:
st.session_state.game = TicTacToe()
st.session_state.game_over = False
st.session_state.winner = None
# Function to handle button clicks
def button_click(row, col):
# Check if game is not over and the cell is empty
if not st.session_state.game_over and st.session_state.game.board[row][col] == ' ':
# Player's move
st.session_state.game.make_move(row, col, 'O')
# Check for player win
winner = st.session_state.game.check_winner()
if winner:
st.session_state.game_over = True
st.session_state.winner = winner
return
# Check for draw
if st.session_state.game.is_board_full():
st.session_state.game_over = True
return
# AI's move
ai_move = st.session_state.game.find_best_move()
if ai_move:
st.session_state.game.make_move(ai_move[0], ai_move[1], 'X')
# Check for AI win
winner = st.session_state.game.check_winner()
if winner:
st.session_state.game_over = True
st.session_state.winner = winner
# Render the game board
game_board = st.columns(3)
for row in range(3):
with game_board[row % 3]:
for col in range(3):
# Create a button for each cell
button_label = st.session_state.game.board[row][col]
button_key = f"button_{row}_{col}"
# Style buttons based on their content
if button_label == 'O':
button_style = "background-color: #FF6B6B; color: white;"
elif button_label == 'X':
button_style = "background-color: #4ECDC4; color: white;"
else:
button_style = ""
# Create the button
if st.button(button_label, key=button_key,
on_click=button_click,
args=(row, col),
disabled=st.session_state.game_over or button_label != ' ',
help="Click to make your move"):
pass
# Display game result
if st.session_state.game_over:
if st.session_state.winner == 'O':
st.success("π Congratulations! You won!")
elif st.session_state.winner == 'X':
st.error("π€ AI wins! Better luck next time.")
else:
st.warning("π€ It's a draw!")
# Restart game button
if st.button("New Game", help="Start a new game"):
st.session_state.game = TicTacToe()
st.session_state.game_over = False
st.session_state.winner = None
st.rerun()
if __name__ == "__main__":
main() |