Practice Project - XO Game (Tic Tac Toe)

Put your JavaScript skills to the test by building a complete XO Game (Tic Tac Toe) with event listeners, DOM manipulation, and game logic

Time to apply everything you've learned! Let's build a complete XO Game (Tic Tac Toe) from scratch.


🎮 Project Overview

In this practice project, you'll build a fully functional Tic Tac Toe game that demonstrates all the JavaScript concepts you've learned:

  • Variables to track game state
  • Functions to organize game logic
  • Arrays to store board data
  • DOM manipulation to update the interface
  • Event listeners to respond to user clicks
  • Conditional statements to check winners

Getting Started

Step 1: Clone the Starter Code

We've prepared a starter repository with HTML and CSS already done. You just need to write the JavaScript!

git clone https://github.com/yassinelamsaaf/CELL_WEB---XO-game.git
cd CELL_WEB---XO-game

Step 2: Open in Your Code Editor

Open the folder in VS Code or your preferred editor.

You'll find three files:

  • index.html - The game structure (already complete)
  • style.css - The game styling (already complete)
  • game-solution.js - Your JavaScript file (this is where you'll work!)

Step 3: Open in Browser

Double-click index.html to open it in your browser and see the game interface.


📁 Starter Files

HTML Structure (index.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>XO Game - Tic Tac Toe</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h1>XO Game</h1>
        
        <div class="game-info">
            <p>Current Player: <span id="current-player">X</span></p>
            <p id="game-status">Game in progress...</p>
        </div>

        <div class="game-board">
            <div class="cell" data-index="0"></div>
            <div class="cell" data-index="1"></div>
            <div class="cell" data-index="2"></div>
            <div class="cell" data-index="3"></div>
            <div class="cell" data-index="4"></div>
            <div class="cell" data-index="5"></div>
            <div class="cell" data-index="6"></div>
            <div class="cell" data-index="7"></div>
            <div class="cell" data-index="8"></div>
        </div>

        <button id="reset-btn">Reset Game</button>
    </div>

    <script src="game-solution.js"></script>
</body>
</html>

CSS Styling (style.css)

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background: #667eea;
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 20px;
}

.container {
    background: white;
    border-radius: 20px;
    padding: 40px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
    text-align: center;
    max-width: 500px;
    width: 100%;
}

h1 {
    color: #333;
    margin-bottom: 30px;
    font-size: 2.5rem;
    text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
}

.game-info {
    margin-bottom: 30px;
}

.game-info p {
    font-size: 1.2rem;
    color: #555;
    margin: 10px 0;
}

#current-player {
    font-weight: bold;
    color: #667eea;
    font-size: 1.5rem;
}

#game-status {
    font-weight: bold;
    color: #764ba2;
}

.game-board {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    margin: 0 auto 30px;
    max-width: 400px;
}

.cell {
    aspect-ratio: 1;
    background: #f5f7fa;
    border: none;
    border-radius: 10px;
    font-size: 3rem;
    font-weight: bold;
    color: #333;
    cursor: pointer;
    display: flex;
    justify-content: center;
    align-items: center;
    transition: all 0.3s ease;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.cell:hover {
    transform: scale(1.05);
    background: #e0e7ff;
    box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}

.cell.x {
    color: #667eea;
}

.cell.o {
    color: #764ba2;
}

.cell.disabled {
    cursor: not-allowed;
    opacity: 0.6;
}

#reset-btn {
    background: #667eea;
    color: white;
    border: none;
    padding: 15px 40px;
    font-size: 1.1rem;
    font-weight: bold;
    border-radius: 50px;
    cursor: pointer;
    transition: all 0.3s ease;
    box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
}

#reset-btn:hover {
    transform: translateY(-2px);
    background: #5568d3;
    box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
}

#reset-btn:active {
    transform: translateY(0);
}

/* Responsive design */
@media (max-width: 500px) {
    .container {
        padding: 20px;
    }

    h1 {
        font-size: 2rem;
    }

    .cell {
        font-size: 2rem;
    }
}

Your Mission: Complete the JavaScript

Open game-solution.js and follow the TODO comments to build the game logic.

JavaScript Structure (game-solution.js)

The file contains detailed comments guiding you through each step:

// ============================================
// XO GAME - TIC TAC TOE
// JavaScript Tutorial with Comments
// ============================================

// ============================================
// VARIABLES
// ============================================
// TODO: Declare variables to track the game state
// - Create an array to represent the 9 cells of the board (initially empty strings)
// - Create a variable to track whose turn it is (starts with 'X')
// - Create a variable to track if the game is still active (boolean)


// ============================================
// DOM ELEMENT REFERENCES
// ============================================
// TODO: Use querySelector and querySelectorAll to get references to HTML elements
// - Get all cell elements (use querySelectorAll with class 'cell')
// - Get the current player display element (id: 'current-player')
// - Get the game status element (id: 'game-status')
// - Get the reset button (id: 'reset-btn')


// ============================================
// WINNING PATTERNS
// ============================================
// TODO: Create an array of arrays containing all possible winning combinations
// The board indices are:
// [0] [1] [2]
// [3] [4] [5]
// [6] [7] [8]
// 
// Winning combinations are:
// Rows: [0,1,2], [3,4,5], [6,7,8]
// Columns: [0,3,6], [1,4,7], [2,5,8]
// Diagonals: [0,4,8], [2,4,6]


// ============================================
// INITIALIZE GAME
// ============================================
// TODO: Create a function called 'initializeGame' that:
// - Resets the board array to empty strings
// - Sets the current player to 'X'
// - Sets game active to true
// - Clears all cell texts using DOM manipulation
// - Removes disabled classes from cells
// - Updates the status message


// ============================================
// HANDLE CELL CLICK
// ============================================
// TODO: Create a function called 'handleCellClick' that takes an event parameter
// This function should:
// - Get the clicked cell element from the event
// - Get the cell index from the data-index attribute
// - Use conditionals (if/else) to check:
//   * If the cell is already filled (check the board array)
//   * If the game is not active
//   * If either condition is true, return early (do nothing)
// - Update the board array at the clicked index with current player
// - Use DOM manipulation to update the cell's innerText
// - Add a class to the cell for styling ('x' or 'o')
// - Call function to check for winner
// - If no winner, switch players


// ============================================
// CHECK FOR WINNER
// ============================================
// TODO: Create a function called 'checkWinner' that:
// - Uses a loop (for loop) to iterate through all winning patterns
// - For each pattern, check if all three positions have the same value
//   and that value is not empty
// - Use conditionals (if statements) to determine:
//   * If there's a winner - call handleGameEnd with winner
//   * If the board is full (no empty strings) - call handleGameEnd with 'draw'
// - You can use array methods or loops to check if board is full


// ============================================
// HANDLE GAME END
// ============================================
// TODO: Create a function called 'handleGameEnd' that takes a result parameter
// This function should:
// - Set game active to false
// - Use conditionals (if/else) to check the result:
//   * If result is 'draw', update status to show it's a draw
//   * Otherwise, update status to show the winner
// - Use a loop or querySelectorAll to add 'disabled' class to all cells


// ============================================
// SWITCH PLAYER
// ============================================
// TODO: Create a function called 'switchPlayer' that:
// - Uses a conditional (if/else or ternary operator) to switch between 'X' and 'O'
// - Updates the current player variable
// - Uses DOM manipulation to update the current player display (innerText)


// ============================================
// EVENT LISTENERS
// ============================================
// TODO: Add click event listeners to all cells
// - Use a loop (forEach) to iterate through all cell elements
// - Add a click event listener to each cell that calls handleCellClick


// TODO: Add click event listener to reset button
// - Should call initializeGame when clicked


// ============================================
// START THE GAME
// ============================================
// TODO: Call initializeGame to start the game when the page loads


// ============================================
// BONUS CHALLENGES FOR STUDENTS
// ============================================
// 1. Add a score counter that tracks wins for X and O
// 2. Add animation when someone wins
// 3. Highlight the winning combination
// 4. Add sound effects for clicks and wins
// 5. Add AI opponent for single player mode

Step-by-Step Guide

Step 1: Variables

Create variables to store:

  • Board state (array of 9 empty strings)
  • Current player ('X' or 'O')
  • Game active status (boolean)

Step 2: DOM References

Use querySelector and querySelectorAll to get HTML elements

Step 3: Winning Patterns

Define all 8 possible winning combinations

Step 4: Initialize Function

Reset the game to starting state

Step 5: Handle Click

Respond when a player clicks a cell

Step 6: Check Winner

Loop through winning patterns to find a winner

Step 7: Handle Game End

Display winner or draw message

Step 8: Switch Player

Alternate between X and O

Step 9: Event Listeners

Attach click handlers to cells and reset button

Step 10: Start Game

Call initialize when page loads


✅ Testing Your Game

Make sure your game can:

  1. ✅ Display X or O when clicking a cell
  2. ✅ Prevent clicking the same cell twice
  3. ✅ Alternate between X and O players
  4. ✅ Detect when someone wins (all 8 patterns)
  5. ✅ Detect a draw (board full, no winner)
  6. ✅ Display game status messages
  7. ✅ Disable cells when game ends
  8. ✅ Reset the game with the Reset button

Bonus Challenges

Once your game works, try these enhancements:

  1. Score Counter - Track wins for X and O across multiple games
  2. Win Animation - Highlight or animate the winning cells
  3. Sound Effects - Add sounds for clicks and wins
  4. AI Opponent - Make the computer play as O
  5. Themes - Add dark mode or different color schemes

Concepts Used

This project uses everything from Session 3:

  • ✅ Variables (const, let)
  • ✅ Functions (regular and arrow functions)
  • ✅ Arrays (storing board state, winning patterns)
  • ✅ DOM manipulation (querySelector, textContent, classList)
  • ✅ Events (addEventListener, click events)
  • ✅ Conditionals (if/else)
  • ✅ Loops (for, forEach)

What You'll Learn

By completing this project, you'll understand:

  • How to structure a complete JavaScript application
  • Managing application state with variables
  • Organizing code with functions
  • User interaction with event listeners
  • Dynamic UI updates with DOM manipulation
  • Game logic with conditionals and loops

Tips

  • Test frequently - Run your code after each function
  • Use console.log() - Debug by printing values
  • Read error messages - They tell you what's wrong
  • Start simple - Get basic clicks working first
  • Ask for help - Don't struggle alone!

Congratulations!

Once you complete this project, you'll have a fully functional game built with pure JavaScript!

This demonstrates real-world programming skills and shows you can:

  • Plan and structure an application
  • Implement interactive features
  • Debug and test code
  • Create something people can actually use

Keep coding and keep building!