cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - ActiveLovehtmlicon-new-collectionicon-personicon-teamlog-outoctocatpop-outspinnerstartv

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.

Quick-add: + add another resource

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.

Quick-add: + add another resource

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.

            
              <div class="container">
  <div class="title">
    <h3>Tic Tac Toe</h3>
  </div>
  
  <div class="settings">
    <div class="player">
      <p>How do you want to play?</p>
      <button id="onePlayer">1 Player</button>
      <button id="twoPlayers">2 Players</button>
    </div>
    <div class="side">
      <p>Would you like to be X or O?</p>
      <button id="x">X</button>
      <button id="o">O</button>
    </div>
  </div>
  
  <div class="board">
    <div id="0" data-state="none"></div>
    <div id="1" data-state="none"></div>
    <div id="2" data-state="none"></div>
    <div id="3" data-state="none"></div>
    <div id="4" data-state="none"></div>
    <div id="5" data-state="none"></div>
    <div id="6" data-state="none"></div>
    <div id="7" data-state="none"></div>
    <div id="8" data-state="none"></div>
  </div>
  
  <div class="scores">
    <div class="first">
      <span id="firstPlayer">Player 1:</span> <span id="firstPlayerScore">0</span>
    </div>
    <div class="second">
      <span id="secondPlayer"></span> <span id="secondPlayerScore">0</span>
    </div>
  </div>
  
  <div class="reset">
    <button id="resetButton">Reset</button>
  </div>
  
  <div class="modal">
    <p id="message"></p>
    <button id="playAgain">PLAY AGAIN</button>
  </div>
  
</div>
            
          
!
            
              body {
  margin: 0;
  padding: 0;
  font-family: 'Signika', sans-serif;
}

.container {
  text-align: center;
  width: 350px;
  height: auto;
  margin: auto;
}

.title h3 {
  font-size: 30px;
}

.board, .settings {
  margin: auto;
  width: 300px;
  height: 300px;
  color: #fff;
  font-family: 'Architects Daughter', cursive;
  border-radius: 5px;
}


.settings {
  background-color: rgba(82, 164, 209, 1);
  display: flex;
  justify-content: center;
  align-items: center;
}

.settings p {
  font-size: 26px;
}

.settings button {
  font-family: 'Architects Daughter', cursive;
  background-color: rgba(82, 164, 209, 1);
  color: #fff;
  border: 1px solid #fff;
  border-radius: 5px;
  margin: 3px;
  font-size: 18px;
  width: 100px;
  cursor: pointer;
}

.settings button:hover {
  background-color: rgba(255, 255, 255, 0.4);
  transition: all 0.5s;
}

.board div {
  vertical-align: top;
  display: inline-block;
  background: rgba(76, 176, 230, 1);
  width: 85px;
  height: 85px;
  margin: 5px 2px;
  border-radius: 10px;
  cursor: pointer;
  font-size: 60px;
  font-weight: bold;
}

.board div:hover {
  background: rgba(62, 180, 244, 0.6);
  transition: all 0.5;
}

.scores {
  font-family: 'Architects Daughter', cursive;
  width: 300px;
  margin-top: 10px;
}

.first, .second {
  text-align: left;
  float: left;

}

.first {
  margin-left: 40px;
  margin-right: 20px;
}

.reset button {
  float: right;
  font-family: 'Architects Daughter', cursive;
  background-color: #fff;
  border: none;
  color: #000;
  border-radius: 5px;
  font-size: 15px;
  cursor: pointer;
}

.reset button:hover {
  border: 1px dashed #000 !important;
  transition: all 0.5s;
}

.reset button:active, .reset button:focus {
  outline: none;
  text-shadow: none;
  box-shadow: none !important;
  border-bottom: 1px solid #000;
}

.reset {
  margin-right: 35px;
  margin-top: 10px;
}

.x {
  background-color: rgba(222, 99, 189, 1) !important;
}

.o {
  background-color: rgba(197, 222, 99, 1) !important;
}

.modal {
  position: relative;
  margin: -222px auto;
  text-align: center;
  width: 190px;
  height: 110px;
  background-color: hsla(30, 12%, 23%, 0.9);
  color: #fff;
  border-radius: 10px;
  padding: 0;
}

.modal button {
  background-color: hsla(30, 10%, 20%, 0.95);
  color: #fff;
  border: none;
  height: 30px;
  width: 100px;
  position: absolute;
  left: 50%;
  top: 80%;
  transform: translate(-50%, -80%);
}
  
.modal button:hover {
  cursor: pointer;
  background-color: hsla(30, 10%, 30%, 0.95);
}

.modal p {
  font-size: 18px;
  width: 140px;
  position: absolute;
  left: 50%;
  top: 0%;
  transform: translate(-50%, -0%);
}
            
          
!
            
              var numPlayers, firstPlayer, secondPlayer, firstPlayerScore = 0, secondPlayerScore = 0, turn, firstTurn = false, endGame = false;
var $player   = $(".player"),
    $side     = $(".side"),
    $settings = $(".settings"),
    $board    = $(".board"),
    $scores   = $(".scores"),
    $boardDivs  = $(".board div"),
    $modal    = $(".modal"),
    $firstPlayerScore = $("#firstPlayerScore"),
    $secondPlayerScore = $("#secondPlayerScore");

// winning lines array
var win = [[1, 2, 3],
          [4, 5, 6],
          [7, 8, 9],
          [1, 4, 7],
          [2, 5, 8],
          [3, 6, 9],
          [1, 5, 9],
          [3, 5, 7]];

// an array that represents the state of each spot of the board
// each element at index x correspond to spot x of the board
var board_arr = ['', '', '', '', '', '', '', '', ''];

/** AI Logic that use MiniMax Algorithm to find the optimal move for the AI 
This MiniMax implementation is from http://richard.to/programming/ai-for-owari-part-2.html
**/

var MiniMax = function() {
  this.minPlayer;
  this.maxPlayer;
};

MiniMax.prototype.setMinMaxPlayers = function(maxPlayer, minPlayer) {
  this.minPlayer = minPlayer;
  this.maxPlayer = maxPlayer;
};

MiniMax.prototype.copyBoard = function(board) {
  return board.slice(0);
};

MiniMax.prototype.checkWinner = function(player, board) {
    if (
    (board[0] == player && board[1] == player && board[2] == player) ||
        (board[3] == player && board[4] == player && board[5] == player) ||
        (board[6] == player && board[7] == player && board[8] == player) ||
        (board[0] == player && board[3] == player && board[6] == player) ||
        (board[1] == player && board[4] == player && board[7] == player) ||
        (board[2] == player && board[5] == player && board[8] == player) ||
        (board[0] == player && board[4] == player && board[8] == player) ||
        (board[2] == player && board[4] == player && board[6] == player)
        ) {
        return true;
    } else {
        return false;
    }
};

MiniMax.prototype.checkTie = function(board) {
  for (var i = 0; i < board.length; i++) {
    if (board[i] === '')
      return false;
  }
  return true;
};


MiniMax.prototype.makeMove = function(move, player, board) {

  var newBoard = this.copyBoard(board);
  if (newBoard[move] === '') {
      newBoard[move] = player;
      return newBoard;
  } else {
      return null;
  }
};

MiniMax.prototype.findMove = function(board) {
  var bestMoveValue = -100;
  var move = 0;
  for (var i = 0; i < board.length; i++) {
    var newBoard = this.makeMove(i, this.maxPlayer, board);
    if (newBoard) {
      var predictedMoveValue = this.minValue(newBoard);
      if (predictedMoveValue > bestMoveValue) {
        bestMoveValue = predictedMoveValue;
        move = i;
      }
    }
  }
  return move;
};

MiniMax.prototype.minValue = function(board) {

    if (this.checkWinner(this.maxPlayer, board)) {
        return 1;
    } else if (this.checkWinner(this.minPlayer, board)) {
        return -1;
    } else if (this.checkTie(board)) {
        return 0;
    } else {
        var bestMoveValue = 100;
        var move = 0;
        for (var i = 0; i < board.length; i++) {
            var newBoard = this.makeMove(i, this.minPlayer, board);
            if (newBoard) {
                var predictedMoveValue = this.maxValue(newBoard);
                if (predictedMoveValue < bestMoveValue) {
                    bestMoveValue = predictedMoveValue;
                    move = i;
                }
            }
        }
        return bestMoveValue;
    }
};

MiniMax.prototype.maxValue = function(board) {
    if (this.checkWinner(this.maxPlayer, board)) {
        return 1;
    } else if (this.checkWinner(this.minPlayer, board)) {
        return -1;
    } else if (this.checkTie(board)) {
        return 0;
    } else {
        var bestMoveValue = -100;
        var move = 0;
        for (var i = 0; i < board.length; i++) {
            var newBoard = this.makeMove(i, this.maxPlayer, board);
            if (newBoard) {
                var predictedMoveValue = this.minValue(newBoard);
                if (predictedMoveValue > bestMoveValue) {
                    bestMoveValue = predictedMoveValue;
                    move = i;
                }
            }
        }
        return bestMoveValue;
    }
};


/**
 * Handle click event when player chooses number of players
 */
function choosePlayer() {
  $("#onePlayer").click(function() {
    numPlayers = 1;
    $player.hide();
    $side.fadeIn('slow');
    $scores.show();
    $(".first").show().addClass("animated fadeInLeft");
    $(".second").addClass("animated fadeInLeft");
    $("#secondPlayer").html("Computer:");
  });
  
  $("#twoPlayers").click(function() {
    numPlayers = 2;
    $player.hide();
    $side.fadeIn('slow');
    $scores.fadeIn('slow');
    $("#secondPlayer").html("Player 2:");
  });
}

/**
 * Handle click event when player chooses side
 */
function chooseSide() {  
  $('.side button').on('click', function(){
    if ($(this).text() === 'X') {
      firstPlayer = 'x';
      secondPlayer = 'o';
    }
    else {
      firstPlayer = 'o';
      secondPlayer = 'x';
    }
    $side.hide();
    $settings.hide();
    $board.fadeIn('slow');
    firstTurn = true;
  });
}

/*
 * Handle click event 9 spots on the board
 */
function boardClickHandler() {
  $boardDivs.on('click', function() {
    // Stop click event handler 
    // on the board if we have a winner
    if (endGame)
      return false;
    var state = $(this).data('state');
    if (numPlayers === 2) {
      // first turn of a game
      if (firstTurn) {
        turn = firstPlayer;
        firstTurn = false;
      }
      if (state === 'none') {
        doMove($(this), turn);
        turn = (turn === 'x') ? 'o' : 'x';
      }
      // check for Winner or Draw
      checkForWinner();
    }
    else if (numPlayers === 1) {
      // assign firstPlayer to minPlayer,  
      // secondPlayer to maxPlayer (AI) if game just starts
      if (firstTurn) {
        AILogic.setMinMaxPlayers(secondPlayer, firstPlayer);  
        firstTurn = false;
      }
      // check if spot is available and first player's turn
      if (state === 'none') {
        doMove($(this), firstPlayer);
      }
      // check for Winner or Draw
      checkForWinner();
      
      // AI's turn
      // find AI move
      var aiMove = AILogic.findMove(board_arr);
      // do AI move
      doMove($('#'+aiMove), secondPlayer);
      // check for winner
      checkForWinner();
    }
  });
}

/*
 * add class, change data-state attribute, and add text to the 
 * corresponding spot on board
 * spot: DOM object (1 of the 9 spot in the board)
 * move: either 'x' or 'o'
 */
function doMove(spot, move) {
  spot.addClass(move);
  spot.html(move);
  spot.data('state', move);
 
  var index = parseInt(spot.attr("id"));
  board_arr[index] = move;
}

/*
 * Check for the winner and print the result
 */
function checkForWinner() {
  // call hasWon function to check if there is a win
  var winner = hasWon();
  // There is a winner, display winning message
  if (winner) {
    if (firstPlayer === winner) {
      $('#message').html("Player 1 has won!");
      // set first player'score
      firstPlayerScore += 1;
      $firstPlayerScore.html(firstPlayerScore);
    }
    else {
      // set second player's score
      secondPlayerScore += 1;
      $secondPlayerScore.html(secondPlayerScore);
      if (numPlayers === 2)
        $('#message').html("Player 2 has won!");
      else
        $('#message').html("The computer has won!");
    }
  // show modal
  $modal.show();
  $modal.addClass("animated bounceInUp");
  }
  // there is no winner yet
  else {
    var draw = checkTie();
    if (draw) {
      endGame = true;
      $('#message').html("It's a draw!");
      // show modal
      $modal.show();
      $modal.addClass("animated bounceInUp");
    }
      
  }
}

/*
 * Check if there is a win 
 */
function hasWon() {
  var state1, state2, state3;
  for (var i in win) {
    state1 = board_arr[win[i][0]-1];
    state2 = board_arr[win[i][1]-1];
    state3 = board_arr[win[i][2]-1];
    if (state1 === state2 && state1 === state3 && state1 !== '') {
      endGame = true;
      return state1; 
    }
  }
  return false;
}

/*
 * Check if there is any available spot left
 * if not, then it is a tie
 */
function checkTie() {
  for (var i in board_arr) {
    if (board_arr[i] === '')
      return false;
  }
  // tie
  return true;
}

/*
 * Start a new game with current settings
 */
function startNewGame() {
  firstTurn = true;
  endGame = false;
  $modal.fadeOut(500);
  $boardDivs.each(function() {
    $(this).removeClass('x').removeClass('o');
    $(this).data('state', 'none');
    $(this).html("");
  });
  // reset board_arr 
  for (var i = 0; i < board_arr.length; i++) {
    board_arr[i] = "";
  }
}


/**
 * Reset the entire game
 */
function reset() {
  // reset game
  startNewGame();
  // reset player scores
  firstPlayerScore = secondPlayerScore = 0;
  $firstPlayerScore.html(firstPlayerScore);
  $secondPlayerScore.html(secondPlayerScore);
  // reset all settings
  $scores.hide();
  $player.fadeIn('slow');
  $side.hide();
  $board.hide();
  $settings.show();
}

// create MiniMax Object
var AILogic = new MiniMax();

$(document).ready(function() {
  $side.hide();
  $scores.hide();
  $board.hide();
  $modal.hide();
  choosePlayer();
  chooseSide();

  boardClickHandler();
  $("#resetButton").addClass("animated fadeInRight");
  $("#resetButton").on('click', reset);
  $("#playAgain").on('click', startNewGame);
});



            
          
!
999px
Loading ..................

Console