Open the tic-tac-toe notebook file:
You can do this by using VSCode's file explorer
Run the virtual environment setup script:
This script will:
Make sure you're in your project root directory when running this command!
In VS Code or Jupyter, select your virtual environment kernel:
The kernel should show your venv path, not system Python!
Execute the code cells to start playing:
You're ready to play! Choose positions 1-9 to make your moves.
If the game doesn't run, check that you've selected the correct venv kernel and that all packages are installed in your virtual environment.
class Player:
def __init__(self, name, symbol):
self.name = name
self.symbol = symbol
class Board:
def __init__(self, size=3): # changed so can change board size
self.size = size
self.grid = [" "] * (size * size)
def display(self):
print("\n")
for row in range(self.size):
start = row * self.size
row_cells = " | ".join(self.grid[start:start + self.size])
print(" " + row_cells)
if row < self.size - 1:
print("---+" * (self.size - 1) + "---")
print("\n")
def display_reference(self):
reference = [str(i + 1) for i in range(self.size * self.size)]
print("Board positions:\n")
for row in range(self.size):
start = row * self.size
row_cells = " | ".join(reference[start:start + self.size])
print(" " + row_cells)
if row < self.size - 1:
print("---+" * (self.size - 1) + "---")
print("\n")
def is_full(self):
return " " not in self.grid
def make_move(self, position, symbol):
index = position - 1
if index < 0 or index >= len(self.grid):
print(f"Invalid position. Choose a number between 1 and {len(self.grid)}.")
return False
if self.grid[index] != " ":
print("That spot is already taken. Try again.")
return False
self.grid[index] = symbol
return True
def check_winner(self, symbol):
win_combinations = self.generate_win_combinations()
for combo in win_combinations:
if all(self.grid[i] == symbol for i in combo):
return True
return False
def generate_win_combinations(self):
combos = []
# win combos for rows
for r in range(self.size):
start = r * self.size
combos.append([start + c for c in range(self.size)])
# win combos for columns
for c in range(self.size):
combos.append([c + r * self.size for r in range(self.size)])
# win comboes for diagonals
combos.append([i * (self.size + 1) for i in range(self.size)]) # Top-left to bottom-right
combos.append([i * (self.size - 1) + (self.size - 1) for i in range(self.size)]) # Top-right to bottom-left
return combos
class TicTacToe:
def __init__(self, player1, player2, size=3): # changed to add the size variable
self.board = Board(size)
self.players = [player1, player2]
self.current_player = player1
self.move_history = [] # added move tracker to the game itself
def switch_player(self):
self.current_player = (
self.players[1] if self.current_player == self.players[0] else self.players[0]
)
def show_move_history(self): # added to define the command.
print("\nMove History:")
for move in self.move_history:
print(f"Turn {move['turn']}: {move['player']} ({move['symbol']}) -> Position {move['position']}")
print()
def play(self):
print("Welcome to Tic-Tac-Toe!")
print(f"{self.players[0].name} is '{self.players[0].symbol}'")
print(f"{self.players[1].name} is '{self.players[1].symbol}'")
print("Players take turns choosing a position (1–9).\n")
self.board.display_reference()
self.board.display()
while True:
try:
move = int(input(f"{self.current_player.name} ({self.current_player.symbol}), enter your move (1-9): "))
except ValueError:
print("Invalid input. Please enter a number from 1 to 9.")
continue
if not self.board.make_move(move, self.current_player.symbol):
continue
# logs the move made
self.move_history.append({
"turn": len(self.move_history) + 1,
"player": self.current_player.name,
"symbol": self.current_player.symbol,
"position": move
})
self.board.display()
self.show_move_history() # this shows move hisotry after every turn.
if self.board.check_winner(self.current_player.symbol):
print(f"{self.current_player.name} ({self.current_player.symbol}) wins!")
self.show_move_history() # this shows the move history if the player wins
break
if self.board.is_full():
print("It's a tie!")
self.show_move_history() # this shows the move history if theres a tie
break
self.switch_player()
if __name__ == "__main__":
size = int(input("Enter board size (3 for 3x3, 5 for 5x5, etc.): ")) # allows for the size to be chosen
player1 = Player("Player 1", "X")
player2 = Player("Player 2", "O")
game = TicTacToe(player1, player2, size) # gives the size to the game to be used
game.play()
Welcome to Tic-Tac-Toe!
Player 1 is 'X'
Player 2 is 'O'
Players take turns choosing a position (1–9).
Board positions:
1 | 2 | 3 | 4
---+---+---+---
5 | 6 | 7 | 8
---+---+---+---
9 | 10 | 11 | 12
---+---+---+---
13 | 14 | 15 | 16
| | |
---+---+---+---
| | |
---+---+---+---
| | |
---+---+---+---
| | |
X | | |
---+---+---+---
| | |
---+---+---+---
| | |
---+---+---+---
| | |
Move History:
Turn 1: Player 1 (X) -> Position 1
X | | |
---+---+---+---
| O | |
---+---+---+---
| | |
---+---+---+---
| | |
Move History:
Turn 1: Player 1 (X) -> Position 1
Turn 2: Player 2 (O) -> Position 6
X | X | |
---+---+---+---
| O | |
---+---+---+---
| | |
---+---+---+---
| | |
Move History:
Turn 1: Player 1 (X) -> Position 1
Turn 2: Player 2 (O) -> Position 6
Turn 3: Player 1 (X) -> Position 2
X | X | |
---+---+---+---
| O | |
---+---+---+---
| | O |
---+---+---+---
| | |
Move History:
Turn 1: Player 1 (X) -> Position 1
Turn 2: Player 2 (O) -> Position 6
Turn 3: Player 1 (X) -> Position 2
Turn 4: Player 2 (O) -> Position 11
X | X | X |
---+---+---+---
| O | |
---+---+---+---
| | O |
---+---+---+---
| | |
Move History:
Turn 1: Player 1 (X) -> Position 1
Turn 2: Player 2 (O) -> Position 6
Turn 3: Player 1 (X) -> Position 2
Turn 4: Player 2 (O) -> Position 11
Turn 5: Player 1 (X) -> Position 3
X | X | X |
---+---+---+---
| O | |
---+---+---+---
| | O |
---+---+---+---
| | | O
Move History:
Turn 1: Player 1 (X) -> Position 1
Turn 2: Player 2 (O) -> Position 6
Turn 3: Player 1 (X) -> Position 2
Turn 4: Player 2 (O) -> Position 11
Turn 5: Player 1 (X) -> Position 3
Turn 6: Player 2 (O) -> Position 16
X | X | X | X
---+---+---+---
| O | |
---+---+---+---
| | O |
---+---+---+---
| | | O
Move History:
Turn 1: Player 1 (X) -> Position 1
Turn 2: Player 2 (O) -> Position 6
Turn 3: Player 1 (X) -> Position 2
Turn 4: Player 2 (O) -> Position 11
Turn 5: Player 1 (X) -> Position 3
Turn 6: Player 2 (O) -> Position 16
Turn 7: Player 1 (X) -> Position 4
Player 1 (X) wins!
Move History:
Turn 1: Player 1 (X) -> Position 1
Turn 2: Player 2 (O) -> Position 6
Turn 3: Player 1 (X) -> Position 2
Turn 4: Player 2 (O) -> Position 11
Turn 5: Player 1 (X) -> Position 3
Turn 6: Player 2 (O) -> Position 16
Turn 7: Player 1 (X) -> Position 4