Creating an AI adversary for a simple Tic Tac Toe game board: a step-by-step guide

Being new to programming, I recently completed a basic Tic Tac Toe gameboard successfully. However, as I progress to the next phase of my assignment which involves implementing an AI opponent, I encountered several challenges.

As a novice in programming, I am seeking guidance on how to enhance and modify my existing code for the regular Tic Tac Toe gameboard to incorporate an AI opponent.

The technologies used for my basic Tic Tac Toe gameboard include HTML, CSS, and JS. Below are the codes:

HTML

`<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Tic Tac Toe</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="container">
    <h1>Tic Tac Toe</h1>
    <div id="board">
      <div class="square" id="0"></div>
      <div class="square" id="1"></div>
      <div class="square" id="2"></div>
      <div class="square" id="3"></div>
      <div class="square" id="4"></div>
      <div class="square" id="5"></div>
      <div class="square" id="6"></div>
      <div class="square" id="7"></div>
      <div class="square" id="8"></div>
    </div>
    <button id="reset">Reset Game</button>
    <div id="message"></div>
  </div>
  <script src="index.js"></script>
</body>
</html>`

CSS

`.container {
  text-align: center;
}

#board {
  display: flex;
  flex-wrap: wrap;
  width: 300px;
  margin: 0 auto;
}

.square {
  width: 90px;
  height: 90px;
  background-color: black;
  margin: 5px;
  border-radius: 5px;
  font-size: 50px;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
}

.square:hover {
  background-color: whitesmoke;
}

.square.X {
  color: #ff5e5e;
}

.square.O {
  color: #0077ff;
}
`

JS

`let board = ["", "", "", "", "", "", "", "", ""];
let currentPlayer = "X";
let gameOver = false;

const winningConditions = [
  [0, 1, 2],
  [3, 4, 5],
  [6, 7, 8],
  [0, 3, 6],
  [1, 4, 7],
  [2, 5, 8],
  [0, 4, 8],
  [2, 4, 6]
];

const squares = document.querySelectorAll(".square");
const resetButton = document.querySelector("#reset");

// Add click event listener to each square
squares.forEach(square => {
  square.addEventListener("click", handleClick);
});

// Add click event listener to reset button
resetButton.addEventListener("click", resetGame);

function handleClick(event) {
  const square = event.target;
  const index = square.getAttribute("id");

  // If square is already clicked or game is over, return
  if (board[index] !== "" || gameOver) {
    return;
  }

  // Add X or O to board and update UI
  board[index] = currentPlayer;
  square.classList.add(currentPlayer);
  square.innerHTML = currentPlayer;

  // Check for winner or tie game
  checkForWinner();
  checkForTieGame();

  // Switch current player
  currentPlayer = currentPlayer === "X" ? "O" : "X";
}

function checkForWinner() {
  for (let i = 0; i < winningConditions.length; i++) {
    const [a, b, c] = winningConditions[i];
    if (board[a] === board[b] && board[b] === board[c] && board[a] !== "") {
      gameOver = true;
      highlightWinnerSquares(a, b, c);
      displayWinner(board[a]);
      break;
    }
  }
}

function checkForTieGame() {
  if (!board.includes("") && !gameOver) {
    gameOver = true;
    displayTieGame();
  }
}

function highlightWinnerSquares(a, b, c) {
  document.getElementById(a).classList.add("winner");
  document.getElementById(b).classList.add("winner");
  document.getElementById(c).classList.add("winner");
}

function displayWinner(player) {
  const message = document.getElementById("message");
  message.innerHTML = `${player} wins!`;
}

function displayTieGame() {
  const message = document.getElementById("message");
  message.innerHTML = "It's a tie game!";
}

function resetGame() {
  board = ["", "", "", "", "", "", "", "", ""];
  currentPlayer = "X";
  gameOver = false;

  squares.forEach(square => {
    square.classList.remove("X", "O", "winner");
    square.innerHTML = "";
  });

  const message = document.getElementById("message");
  message.innerHTML = "";
}`

Answer №1

Transform the code within handleClick into a separate function:

function handleClick(event) {
  const square = event.target;
  click(square);
}

function click(square) {
  const index = square.getAttribute("id");

  // If square is already clicked or game is over, exit
  if (board[index] !== "" || gameOver) {
    return;
  }

  // Place X or O on board and update UI
  board[index] = currentPlayer;
  square.classList.add(currentPlayer);
  square.innerHTML = currentPlayer;

  // Check for winner or tie game
  checkForWinner();
  checkForTieGame();

  // Switch player turn
  currentPlayer = currentPlayer === "X" ? "O" : "X";
}

Now your AI player can utilize the click function.

click(document.getElementById("4"));
, etc.

I suggest letting the AI make its moves within the click event handler (after the player's move)

function handleClick(event) {
  const playerMove = event.target;
  click(playerMove);
  const computerMove = chooseComputerMove();
  click(chooseComputerMove);
}

function chooseComputerMove() {
  // TODO: implement this method
  // determine which square the AI should play on this turn,
  // return the associated HTML element
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for integrating a "datetime" picker in your AngularJS application

Currently working on an AngularJS application. The single page has a date input that needs to be added. Date Input <input type="date" ng-model="InputDate" /> Any suggestions on how to accomplish this task? ...

Exploring CouchDB through Ajax to interact with a static website

Is it feasible for my HTML static website to interact with CouchDB using AJAX and retrieve the data without relying on server-side languages like PHP or Python? The CouchDB might be hosted on a different server/domain, so JSONP would need to be utilized. ...

One of the great features of Next.js is its ability to easily change

At the moment, my dynamic path is configured to display events by their ID [id].js localhost:3000/event/1 But I would like it to be structured as follows: localhost:3000/city/date/title. All of this information is available in the events database, but I&a ...

A significant number of middleware packages, such as compress, are no longer provided as part of the

I recently added [email protected], [email protected], [email protected] and [email protected] (just to be safe). However, I am encountering this error message when trying to execute sails lift /Users/myuser/myproject/backend/node_modu ...

Calculating dimensions for parents and their children

Could someone please explain to me why the size of #child is different from that of #parent? <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.or ...

Display only distinct items in a v-for loop in Vue.js

I am attempting to show icons based on specific v-for and v-if conditions. However, the icons are appearing multiple times when I only want them to display once. I attempted using v-if = 'index === 0', but this did not resolve the issue. <di ...

Supplier for a module relying on data received from the server

My current component relies on "MAT_DATE_FORMATS", but I am encountering an issue where the "useValue" needs to be retrieved from the server. Is there a way to make the provider asynchronous in this case? export const MY_FORMATS = { parse: { d ...

Illuminate the rows in a table generated from a parsed text file using PHP

I am facing an issue with my PHP logic for selecting and highlighting rows in a table based on dropdown selection. I have a group of text files that are parsed into a table, and I need to highlight rows that match selections from 5 dropdowns created from t ...

When the function $(document).width() is called, it may yield varying results depending on the timing of the call

Every time I use $(document).width(); within $(window).load(function(){}) or $(document).ready(function(){}), the result differs from when it is called inside $(window).resize(function(){}). The discrepancy is approximately 100px, and it's not due to ...

What is the process for utilizing jQuery's advanced ticker feature to extract content from a text file?

I am currently implementing this code on my website: <script> var file = "http://newsxpressmedia.com/files/theme/test.txt"; function getData(){ $.get(file,function(txt){ var lines = txt.responseText.split("\n"); for (var i = ...

Issues with the animation of the navbar menu button are preventing it from functioning

I have been attempting to incorporate animation when the navbar-button is toggled on smaller screen sizes. Inspired by the design of .navbar-toggle.larr in this particular template, I tried to implement a similar effect. /* ANIMATED LEFT ARROW */ .navbar- ...

What steps can I take to ensure that the information in my Cart remains consistent over time?

I recently built a NextJS application integrating the ShopifyBuy SDK. My implementation successfully fetches products from the store and displays them to users. Users can navigate to product pages and add items to their cart. However, I encountered an iss ...

Incorporate Subtitles into Your Website Using JWPlayer

I want to incorporate Video Captions similar to those seen on Lynda.com, for example at The captions should synchronize with the player and also appear in a separate block of HTML below the player. I am using JWPlayer for my video and have successfully in ...

Adding Labels to Doughnut Charts in React using Chart.js 2.0

Currently, I'm exploring the world of data visualizations using react, react-chartjs-2, and chart.js version 2.2.1. While searching for a solution to my inquiry, I came across a potentially relevant answer on this link (specifically check out the upda ...

How to iterate over an array and assign values to distinct labels using AngularJS

Challenge My goal is to present the user with information about their upcoming 4 events. I have used splice on an array to extract the first 4 objects. Now, I need to iterate through these objects and display the relevant data. Each label is unique and w ...

"Troubleshooting a bug: GetElementById function fails to find elements with hyphenated

When calling attr('id') on an immutable id attribute for an HTML element, my code runs smoothly when the id contains no hyphens. However, it encounters issues when the id includes a hyphen. $('.coloursContainer .radio-box').live(' ...

"Exploring the world of JavaScript through the lens of time

This summer, I have the opportunity to assist a friend with some JavaScript challenges on his website. The main issue seems to revolve around technical difficulties with online form submissions. Unfortunately, there are instances where we struggle to verif ...

Using jQuery to append text after multiple element values

I currently have price span tags displayed on my website: <div> <span class="priceTitle">10.00</span> </div> <div> <span class="priceTitle">15.00</span> </div> <div> <span class="priceTitle">20.0 ...

Class does not have the capability to deserialize an array

I encountered this issue with my code (see image): Here is the snippet of my code: function CheckLoginData() { var user = []; user.Email = $("#tbEmail").val(); user.Password = $("#tbPassword").val(); $.ajax({ type: "POST", contentType: "applic ...

Revolutionary CSS and jQuery for an Exceptional Top Navigation Experience

I would like to create a top navigation similar to the one on Facebook, using CSS and jQuery. Here is an example: Additionally: Notice how the arrow in the popbox always remains beneath the selected navigation item, and all popboxes have the same width. ...