Question concering cleaner tic tac toe "ai"

Hey all! I’ve been working on my tic tac toe game the past couple of days and while I feel I can get it to do what I need, I feel the code could be much more condensed. I haven’t finished all of the ai for the computer moves yet but it’s looking to be around 70+ if else statements which seems extreme. Any better ways to tackle this? Any help is appreciated!

Here’s the code I’m talking about. The full site is at http://codepen.io/jeffm64/pen/BLmjvv?editors=1011

function computerAI() {

//Win: If you have two in a row, play the third to get three in a row.
if(board[0][0] === player2.symbol && board[0][1] === player2.symbol && board[0][2] !== player1.symbol && board[0][2] !== player2.symbol) {
  $(".tp-right").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
  board[0][2] = player2.symbol;
}
else if(board[0][1] === player2.symbol && board[0][2] === player2.symbol && board[0][0] !== player1.symbol && board[0][0] !== player2.symbol) {
  $(".tp-left").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
  board[0][0] = player2.symbol;
}
//Block: If the opponent has two in a row, play the third to block them.
//Fork: Create an opportunity where you can win in two ways.
//Block Opponent's Fork:
//Option 1: Create two in a row to force the opponent into defending, as long as it doesn't result in them creating a fork or winning. For example, if "X" has a corner, "O" has the center, and "X" has the opposite corner as well, "O" must not play a corner in order to win. (Playing a corner in this scenario creates a fork for "X" to win.)
//Option 2: If there is a configuration where the opponent can fork, block that fork.
//Center: Play the center.
else if(board[1][1] === "") {
  $(".md-mid").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
  board[1][1] = player2.symbol;
}
//Opposite Corner: If the opponent is in the corner, play the opposite corner.
 else if(board[0][0] === player1.symbol && board[2][2] !== player2.symbol) {
   $(".bm-right").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
   board[2][2] = player2.symbol;
 }
 else if(board[0][2] === player1.symbol && board[2][0] !== player2.symbol) {
   $(".bm-left").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
   board[2][0] = player2.symbol;
 }
 else if(board[2][0] === player1.symbol && board[0][2] !== player2.symbol) {
   $(".tp-right").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
   board[0][2] = player2.symbol;
 }
 else if(board[2][2] === player1.symbol && board[0][0] !== player2.symbol) {
   $(".tp-left").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
   board[0][0] = player2.symbol;
 }
//Empty Corner: Play an empty corner.
 else if(board[0][0] === "") {
   $(".tp-left").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
   board[0][0] = player2.symbol;
 } 
 else if(board[0][2] === "") {
   $(".tp-right").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
   board[0][2] = player2.symbol;
 }
 else if(board[2][0] === "") {
   $(".bm-left").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
   board[2][0] = player2.symbol;
 }
 else if(board[2][2] === "") {
   $(".bm-right").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
   board[2][2] = player2.symbol;
 }
//Empty Side: Play an empty side.
else if(board[1][0] === "") {
  $(".md-left").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
  board[1][0] = player2.symbol;
}
else if(board[1][2] === "") {
  $(".md-right").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
  board[1][2] = player2.symbol;
}
else if(board[0][1] === "") {
  $(".tp-mid").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
  board[0][1] = player2.symbol;
}
else if(board[2][1] === "") {
  $(".bm-mid").append("<span class='" + player2.symbol +"'>" + player2.symbol +"</span>");
  board[2][1] = player2.symbol;
}   

checkWin();
if(diagonalComplete1 === 3 || diagonalComplete2 === 3) {
  console.log("You win");
}
else {
  player1.turn = true;
  player2.turn = false;
}

}

1 Like

Well there’s definitely a lot of decision making in a program like this, so you’re going to have some if / else up in there, but 70 does seem like a bit much. I count around 20 - 25 in my version of the program, and that’s for everything, not just the game logic.

You’re welcome to take a look at my code for ideas, I hope it helps. BTW, I like your CSS. My version isn’t as pretty.

Check out min-max algorithm

I have actually researched it quite a bit since starting this challenge. I feel like I get the concept in that the computer goes through each scenario of possible moves and picks the one that gives the most “points”. It’s just anytime I look at it in code it makes no sense at all to me.

Yeah yours is definetly a bit more clean. Without using minimax I feel the best way to condense seems to be figuring out ways to use for loops for move making rather than just if else statements. Thanks for the compliment! I have a degree in design so it makes it hard to not make it look decent but sometimes I feel I’m spending too much time designing it considering I’m trying to become front end rather than a web designer.

I feel ya. When I started reading about min-max, conceptually I understood but implementing was another thing.

Eventually what helped is literally draw scenarios on a paper and tried to figure it out how to do it by code. After learning Object-Oriented from Udacity’s free course (which is great by the way if you want to learn OO in JS), that helped my organization and eventually got me through.

I will tell you right now, I’d say the AI tic-tac-toe was the most challenging thing I’ve done here in FCC so don’t feel too stressed. It’s meant to be hard!

1 Like