Pen Settings

HTML

CSS

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. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

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

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

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.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div id="banner">
  <h1> TIC TAC TOE</h1>
</div>
<div id="options">
  <p> Choose your option</p>
  <button id="x">X</button>
  <button id="o">O</button>
</div>
<div id="choice">
  <p id="choiceMsg"></p>
</div> 
<table id="game">
  <tr>
    <td id="one" data-value="1">
      <div class="up-dots">
        <i class="fa fa-dot-circle-o pull-right"></i>
      </div>
      <div class="center-space">
      </div>
      <div class="down-dots">
      <i class="fa fa-dot-circle-o pull-left"></i>
      <i class="fa fa-dot-circle-o pull-right"></i>
      </div>
    </td>
    <td id="two" data-value="2">
      <div class="placeholder">
      </div>
      <div class="center-space">
      </div>
      <div class="placeholder">
      </div>
    </td> 
    <td id="three" data-value="3">
      <div class="up-dots">
        <i class="fa fa-dot-circle-o pull-left"></i>
      </div>
      <div class="center-space">
      </div>
      <div class="down-dots">
      <i class="fa fa-dot-circle-o pull-left"></i>
      <i class="fa fa-dot-circle-o pull-right"></i>
      </div>
    </td>
  </tr>
  <tr>
    <td id="four" data-value="4">
      <div class="placeholder">
      </div>
      <div class="center-space">
      </div>
      <div class="placeholder">
      </div>
    </td>
    <td id="five" data-value="5">
      <div class="placeholder">
      </div>
      <div class="center-space">
      </div>
      <div class="placeholder">
      </div>
    </td> 
    <td id="six" data-value="6">
      <div class="placeholder">
      </div>
      <div class="center-space">
      </div>
      <div class="placeholder">
      </div>
    </td>
  </tr>
  <tr>
    <td id="seven" data-value="7">
      <div class="down-dots">
        <i class="fa fa-dot-circle-o pull-left"></i>
        <i class="fa fa-dot-circle-o pull-right"></i>
      </div>      
      <div class="center-space">
      </div>
      <div class="up-dots">        
        <i class="fa fa-dot-circle-o pull-right"></i>
      </div>
    </td>
    <td id="eight" data-value="8">
      <div class="placeholder">
      </div>
      <div class="center-space">
      </div>
      <div class="placeholder">
      </div>
    </td> 
    <td id="nine" data-value="9">
      <div class="down-dots">
        <i class="fa fa-dot-circle-o pull-left"></i>
        <i class="fa fa-dot-circle-o pull-right"></i>
      </div>      
      <div class="center-space">
      </div>
      <div class="up-dots">        
        <i class="fa fa-dot-circle-o pull-left"></i>
      </div>
    </td>
  </tr>
</table>
  <div id="details">
    
</div>
<center>
  <label id="result"></label>
  <div id="anotherGame">
    <p id="playAgain">Do you want to play again?</p>
    <button id="yes">YES</button>
    <button id="no">NO</button>
  </div>
</center>  
</div>
              
            
!

CSS

              
                body{
  background-color: #9C27B0;
  color: #ffd700;
  font-family: Oswald, sans-serif;
  font-size: 20px;
  text-transform: uppercase;
}

table {
  background-color: #9C27B0;
  cursor:pointer;
  border-collapse: collapse;
}

table td, table th {
  border: 3px solid #c0c0c0;
}
table tr:first-child td {
  border-top: 0;
}
table tr:last-child td {
  border-bottom: 0;
}
table tr td:first-child,
table tr th:first-child {
  border-left: 0;
}
table tr td:last-child,
table tr th:last-child {
  border-right: 0;
}

#game tr td{
  width:60px;
  height:80px;
}

#banner{
  text-align:center;
  padding-bottom:15px;
}

#options{
  display:flex;
  justify-content:center;
}

#choice{
  text-align:center;
  padding: 30px 0;
}

#game{
  width:400px;
  margin:0 auto;
  text-align:center;
  font-size:40px;
}
#details{
  diplay:flex;
  flex-wrap:wrap;
}
#accordion{
  max-width:500px;
  margin:0 auto;
  margin-top:10px;
}
button{
  width: 70px;
  padding:5px;
  background-color: transparent;
  border: 2px solid #c0c0c0;
  margin-left:10px;
  border-radius: 10px;
  font-weight: bolder;
}
#anotherGame{
  display:none;
  padding: 30px;
}


/*Added by Eduardo Sanchez*/

h1 {
  font-family: 'Ruslan Display', cursive;
  font-size: 72px;
}

.down-dots,
.up-dots,
.placeholder {
  clear: both;
  width: 100%;
  heigth: 20px;
}

.down-dots .fa,
.up-dots .fa{
  display: none;
}

.center-space {
  height: 80px;
  color: #c0c0c0;
}

.center-space .fa {
  position: relative;
  top: 10%;
}

.fa-dot-circle-o {
  font-size: 14px;
  color: #c0c0c0;
}

.fa-stop-circle {
  color: #ffd700;
}

#result {
  padding-top: 80px;
}

              
            
!

JS

              
                var board=[];
var userChoice
var currentTurn

function minmax(){
  this.minPlayer=1;
  this.maxPlayer=2;
}

/*Setting the min and max values once we get the choice from the user*/
minmax.prototype.setMinMax=function(min,max){
  this.minPlayer=min;
  this.maxPlayer=max;
}

/*Copying the current configuration of the board and returning it. We do this since we need more have to operate on induvidual board instances on deeper depths 
*/
minmax.prototype.copyBoard=function(board){
  return board.slice(0);
}

/*This function checks if a position is free on the board and makes the move. If the position is free, it makes a move and returns the new board, else returns the old board.
*/
minmax.prototype.makeMove=function(position,board,player){
  if(board[position]==0){
    var newBoard=this.copyBoard(board);
    newBoard[position]=player;
    return newBoard;
  }
  else{
    return null;
  }
}

/*The main implementation of Minax algorithm. Since we are already making the max players move here, we call the minMove function here. The minMove and maxMove functions flicker between each other until a score is available. This function returns the bestmove for the computer for the given board configuration. 
*/
minmax.prototype.minMaxAlgo=function(board){
  var bestValue=-100;
  var bestMove=0;
  var newBoard=[];
  var value;
  for(var i=0;i<board.length;i++){
    newBoard=this.makeMove(i,board,this.maxPlayer);
    if(newBoard){
      value=this.minMove(newBoard);
      if(value>bestValue){
        bestValue=value;
        bestMove=i;
      }
    }
  }
  return bestMove;
}

/*This function depicts the moves of the player, it returns the final score of the board configuration if either of the players won or if it is a tie. Else it calls the maxMove function
*/
minmax.prototype.minMove=function(board){
  if(this.won(this.minPlayer,board)){
    return -10;
  }
  else if(this.won(this.maxPlayer,board)){
    return 10;
  }
  else if(this.isTie(board)){
    return 0;
  }
  else{
    var leastValue=100;
    for(var i=0;i<board.length;i++){
      var newBoard=this.makeMove(i,board,this.minPlayer);
      if(newBoard){
        var value=this.maxMove(newBoard);
        if(value<leastValue){
          leastValue=value;
        }
      }
    }
    return leastValue;
  }
}

/*This function depicts the moves of the computer, it returns the final score of the board configuration if either of the players won or if it is a tie. Else calls the minMove function
*/
minmax.prototype.maxMove=function(board){
  if(this.won(this.minPlayer,board)){
    return -10;
  }
  else if(this.won(this.maxPlayer,board)){
    return 10;
  }
  else if(this.isTie(board)){
    return 0;
  }
  else{
    var maxValue=-100;
    for(var i=0;i<board.length;i++){
      var newBoard=this.makeMove(i,board,this.maxPlayer);
      if(newBoard){
       var value=this.minMove(newBoard);
        if(value>maxValue){
          maxValue=value;
        }
      }
    }
    return maxValue;
  }
}

/*In this function we haveto check whether the player in the current board configuration has won the game or not. For a win we have to check the row , columns and diagnols respectively
*/
minmax.prototype.won=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;
  }
}

/*Since the board is populated with 0's in empty positions, I am checking for 0's, if I find any I will return the value as false else as true
*/
minmax.prototype.isTie=function(board){
  for(var i=0;i<board.length;i++){
    if(board[i]==0){
      return false;
    }
  }
  return true;
}

//End of the MinMax algorithm

$(function() {
  game=new minmax(board);
  board=[0,0,0,0,0,0,0,0,0];
  $("#game").css("pointer-events", "none");
  console.log(board);
});

/*The main function which handles the user inputs. It basically makes a check of two important conditions and if they satify, it continues processing the input. They are 
1. Check if the current turn is the users turn, as the user might click on the board, while the computer is processing its move, if the computer accepts this move, then the game goes haywire .
2. Check if the board position is already filled. It doesnt make sense to accept input into a box which is already filled. Yet to make sure even that the computer doesnt accept it as there might be accidental clicks, this condition should be in place  
*/
$("td").click(function(e){
  console.log(currentTurn);
  if(currentTurn=="user"){
      var id=$(this).attr("id");
      var value=$("#"+id).attr("data-value");
      if(board[value-1]==0){
          $("#game").css("pointer-events", "none");
          $(convertValueToDiv(value-1) + " .center-space").html(userChoice);
          board[value-1]=game.minPlayer;
          if(game.won(game.minPlayer,board)){
           $("#result").text("You win");
           $("#anotherGame").css("display","block");
          }
          else if(game.isTie(board)){
            $("#result").text("Its a tie");
            $("#anotherGame").css("display","block");
          }
          else{
            currentTurn="computer";
            setTimeout(delayComputerMove,1000);

          }
      }
  } 
});

function delayComputerMove(){
  var move=game.minMaxAlgo(board);
  console.log(move);
  board[move]=game.maxPlayer;
  $(convertValueToDiv(move) + " .center-space").html(computerChoice);
  setTimeout(function(){currentTurn="user";},0);
  if(game.won(game.maxPlayer,board)){
    $("#result").text("Computer wins");
    $("#anotherGame").css("display","block");
  }
  else if(game.isTie(board)){
    $("#result").text("Its a tie");
    $("#anotherGame").css("display","block");
  }
  else{
    $("#game").css("pointer-events", "auto");
  }
}

$("#x").click(function(){
  currentTurn="user";
  $("#choiceMsg").text("You have choosen X, and X goes first !!");
  $("#options").toggle(1000);
  computerChoice="<i class='fa fa-stop-circle animated flip'></i>";
  userChoice="<i class='fa fa-times animated flip'></i>";
  game.setMinMax(2,1);
  $("#game").css("pointer-events", "auto");
  console.log(board);
});

$("#o").click(function(){
  $("#game").css("pointer-events", "auto");
  currentTurn="computer";
  $("#choiceMsg").text("You have choosen O but X goes first ");
  $("#options").toggle(1000);
  setTimeout(delayO,1000);
});

$("#yes").click(function(){
  board=[0,0,0,0,0,0,0,0,0];
  $("td .center-space").empty();
  $("#anotherGame").css("display","none");
  $("#result").text("");
  $("#choiceMsg").text("");
  $("#options").toggle(1000);
});

$("#no").click(function(){
  $("#game").css("pointer-events", "none");
  $("#choiceMsg").text("");
  $("#anotherGame").css("display","none");
  $("td").empty();
  $("#result").text("Refresh page to play again");
});

/*An initial delay when the computer goes first, to create an illusion that the computer is thinking. Also inrespect of the design perspective, when the the options toggle out, the first move of the computer appears
*/
function delayO(){
  $('#game').attr("disabled", "disabled");
  userChoice="<i class='fa fa-stop-circle animated flip'></i>";
  computerChoice="<i class='fa fa-times animated flip'></i>";
  game.setMinMax(1,2);
  myMax=8;
  myMin=0;
  /*Generating a random first move for the computer, because when the computer goes first, the first move doesnt matter.  Also it takes lot of time for the computer to generate a first move with empty board, as it has to evaluate a lot of board positions. 
  */
  var move= Math.floor(Math.random()*(myMax-myMin+1))+myMin;
  board[move]=game.maxPlayer;
  var divId=convertValueToDiv(move);
  $(divId + " .center-space").html(computerChoice);
  console.log(board);
  setTimeout(function(){currentTurn="user";},0);
}

/*Return the divisionId for a corresponding value. This method is useful when the computer goes first and generates a random move. To represent the move on the table, we need a mapping between the value and the divId 
*/
function convertValueToDiv(value){
  var cases={0:"#one",1:"#two",2:"#three",3:"#four",4:"#five",5:"#six",6:"#seven",7:"#eight",8:"#nine"};
  return cases[value];
}
  


              
            
!
999px

Console