<body>
<div class="text-right">
    <h1 id='title'>Tic-Tac-Toe</h1>
  </div>
  <div class="container-fluid">
  <div class="jumbotron">
    <div class = 'board'>
                <div class='cell' id="0" ></div>
                <div class='cell' id="1" ></div>
                <div class='cell' id="2" ></div>
                <div class='cell' id="3" ></div>
                <div class='cell' id="4" ></div>
                <div class='cell' id="5" ></div>
                <div class='cell' id="6" ></div>
                <div class='cell' id="7" ></div>
                <div class='cell' id="8" ></div>
            </div>
    </div>
    <div class="text-center">
    <div id="reset">
      <i class="fa fa-refresh fa-5x"></i>
      </div>
      </div>
        </div>
  </div>
    </div>
<div id="deb"></div>
</body>
<div class="text-center panel">
    <p>'AI Based Tic-tac-toe' : A project by <a href="https://codepen.io/vikster098/" id="myself">Vikrant Deshpande</a><br>Inspired from <a href="https://mostafa-samir.github.io/Tic-Tac-Toe-AI/" id="myself">Mostafa Samir</a></p>
  </div>
*{
  -webkit-transition:300ms;
  font-family: 'Cabin';
}
body{
  background-image:url('http://www.publicdomainpictures.net/pictures/120000/velka/mint-green-diffused-background.jpg');
  background-repeat: no-repeat;
  background-attachment: fixed;
}
.jumbotron{
  background:rgba(0,0,0,0.0);
}
#title
{
  color:black;
  letter-spacing:3px;
  margin-right:20px;
  font-weight:600;
  display:inline-block;
}
#title:hover{
  text-decoration:none;
  color:#2c2d2d;
  cursor:default;
  transition-delay:50ms;
  transition-duration:100ms;
}
#myself:hover{
  text-decoration:none;
  background:rgba(0,0,0,0.3);
  border-radius:2px;
  transition-delay:50ms;
  transition-duration:300ms;
  padding: 6px;
  display:inline;
}
.panel{
  margin-bottom:0px;
  margin-top:150px;
  padding-top:10px;
  background:rgba(255,255,255,0.8);
  font-size:20px;
}
.board {
    height: 450px;
    width: 450px;
    margin: 0 auto;
}
.cell
{
    width: 150px;
    height: 150px;
    border: 1px solid grey;
    cursor:pointer;
    float:left;
    line-height: 140px;
  border-radius:20px;
    text-align: center;
  background:rgba(0,0,0,0.2);
    font-weight: bold;
    font-size: 70px;
  transition:all 0.9s;
}
.occupied
{
  font-family:Helvetica;
}
.cell:hover{
  box-shadow: 300px 0 0 0  rgba(0,0,0,0.15) inset, -300px 0 0 0  rgba(0,0,0,0.15) inset;
}
.control
{
  font-size:20px;
}
.level
{
    margin: 0 15px;
    color: lightskyblue;
    cursor: pointer;
}
.not-selected {
    opacity: 0.5;
}

.not-selected:hover {
    opacity:1;
}


.sweet-alert *
{
  font-family:'Linotype';
}
.sweet-alert button
{
  font-family:'Cabin';
}
.sweet-alert button.cancel{
  background-color: #f26f99;
  color: white;
}
.sweet-alert button.cancel:hover
{
  background-color: #f26f99;
}

.fa-refresh
{
  background-color:#8bb3f4;
  color:#396aba;
  padding:10px 14px 10px 14px;
  border-radius:40px;
}
.fa-refresh:hover
{
  color:white;
   box-shadow: 300px 0 0 0 rgba(0,0,0,0.5) inset;
}
var globals={};
var level="";
  function insert(n, char) {
    var cell = $('.board .cell:nth-child('+(n+1)+')');;
    if(!cell.hasClass('occupied')) {
        cell.text(char);
        cell.css({color : char == "X" ? "green" : "red"});
        cell.addClass('occupied');
    }
  }
function clearall() {
    for(var i=0;i<9;i++)
	{
	        var cell = $('.board .cell:nth-child('+(i+1)+')');;
    	    if(cell.hasClass('occupied')) 
		      {
        		cell.text("");
        		cell.removeClass('occupied');
    		  }
	}
  }

  var AIAction = function(pos) {

    this.markat = pos;
    this.minimaxVal = 0;
    this.applyTo = function(state) {
        var next = new State(state);
        next.board[this.markat] = state.turn;
        if(state.turn === "O")
            next.numomoves++;
        next.advanceTurn();
        return next;
    }
};

AIAction.ASCENDING = function(action1, action2) {
    if(action1.minimaxVal < action2.minimaxVal)
        return -1; 
    else if(action1.minimaxVal > action2.minimaxVal)
        return 1; 
    else
        return 0; 
}

AIAction.DESCENDING = function(action1, action2) {
    if(action1.minimaxVal > action2.minimaxVal)
        return -1; 
    else if(action1.minimaxVal < action2.minimaxVal)
        return 1; 
    else
        return 0; 
}

var AI = function(level) {
    var intellilevel = level;
    var game = {};
    function minimaxValue(state) {
        if(state.isTerminal()) {
            return Game.score(state);
        }
        else {
            var stateScore; 
            if(state.turn === "X")
                stateScore = -1000;
            else
                stateScore = 1000;
            var positionchoices = state.emptyCells();
            var stateschoices = positionchoices.map(function(pos) {
                var action = new AIAction(pos);
                var nextState = action.applyTo(state);
                return nextState;
            });
            stateschoices.forEach(function(nextState) {
                var nextScore = minimaxValue(nextState);
                if(state.turn === "X") {
                    if(nextScore > stateScore)
                        stateScore = nextScore;
                }
                else {
                    if(nextScore < stateScore)
                        stateScore = nextScore;
                }
            });
            return stateScore;
        }
    }

    function makenoobmove(turn) {
        var availablechoices = game.currentState.emptyCells();
        var noobdecisioncell = availablechoices[Math.floor(Math.random() * availablechoices.length)];
        var action = new AIAction(noobdecisioncell);
        var next = action.applyTo(game.currentState);
        insert(noobdecisioncell, turn);
        game.advanceTo(next);
    }

    function makeexpertmove(turn) {
        var available = game.currentState.emptyCells();

        var actionchoices = available.map(function(pos) {
            var action =  new AIAction(pos); 
            var next = action.applyTo(game.currentState);              action.minimaxVal = minimaxValue(next); 
            return action;
        });

        if(turn === "X")
            actionchoices.sort(AIAction.DESCENDING);
        else
            actionchoices.sort(AIAction.ASCENDING);


        var doaction = actionchoices[0];
        var next = doaction.applyTo(game.currentState);
        insert(doaction.markat, turn);
        game.advanceTo(next);
    }

  
    this.plays = function(_game){
        game = _game;
    };

    this.notify = function(turn) {
        switch(intellilevel) {
            case "noob": makenoobmove(turn); break;
            case "expert": makeexpertmove(turn); break;
        }
    };
};
  
  //STATE
  var State=function(old)
  {
    this.turn="";
    this.numomoves=0;
    this.result="still running";
    this.board=[];
    if(typeof old!=="undefined")    //new state is to be constructed from old state
      {
        var len=old.board.length;
        this.board=new Array(len);
        for(var i=0;i<len;i++)
          {
            this.board[i]=old.board[i];
          }
        this.numomoves=old.numomoves;
        this.result=old.result;
        this.turn=old.turn;
      }
    this.advanceTurn=function()
    {
      if(this.turn==="X")
        this.turn="O";
      else
        this.turn="X";
    };
    
    this.emptyCells=function()
    {
      var emptycellindices=[];
      for(var i=0;i<9;i++)
        {
          if(this.board[i]==="E")
            {
              emptycellindices.push(i);
            }
        }
      return emptycellindices;
    };
    
    this.isTerminal=function()
    {
      var b=this.board;
        for(var i=0;i<=6;i=i+3) {
            if(b[i]!=="E" && b[i]===b[i+1] && b[i+1]==b[i+2]) 
            {
                this.result=b[i]+"-won";
                return true;
            }
        }
        for(var i=0;i<=2;i++) {
            if(b[i]!=="E" && b[i]===b[i+3] && b[i+3]===b[i+6]) {
                this.result=b[i]+"-won"; //update the state result
                return true;
            }
        }
        for(var i=0,j=4;i<=2;i=i+2,j=j-2) {
            if(b[i]!=="E" && b[i]==b[i+j] && b[i+j]===b[i+2*j]) {
                this.result=b[i]+"-won";
                return true;
            }
        }
        var available = this.emptyCells();
        if(available.length == 0) {
            this.result = "draw";
            return true;
        }
        else {
          //$("#deb").append("<p>You are in isTerminal()</p>");
            return false;
        }
    };
  };
  
  
  
  //GAME
  var Game=function(aiplayer)
  {
    this.ai=aiplayer;
    this.currentState=new State();
    this.currentState.board=["E","E","E","E","E","E","E","E","E"];
    this.currentState.turn="X";
    this.status="beginning";
    this.advanceTo=function(_state)
    {
      this.currentState=_state;
      if(_state.isTerminal())
        {
          //$("#deb").append("<p>You are in advanceTo()</p>");
          this.status="ended";
          
          if(_state.result==="X-won")
            {
              swal("Woohoo", "You won!", "success");
                 createnewgame(level);
            }
          else if(_state.result==="O-won")
            {
              swal("Boohoo", "You lost!", "error");
                 createnewgame(level);
            }
          else
            {
              swal("Bleh", "Just a draw, who cares..", "error");
                 createnewgame(level);
            }
        }
      else
        {
          
          if(this.currentState.turn==="O")
            {
              this.ai.notify("O");
              //$("#deb").append("<p>We are now notifying AI!</p>");
            }
        }
    };
    this.start=function()
    {
      if(this.status==="beginning")
        {
          //$("#deb").append("<p>Fuck YOU</p>");
          this.advanceTo(this.currentState);
          this.status="running";
        }
    }
  };
  Game.score=function(_state)
  {
    if(_state.result==="X-won")
    {return 10-_state.numomoves;}
    else if(_state.result==="O-won")
    {return -10+_state.numomoves;}
    else
      {return 0;}
  }
  
  
   $(".cell").each(function() {
     var $this = $(this);
     
     $this.click(function() {
         if((globals.game.status === "running" ) && globals.game.currentState.turn === "X" && !$this.hasClass('occupied')) {
             var indx=parseInt($this.attr("id"));
             var next = new State(globals.game.currentState);
             next.board[indx] = "X";
             insert(indx, "X");
             next.advanceTurn();
             globals.game.advanceTo(next);
         }
     });
 });
function createnewgame(level)
{
    var ai=new AI(level);
    globals.game=new Game(ai);
    ai.plays(globals.game);
    globals.game.start();
    clearall();
}
$("#reset").click(function(){
  swal("Leaving?", "What Happened? Couldn't Cope up?", "info");
   createnewgame(level);
});





$(document).ready(function(){
  swal({
  title: "Welcome",
  text: "Select your difficulty level",
  type: "warning",
  showCancelButton: true,
  confirmButtonColor: "#3ae527",
  confirmButtonText: "Expert",
  cancelButtonText: "Noob",
  closeOnConfirm: false,
  closeOnCancel: false
},
function(isConfirm){
  if (isConfirm) {
    swal("Whoa you seem confident", "Good luck trying to win", "success");
    level="expert";
       createnewgame(level);

  } else {
        swal("Easy Peasy lemon squeezy", "Enjoy", "success");
    level="noob";
       createnewgame(level);

    //$("#deb").append(globals.game.status);
  }
});
  
});//EOF

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js