Basic Tic-Tac-Toe JavaScript, HTML, CSS
👤 Sharing: AI
Okay, here's a basic Tic-Tac-Toe game implemented using JavaScript, HTML, and CSS. I'll provide the code, followed by explanations to help you understand how it works.
**HTML (index.html):**
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tic-Tac-Toe</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Tic-Tac-Toe</h1>
<div class="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>
<p id="message"></p>
<button id="resetBtn">Reset Game</button>
<script src="script.js"></script>
</body>
</html>
```
**CSS (style.css):**
```css
body {
font-family: sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
}
h1 {
margin-bottom: 20px;
}
.board {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 5px;
margin-bottom: 20px;
}
.cell {
width: 100px;
height: 100px;
background-color: #fff;
border: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
font-size: 2em;
cursor: pointer;
}
.cell:hover {
background-color: #eee;
}
#message {
font-size: 1.2em;
margin-bottom: 10px;
}
#resetBtn {
padding: 10px 20px;
font-size: 1em;
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
}
#resetBtn:hover {
background-color: #3e8e41;
}
```
**JavaScript (script.js):**
```javascript
const board = document.querySelector('.board');
const cells = document.querySelectorAll('.cell');
const message = document.getElementById('message');
const resetBtn = document.getElementById('resetBtn');
let currentPlayer = 'X';
let gameBoard = ['', '', '', '', '', '', '', '', ''];
let gameActive = true;
const winningCombinations = [
[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
];
function handleCellClick(event) {
const cellIndex = parseInt(event.target.dataset.index);
if (gameBoard[cellIndex] !== '' || !gameActive) {
return; // Cell already taken or game is over
}
gameBoard[cellIndex] = currentPlayer;
event.target.textContent = currentPlayer;
event.target.classList.add(currentPlayer === 'X' ? 'x-mark' : 'o-mark'); // Optional visual styling
if (checkWin()) {
message.textContent = `Player ${currentPlayer} wins!`;
gameActive = false;
return;
}
if (checkDraw()) {
message.textContent = "It's a draw!";
gameActive = false;
return;
}
currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
message.textContent = `Player ${currentPlayer}'s turn`;
}
function checkWin() {
for (let combination of winningCombinations) {
const [a, b, c] = combination;
if (gameBoard[a] && gameBoard[a] === gameBoard[b] && gameBoard[a] === gameBoard[c]) {
return true;
}
}
return false;
}
function checkDraw() {
return !gameBoard.includes(''); // If no empty cells, it's a draw
}
function resetGame() {
gameBoard = ['', '', '', '', '', '', '', '', ''];
currentPlayer = 'X';
gameActive = true;
message.textContent = `Player ${currentPlayer}'s turn`;
cells.forEach(cell => {
cell.textContent = '';
cell.classList.remove('x-mark', 'o-mark'); // Remove visual styling, if any
});
}
// Event Listeners
cells.forEach(cell => {
cell.addEventListener('click', handleCellClick);
});
resetBtn.addEventListener('click', resetGame);
//Initial message
message.textContent = `Player ${currentPlayer}'s turn`;
```
**Explanation:**
1. **HTML (index.html):**
* Sets up the basic page structure.
* `<h1>`: The title of the game.
* `<div class="board">`: This is the main container for the Tic-Tac-Toe grid.
* `<div class="cell" data-index="...">`: Each cell of the board is a `div` with the class `cell`. The `data-index` attribute stores the cell's position (0-8), which is crucial for our JavaScript logic.
* `<p id="message">`: This is where we'll display messages (e.g., whose turn it is, who won, or if it's a draw).
* `<button id="resetBtn">`: The button to reset the game.
* `<script src="script.js"></script>`: Links the JavaScript file to handle the game's logic.
2. **CSS (style.css):**
* Provides basic styling for the page and the Tic-Tac-Toe board. You can customize this to your liking.
* `.board`: Uses CSS Grid to create the 3x3 grid layout.
* `.cell`: Styles the individual cells. Crucially, it makes them clickable with `cursor: pointer;`.
* `#message`: Styles the message paragraph.
* `#resetBtn`: Styles the reset button.
3. **JavaScript (script.js):**
* **Variable Declarations:**
* `board`: Selects the `.board` element from the HTML.
* `cells`: Selects all elements with the class `.cell`.
* `message`: Selects the element with the ID `message`.
* `resetBtn`: Selects the element with the ID `resetBtn`.
* `currentPlayer`: Keeps track of whose turn it is ('X' or 'O'). Initialized to 'X'.
* `gameBoard`: An array that represents the state of the Tic-Tac-Toe board. Each element corresponds to a cell. Initially, all elements are empty strings (`''`).
* `gameActive`: A boolean flag indicating whether the game is still in progress.
* `winningCombinations`: An array of arrays. Each inner array represents a winning combination of cell indices.
* **`handleCellClick(event)` Function:**
* This function is called when a cell is clicked.
* `cellIndex`: Gets the index of the clicked cell from the `data-index` attribute. `parseInt()` is used to convert the string value to an integer.
* **Check for Valid Move:**
* `if (gameBoard[cellIndex] !== '' || !gameActive)`: This checks if the cell is already taken (`gameBoard[cellIndex] !== ''`) or if the game is over (`!gameActive`). If either is true, the function returns, doing nothing.
* **Update Game State:**
* `gameBoard[cellIndex] = currentPlayer;`: Updates the `gameBoard` array with the current player's symbol ('X' or 'O') at the clicked cell's index.
* `event.target.textContent = currentPlayer;`: Sets the text content of the clicked cell to the current player's symbol, displaying it on the board.
* **Check for Win or Draw:**
* `checkWin()`: Calls the `checkWin()` function to see if the current player has won. If so, it updates the `message` element, sets `gameActive` to `false`, and returns.
* `checkDraw()`: Calls the `checkDraw()` function to see if the game is a draw. If so, it updates the `message` element, sets `gameActive` to `false`, and returns.
* **Switch Player:**
* `currentPlayer = currentPlayer === 'X' ? 'O' : 'X';`: Switches the current player to the other player using a ternary operator.
* `message.textContent = \`Player ${currentPlayer}'s turn\`;`: Updates the message to indicate the next player's turn.
* **`checkWin()` Function:**
* Iterates through each winning combination in the `winningCombinations` array.
* For each combination, it checks if all three cells in that combination have the same non-empty value (i.e., 'X' or 'O').
* If a winning combination is found, it returns `true`.
* If no winning combination is found after checking all combinations, it returns `false`.
* **`checkDraw()` Function:**
* Checks if the `gameBoard` array contains any empty strings (`''`).
* If it doesn't (meaning all cells are filled), it returns `true` (it's a draw).
* Otherwise, it returns `false` (the game is not a draw).
* **`resetGame()` Function:**
* Resets the `gameBoard` array to all empty strings.
* Resets `currentPlayer` to 'X'.
* Resets `gameActive` to `true`.
* Clears the text content of all cells on the board.
* Updates the `message` element to indicate the initial player's turn.
* **Event Listeners:**
* `cells.forEach(cell => { cell.addEventListener('click', handleCellClick); });`: Attaches a click event listener to each cell. When a cell is clicked, the `handleCellClick` function is called.
* `resetBtn.addEventListener('click', resetGame);`: Attaches a click event listener to the reset button. When the button is clicked, the `resetGame` function is called.
* **Initial Message:**
* `message.textContent = \`Player ${currentPlayer}'s turn\`;` Sets initial message to first players turn
**How to Run:**
1. Save the HTML as `index.html`, the CSS as `style.css`, and the JavaScript as `script.js` in the same directory.
2. Open `index.html` in your web browser.
**Key Concepts:**
* **DOM Manipulation:** JavaScript interacts with the HTML elements (cells, message, button) to update their content and respond to user clicks.
* **Event Handling:** The `addEventListener` method is used to listen for click events on the cells and the reset button.
* **Arrays:** The `gameBoard` array stores the state of the game. The `winningCombinations` array helps determine the winner.
* **Functions:** Functions like `handleCellClick`, `checkWin`, `checkDraw`, and `resetGame` encapsulate different parts of the game's logic.
* **Data Attributes:** The `data-index` attribute is used to store the cell's position within the grid. This is a common technique for associating data with HTML elements.
* **CSS Grid:** Used for creating the board layout.
This is a basic implementation. You can extend it by:
* Adding styling to differentiate 'X' and 'O' visually. (I added `x-mark` and `o-mark` classes in JavaScript to help with this, but you'd need to define the CSS rules for them.)
* Implementing an AI opponent (easy, medium, hard difficulty).
* Tracking the score.
* Using local storage to persist the score between browser sessions.
* Making the UI more visually appealing.
I hope this explanation helps you understand the code and build upon it!
👁️ Viewed: 9
Comments