1. Navigate to the Notebook

Open the tic-tac-toe notebook file:

_notebooks/Foundation/F-projects/2025-08-18-tictactoe-game.ipynb

You can do this by using VSCode’s file explorer

2. Set Up Virtual Environment

Run the virtual environment setup script:

./scripts/venv.sh

This script will:

⚠️ Important

Make sure you’re in your project root directory when running this command!

3. Select the Correct Kernel

In VS Code or Jupyter, select your virtual environment kernel:

  1. Click on “Select Kernel” (usually in the top-right of the notebook)
  2. Choose “Python Environments”
  3. Select your venv kernel from the list

💡 Pro Tip

The kernel should show your venv path, not system Python!

4. Run the Game

Execute the code cells to start playing:

🎉 Success!

You’re ready to play! Choose positions 1-9 to make your moves.

🔧 Troubleshooting

Common Issues

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):
        self.grid = [" "] * 9

    def display(self):
        print("Current Board:")
        print(f" {self.grid[0]} | {self.grid[1]} | {self.grid[2]}")
        print("---+---+---")
        print(f" {self.grid[3]} | {self.grid[4]} | {self.grid[5]}")
        print("---+---+---")
        print(f" {self.grid[6]} | {self.grid[7]} | {self.grid[8]}")
        print()

    def display_reference(self):
        print("Board positions:")
        print(" 1 | 2 | 3")
        print("---+---+---")
        print(" 4 | 5 | 6")
        print("---+---+---")
        print(" 7 | 8 | 9")
        print()

    def is_full(self):
        return " " not in self.grid

    def make_move(self, position, symbol):
        if not isinstance(position, int) or position < 1 or position > 9:
            print("❌ Invalid position. Choose a number between 1 and 9.")
            return False
        if self.grid[position - 1] != " ":
            print("❌ That spot is already taken. Try again.")
            return False
        
        self.grid[position - 1] = symbol
        return True

    def check_winner(self, symbol):
        win_combinations = [
            [0, 1, 2], [3, 4, 5], [6, 7, 8],  # Rows
            [0, 3, 6], [1, 4, 7], [2, 5, 8],  # Columns
            [0, 4, 8], [2, 4, 6]              # Diagonals
        ]
        for combo in win_combinations:
            if (self.grid[combo[0]] == symbol and
                self.grid[combo[1]] == symbol and
                self.grid[combo[2]] == symbol):
                return True
        return False

    def get_empty_positions(self):
        return [i + 1 for i in range(9) if self.grid[i] == " "]


class JupyterTicTacToe:
    def __init__(self):
        self.board = Board()
        self.players = [Player("Player 1", "X"), Player("Player 2", "O")]
        self.current_player_index = 0
        self.game_over = False
        self.winner = None
        
    def get_current_player(self):
        return self.players[self.current_player_index]
    
    def start_game(self):
        """Call this to start a new game"""
        self.board = Board()
        self.current_player_index = 0
        self.game_over = False
        self.winner = None
        
        print("🎮 Welcome to Tic-Tac-Toe! 🎮")
        print("=" * 30)
        print(f"{self.players[0].name} is '{self.players[0].symbol}'")
        print(f"{self.players[1].name} is '{self.players[1].symbol}'")
        print()
        
        self.board.display_reference()
        self.show_game_state()
    
    def show_game_state(self):
        """Display current game state"""
        self.board.display()
        
        if not self.game_over:
            current_player = self.get_current_player()
            available = self.board.get_empty_positions()
            print(f"🎯 {current_player.name} ({current_player.symbol})'s turn")
            print(f"Available positions: {available}")
            print(f"➡️  To make a move, run: game.make_move(position)")
            print(f"    Example: game.make_move(5)")
        
    def make_move(self, position):
        """Make a move at the specified position"""
        if self.game_over:
            print("❌ Game is over! Start a new game with: game.start_game()")
            return
            
        current_player = self.get_current_player()
        print(f"🎯 {current_player.name} ({current_player.symbol}) plays position {position}")
        
        if self.board.make_move(position, current_player.symbol):
            print("✅ Move successful!")
            
            # Check for winner
            if self.board.check_winner(current_player.symbol):
                self.game_over = True
                self.winner = current_player
                self.board.display()
                print(f"🎉🎉 {current_player.name} ({current_player.symbol}) WINS! 🎉🎉")
                print("🔄 Start a new game with: game.start_game()")
                return
            
            # Check for tie
            if self.board.is_full():
                self.game_over = True
                self.board.display()
                print("🤝 It's a TIE! Good game!")
                print("🔄 Start a new game with: game.start_game()")
                return
            
            # Switch players and continue
            self.current_player_index = 1 - self.current_player_index
            self.show_game_state()
        else:
            print("❌ Invalid move. Try again.")
            self.show_game_state()
    
    def show_help(self):
        """Show help instructions"""
        print("🆘 HOW TO PLAY:")
        print("=" * 20)
        print("1. Start a new game: game.start_game()")
        print("2. Make moves: game.make_move(1-9)")
        print("3. Check game state: game.show_game_state()")
        print("4. Show this help: game.show_help()")
        print()
        print("📋 Board positions are numbered 1-9:")
        self.board.display_reference()


# Create a global game instance
game = JupyterTicTacToe()

# Auto-start the first game
print("🚀 Initializing Tic-Tac-Toe for Jupyter Notebook...")
print("=" * 50)
game.start_game()

print("\n💡 QUICK START:")
print("   Make your first move by running: game.make_move(5)")
print("   Need help? Run: game.show_help()")
game.make_move(1)
🚀 Initializing Tic-Tac-Toe for Jupyter Notebook...
==================================================
🎮 Welcome to Tic-Tac-Toe! 🎮
==============================
Player 1 is 'X'
Player 2 is 'O'

Board positions:
 1 | 2 | 3
---+---+---
 4 | 5 | 6
---+---+---
 7 | 8 | 9

Current Board:
   |   |  
---+---+---
   |   |  
---+---+---
   |   |  

🎯 Player 1 (X)'s turn
Available positions: [1, 2, 3, 4, 5, 6, 7, 8, 9]
➡️  To make a move, run: game.make_move(position)
    Example: game.make_move(5)

💡 QUICK START:
   Make your first move by running: game.make_move(5)
   Need help? Run: game.show_help()
🎯 Player 1 (X) plays position 1
✅ Move successful!
Current Board:
 X |   |  
---+---+---
   |   |  
---+---+---
   |   |  

🎯 Player 2 (O)'s turn
Available positions: [2, 3, 4, 5, 6, 7, 8, 9]
➡️  To make a move, run: game.make_move(position)
    Example: game.make_move(5)
game.make_move(3)

🎯 Player 2 (O) plays position 3
✅ Move successful!
Current Board:
 X | O | O
---+---+---
   | X |  
---+---+---
   |   |  

🎯 Player 1 (X)'s turn
Available positions: [4, 6, 7, 8, 9]
➡️  To make a move, run: game.make_move(position)
    Example: game.make_move(5)