JSFiddle - React, Tailwind, and code Playground

HTML

<body>
   <div class="game">
      <!-- <h1 id="title"> Tic-Tac-Toe </h1> -->
      <div id="grid">
         <table>
            <tr id="rowOne">
               <td class="button" id="b1"></td>
               <td class="button" id="b2"></td>
               <td class="button" id="b3"></td>
            </tr>
            <tr id="rowTwo">
               <td class="button" id="b4"></td>
               <td class="button" id="b5"></td>
               <td class="button" id="b6"></td>
            </tr>
            <tr id="rowThree">
               <td class="button" id="b7"></td>
               <td class="button" id="b8"></td>
               <td class="button" id="b9"></td>
            </tr>
         </table>
      </div>
   </div>
</body>

CSS

#title {
   font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
   font-size: 27.7px;
}

#grid {
   width: 175px;
   height: 175px;
   position: absolute;
   top: 0;
   left: 0;
   right: 0;
   bottom: 0;
   margin-top: auto;
   margin-left: auto;
   margin-right: auto;
   margin-bottom: auto;
}

.button {
   width: 50px;
   height: 50px;
   border: 2px solid #000000;
   font-family: Arial, Helvetica, sans-serif;
   font-size: 30px;
   text-align: center;
}

.button:hover {
   background-color: #f0f0f0;
   cursor: pointer;
}

.button:active {
   background-color: #dddddd;
}

.x {
   color: #ffffff;
   background-color: #42a1f4;
   content: "X";
}

.x:hover {
   background-color: #42a1f4;
   cursor: default;
}

.x:after {
   content: "X";
}

.o {
   color: #ffffff;
   background-color: #b73a43;
}

.o:hover {
   background-color: #b73a43;
   cursor: default;
}

.o:after {
   content: "O";
}

JavaScript

player = true; //true = human, false = ai
_gameEnded = 0; //default to game running
result = 2; //default to placeholder value

$(".button").bind("click", function() { //add x or o to button clicked
   if ($(this).hasClass("x") || $(this).hasClass("o") || _gameEnded)
      return; //dont do anything if a button has x or o already or the game has ended
   $(this).toggleClass("x"); //add x or o depending on current player
   player = !player; //switch player
   checkGameEnd(); //check if game ended
   computerMove(); //let the ai make a move
});

function computerMove() {
   if (_gameEnded == 0 && !player) { //execute only when game is running (to prevent adding after win/loss alert)
		
		var gameStatus = getGameStatus();
		var field = getNextMove(gameStatus);
      var btnId = "#b" + field;
      $(btnId).toggleClass("o"); //add o the the randomly chosen button
		player = !player; //switch player
      checkGameEnd(); //check if game ended
   } 	
}

function getNextMove(gameStatus) {
	var bestZ, bestS; //values to assign best slot to later on
	var bestValue = -2; //placeholder value to be replaced with result value
	for (var z = 0; z < 3; z++) { //loop for row
		for (var s = 0; s < 3; s++) { //loop for column
			if (gameStatus[z][s]) //if current slot has an x or o, 
				continue; //skip it			
			var nextMove = cloneGameStatus(gameStatus); //create temporary array with base of current grid
			nextMove[z][s] = "o"; //assign first free field an o
			var value = evaluateMove(nextMove, false, 0); //evaluate the move from the line above
			if (value > bestValue) { //assign best values to calculate the best slot
				bestZ = z;
				bestS = s;
				bestValue = value;
			}			
		}
	}
	return (bestZ) * 3 + bestS + 1; //return calculated number of best slot
}

function evaluateMove(move, player, depth) {
	var gameStatus = evaluateGameStatus(move); //get status of current board
	if (gameStatus < 2 && player)
		return gameStatus; //return gameStatus for human move
	if...