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