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:
- ✅ Display X or O when clicking a cell
- ✅ Prevent clicking the same cell twice
- ✅ Alternate between X and O players
- ✅ Detect when someone wins (all 8 patterns)
- ✅ Detect a draw (board full, no winner)
- ✅ Display game status messages
- ✅ Disable cells when game ends
- ✅ Reset the game with the Reset button
Bonus Challenges
Once your game works, try these enhancements:
- Score Counter - Track wins for X and O across multiple games
- Win Animation - Highlight or animate the winning cells
- Sound Effects - Add sounds for clicks and wins
- AI Opponent - Make the computer play as O
- 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!
