css Audio - Active file-generic CSS - Active Generic - Active HTML - Active JS - Active SVG - Active Text - Active file-generic Video - Active header Love html icon-new-collection icon-person icon-team numbered-list123 pop-out spinner split-screen star tv

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              <body>
      <div id="chooseToken" class="chooseToken container-fluid">
        <div id="winnerDiv"></div>
        <div class="chooseTokenContent">
            <p class="chooseTokenText">Select your token:</p>
            <button class="choiceButton btn btn-primary" value="X">X</button>
            <button class="choiceButton btn btn-primary" value="O">O</button>
        </div>
    </div>

  <div id="gridContainer">
    <h2 id="status">Tic Tac Toe</h2><br>
    <table>
      <tr>
        <td id="0" value="0" class="cell top left"></td>
        <td id="1"  value="1"  class="top cell"></td>
        <td id="2"  value="2" class="top right cell"></td>
      </tr>
      <tr>
        <td id="3"  value="3" class="cell left"></td>
        <td id="4" value="4" ></td>
        <td id="5"  value="5" class ="cell right"></td>
      </tr>
      <tr>
        <td id="6"  value="6" class="cell bottom left"></td>
        <td id="7"  value="7" class="cell bottom"></td>
        <td id="8" value="8"  class="cell bottom right"></td>
      </tr>
    </table>
    <!--  <p id="winner">It is on!</p> -->
    <button id="reset">Reset</button>
  </div>



  <footer></footer>
  <script src="https://code.jquery.com/jquery-2.2.4.min.js"   integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="   crossorigin="anonymous"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
  <script src="js/ticTacToe.js"></script>
</body>
</html>

            
          
!
            
              * {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  font-family: Helvetica, Verdana, sans-serif;
}

#gridContainer {
text-align: center;
}

h2 {
  margin-top: 20%;
}

table {
  width: 500px;
  height: 500px;
  margin: 10% auto;
}

td {
  border: 1px solid gray;
  width: 125px;
  height: 125px;
  text-align: center;
  font-size: 70px;
  font-weight: 900;
}

.chooseToken {
  display: none;
  position: fixed;
  z-index: 1;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.4);
  text-align: center;
}

#winnerDiv {
  display: none;
  font-size: 2.5em;
  font-weight: 900;
  background-color: #fff;
  border: 1px solid #ddd;
  margin: 10% auto;
  width: 350px;
  padding: 50px;
  border-radius: 200px;
}

.chooseTokenContent {
  background-color: #fff;
  border: 1px solid #ddd;
  margin: 10% auto;
  width: 350px;
  padding: 50px;
  border-radius: 200px;
}

.choiceButton {
  font-size: 1.8em;
  font-weight: 900;
  width: 3em;
  height: 3em;
  margin: 20px;
  box-shadow: 5px 5px 5px 2px #ddd;
}

.chooseTokenText {
  font-size: 2.5em;
}

.top {
  border-top: none;
}
.left {
  border-left: none;
}
.right {
  border-right: none;
}
.bottom {
  border-bottom: none;
}

            
          
!
            
              // Global Vars
//ToDo: Make a class named "State" that will include all information
//concerning the state of the game
  var move,
      playerToken = "X",
      aiToken = "O",
      board = ["","","","","","","","",""],
      cellArray = document.getElementsByTagName("td"),
      playerBoard = [],
      aiBoard = [],
      playerTurn = false,
      aiTurn = false,
      nextMove,
      win = false, lose = false, tie = false,
      aiMoveCount,
      playerMoveCount,
      gameOver = false,
      winners = [
              [0, 1, 2],
              [3, 4, 5],
              [6, 7, 8],
              [0, 3, 6],
              [1, 4, 7],
              [2, 5, 8],
              [0, 4, 8],
              [2, 4, 6],
          ];

//setup functions
//count the moves by counting occupied board fields
function countMoves(player) {
  if (player == "ai"){
    return aiMoveCount = board.filter(function(value){
      return value === aiToken;
    }).length;
  }
  else if (player == "user"){
    return playerMoveCount = board.filter(function(value){
      return value === playerToken;
    }).length;
  }
}
//draw tokens on the board and update board Array
function updateBoard(val, token, playingBoard) {
  board[val] = token;
  document.getElementById(val).innerHTML = token;
  playingBoard.push($("#"+val).attr("value"));
}
//set up cell click handler
function setupCellClickHandler() {
  for (var i = 0; i<cellArray.length; i++ ){
    if (cellArray[i].innerHTML === "") {
      cellArray[i].addEventListener("click", cellClickHandler);
    }
  }
}
function cellClickHandler(e){
  //ToDo: avoid function call by click on non-empty fields
  if (playerTurn && e.target.innerHTML === "" && !gameOver){
  updateBoard(e.target.id, playerToken, playerBoard);
  countMoves("user");
  //set AI up for next turn
  winnerCheck();
  playerTurn = false;
  aiTurn = true;
  //call function for AI move
  play();
  }
}
//Clear grid
function clearGrid() {
  //reset the grid
    for (var i =0; i<cellArray.length; i++) {
   cellArray[i].innerHTML = "";
    }
    //reset game variables
    gameOver = false;
    board = ["","","","","","","","",""];
    aiBoard = [];
    win = lose = tie = false;
    playerBoard = [];
    aiMoveCount = 0;
    winningArray = [];
    tokenChoice();
  }
function init () {
//setup reset button
document.getElementById("reset").addEventListener("click", clearGrid);
tokenChoice();
setupCellClickHandler()
}
//token choice for the player
function tokenChoice() {
            var chooseToken = document.getElementById("chooseToken");
            var choiceBtn = document.querySelector(".chooseTokenContent");
            var winnerDiv = document.getElementById("winnerDiv");
            winnerDiv.style.display = "none";
            choiceBtn.style.display = "block";
            chooseToken.style.display = "block";
            choiceBtn.addEventListener("click", function(e) {
                playerToken = e.target.value || "X";
                if (playerToken === "X"){
                  aiToken = "O";
                  playerTurn = true;
                }
                else {
                  aiToken = "X";
                }
                chooseToken.style.display = "none";
                if (playerToken === "O") {
                    playerTurn = false;
                    play();
                }
            });
        }

//game control functions
//run the game
function play() {
  //it needs to be ai's turn and no gameOver
    if (!playerTurn && !gameOver){
      countMoves("user");
  //If user hasn't made 2 moves yet there is no need for defense
  if (playerMoveCount < 2){
    //first ai move should be upper left corner
    if (board[0] === ""){
      setTimeout(function() {
        nextMove = 0;
        updateBoard(nextMove, aiToken, aiBoard);
        countMoves("ai");
        playerTurn = true;
      }, 300);
    }//end board[0] if
    //second ai move is the opposite corner
    else if (board[8] === "") {
      setTimeout(function() {
        nextMove = 8;
        updateBoard(nextMove, aiToken, aiBoard);
        countMoves("ai");
        playerTurn = true;
      }, 300);
    }//end else if
    //alternative ai move if 0 and 8 are both taken
    else {
      setTimeout(function() {
        nextMove = 2;
        updateBoard(nextMove, aiToken, aiBoard);
        countMoves("ai");
        playerTurn = true;
      }, 300);
    }//end else
  }// end playerMoveCount if
      // after two ai moves it gets a little more complicated :)
      else {
        setTimeout(function() {
          //the following iterations could also be done with winners.some and return true or false
          winners.map(function(a) {
            if (board[a[0]] === aiToken && board[a[1]] === aiToken && board[a[2]] === "" || board[a[0]] === aiToken && board[a[2]] === aiToken && board[a[1]] === "" || board[a[1]] === aiToken && board[a[2]] === aiToken && board[a[0]] === "") {
              if (aiTurn) {
              checkForWinningMove();
              updateBoard(nextMove, aiToken, aiBoard);
              countMoves("ai");
              winnerCheck();
              playerTurn = true;
              aiTurn = false;
              }
            }
          });
            //check if defense is necessary
            winners.map(function(a) {
              if (board[a[0]] === playerToken && board[a[1]] === playerToken && board[a[2]] === "" || board[a[0]] === playerToken && board[a[2]] === playerToken && board[a[1]] === "" || board[a[1]] === playerToken && board[a[2]] === playerToken && board[a[0]] === "" ) {
                if (aiTurn) {
                  checkForDefense();
                  updateBoard(nextMove, aiToken, aiBoard);
                  countMoves("ai");
                  winnerCheck();
                  playerTurn = true;
                  aiTurn = false;
              }
            }
          });
            //if neither winning nor defending is possible choose next attacking move
            winners.map(function(a) {
            if (board[a[0]] === aiToken && board[a[1]] === "" && board[a[2]] === "" || board[a[1]] === aiToken && board[a[0]] === "" && board[a[2]] === "" || board[a[2]] === aiToken && board[a[0]] === "" && board[a[1]] === "" || board[a[2]] === aiToken && board[a[0]] === playerToken && board[a[1]] === "" || board[a[2]] === playerToken && board[a[0]] === aiToken && board[a[1]] === "") {
              if (aiTurn) {
                aiAttackingMove();
                updateBoard(nextMove, aiToken, aiBoard);
                countMoves("ai");
                winnerCheck();
                playerTurn = true;
                aiTurn = false;
              }
            }
          }); //end mapping through winners array
        }, 300);
      }//end else
    }//end outer if
}//end of play()
//checking if ai has only one move to win
function checkForWinningMove(){
  winners.map(function(a) {
    if (board[a[0]] === aiToken && board[a[1]] === aiToken && board[a[2]] === ""){
          nextMove = a[2];
          return nextMove;
        }
    else if (board[a[0]] === aiToken && board[a[2]] === aiToken && board[a[1]] === ""){
          nextMove = a[1];
          return nextMove;
        }
    else if (board[a[1]] === aiToken && board[a[2]] === aiToken && board[a[0]] === ""){
          nextMove = a[0];
          return nextMove;
        }
  });
}
//check defending moves
function checkForDefense() {
  winners.map(function(a) {
    if (board[a[0]] === playerToken && board[a[1]] === playerToken && board[a[2]] === ""){
      nextMove = a[2];
      return nextMove;
    }
    else if (board[a[0]] === playerToken && board[a[2]] === playerToken && board[a[1]] === ""){
      nextMove = a[1];
      return nextMove;
    }
    else if (board[a[1]] === playerToken && board[a[2]] === playerToken && board[a[0]] === ""){
      nextMove = a[0];
      return nextMove;
    }
  });
}
    //if defending not necessary, look for a winning move
        //If there is no danger of player winning and no possibility to
        // immediately win for AI
        // then AI should play its next token on a free field in a "winner" with
        // no player tokens in it, but one aiToken already there
function aiAttackingMove() {
  winners.map(function(a) {
    if (board[a[0]] === aiToken && board[a[1]] === "" && board[a[2]] === "") {
      nextMove = a[2];
      return nextMove;
    }
    else if (board[a[1]] === aiToken && board[a[0]] === "" && board[a[2]] === "") {
      nextMove = a[0];
      return nextMove;
    }
    else if (board[a[2]] === aiToken && board[a[0]] === "" && board[a[1]] === "") {
      nextMove = a[0];
      return nextMove;
    }
    //if nothing else fits there must be only two free fields left, pick the first one
    else if (board[a[2]] === aiToken && board[a[0]] === playerToken && board[a[1]] === "") {
      nextMove = a[1];
      return nextMove;
    }
    else if (board[a[2]] === playerToken && board[a[0]] === aiToken && board[a[1]] === "") {
      nextMove = a[1];
      return nextMove;
    }
});
}
//check for a winner
function winnerCheck() {
  //restart the game by resetting the board, moveCount and all game states
  //and displaying the token choice screen
    for (var i = 0; i<winners.length; i++) {
      //check for player win
      if (board[winners[i][0]] == playerToken && board[winners[i][1]] == playerToken && board[winners[i][2]] == playerToken){
        win = true;
        gameOver = true;
        showWinner();
        setTimeout(function() {
          clearGrid();
        }, 2000);
      }
      //check for player lose
      else if (board[winners[i][0]] == aiToken && board[winners[i][1]] == aiToken && board[winners[i][2]] == aiToken){
        lose = true;
        gameOver = true;
        showWinner();
        setTimeout(function() {
          clearGrid();
        }, 2000);
      }
      //check for a draw
      else if (aiToken == "X" && aiMoveCount == 5 || playerToken == "X" && playerMoveCount == 5) {
        tie = true;
        gameOver = true;
        showWinner();
        setTimeout(function() {
          clearGrid();
        }, 2000);
      }
    }
  }
//function that displays the winning combination
function showWinner() {
  //display the announcement div
  var winnerDiv = document.getElementById("winnerDiv");
  var chooseToken = document.getElementById("chooseToken");
  var choiceBtn = document.querySelector(".chooseTokenContent");
  winnerDiv.style.display = "block";
  choiceBtn.style.display = "none";
  chooseToken.style.display = "block";
  //check different game end scenarios
  if (win) {
    winnerDiv.innerHTML = "You Win! :)"
  }
  else if (lose) {
    winnerDiv.innerHTML = "You Lose! :("
  }
  else if (tie) {
    winnerDiv.innerHTML = "It's a Tie! :| "
  }
}
window.onload = init();

            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.
Loading ..................

Console