<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Tic Tac Toe</title>
  <link rel="stylesheet" href="style.css">
  <script>
    window.console = window.console || function(t) {};
  </script>
</head>

<body translate="no">
  <div class="container">
    <div class="game">
      <div class="cell">
        <input type="checkbox" data-cell="0" id="cell-1" />
        <label for="cell-1"></label>
      </div>
      <div class="cell">
        <input type="checkbox" data-cell="1" id="cell-2" />
        <label for="cell-2"></label>
      </div>
      <div class="cell">
        <input type="checkbox" data-cell="2" id="cell-3" />
        <label for="cell-3"></label>
      </div>
      <div class="cell">
        <input type="checkbox" data-cell="3" id="cell-4" />
        <label for="cell-4"></label>
      </div>
      <div class="cell">
        <input type="checkbox" data-cell="4" id="cell-5" />
        <label for="cell-5"></label>
      </div>
      <div class="cell">
        <input type="checkbox" data-cell="5" id="cell-6" />
        <label for="cell-6"></label>
      </div>
      <div class="cell">
        <input type="checkbox" data-cell="6" id="cell-7" />
        <label for="cell-7"></label>
      </div>
      <div class="cell">
        <input type="checkbox" data-cell="7" id="cell-8" />
        <label for="cell-8"></label>
      </div>
      <div class="cell">
        <input type="checkbox" data-cell="8" id="cell-9" />
        <label for="cell-9"></label>
      </div>

    </div>
  </div>
  <div class="modal">
    <div class="mod-container">
      <div class="mod-header">
        TicTacToe
      </div>
      <div class="mod-body">
        Let's play
      </div>
      <div class="mod-footer">
        <div class="mark-switch">
          Choose your mark:
          <div class="mark">
            <input type="radio" value="tic" name="mark-switch" id="mark-x" checked />
            <label id="lbl-x" class="btn" for="mark-x">&#10005;</label>
          </div>
          <div class="mark">
            <input type="radio" value="tac" name="mark-switch" id="mark-o" />
            <label id="lbl-o" class="btn" for="mark-o">&#9898;</label>
          </div>
        </div>
        <div class="play-order">
          <div class="btn" id="btn-first">Start First</div>
          <div class="btn" id="btn-second">Start Second</div>
        </div>
      </div>
    </div>
  </div>
  <script src='//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
  <script id="rendered-js" src="script.js"></script>
</body>

</html>
*,
*:before,
*:after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  background-color: #eceff1;
  font-family: Roboto, sans;
}
.container {
  width: 100%;
}
.game {
  width: 450px;
  margin: 100px auto;
  display: flex;
  flex-wrap: wrap;
  font-family: monospace;
}
.cell {
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}
.cell > label {
  position: relative;
  top: 0;
  left: 0;
  width: 140px;
  height: 140px;
  background-color: #455a64;
  margin: 5px;
  border: 10px solid #546e7a;
  cursor: pointer;
  transform-style: preserve-3d;
  transition: all 350ms ease;
  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
}
.cell > label:hover {
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
}
.cell > input[type="checkbox"] {
  display: none;
}
.cell > input[type="checkbox"]:checked ~ label {
  transform: rotateY(180deg);
}
.cell > label:after {
  content: "";
  position: absolute;
  top: -10px;
  left: -10px;
  width: 140px;
  height: 140px;
  transform: rotateY(180deg);
  border: 10px solid transparent;
  font-size: 80px;
  line-height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: -1;
  transition: border-color, color 250ms ease;
}
.cell.tic > label:after {
  content: "\2715";
  border-color: #66bb6a;
  color: #66bb6a;
}
.cell.tac > label:after {
  content: "\26AA";
  border-color: #81d4fa;
  color: #81d4fa;
}
.win-line > label:after {
  border-color: #ffab91 !important;
  color: #ffab91 !important;
}
.modal {
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  background-color: rgba(38, 50, 56, 0.7);
  display: flex;
  justify-content: center;
  align-items: center;
  transition: top 350ms ease;
}
.mod-container {
  width: 60%;
  max-width: 800px;
  min-width: 600px;
  background-color: #546e7a;
  color: #fff;
  display: flex;
  flex-direction: column;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
}
.mod-header {
  width: 100%;
  background-color: #455a64;
  font-size: 2em;
  padding: 8px;
  text-align: center;
}
.mod-body {
  width: 100%;
  padding: 20px;
  text-align: center;
  font-size: 1.6em;
}
.mod-footer {
  min-height: 50px;
  background-color: #455a64;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
}
.mark-switch {
  display: flex;
  margin-left: 5px;
}
.mark > label {
  background-color: transparent;
}
.mark > input[type="radio"] {
  display: none;
}
.mark > input[type="radio"]:checked ~ label {
  border: 2px solid rgba(236, 239, 241, 0.7);
  padding: 4px 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
}
.play-order {
  display: flex;
}
.btn {
  font-size: 1.2em;
  background-color: #546e7a;
  padding: 6px 10px;
  margin-left: 4px;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
}
.btn:hover {
  background-color: #263238;
}
var modal;
var cells, playerClass, cpuClass, grid;
var lines = ["012", "345", "678", "036", "147", "258", "048", "246"];
var pw = ["0pp", "p0p", "pp0"];
var cw = ["0cc", "c0c", "cc0"];
var corners = [0, 2, 6, 8];
var sides = [1, 3, 5, 7];
var winObj = {
  win: false,
  player: "",
  line: 0 };


$(document).ready(function () {
  modal = new Modal();
  cells = $(".cell>input:checkbox");
  cells.click(function (e) {
    playerMove(e.target);
  });
  $("#btn-first").click(function () {
    init(false);
  });
  $("#btn-second").click(function () {
    init(true);
  });
});

function init(flag) {
  winObj.win = false;
  cells.each(function (c, e) {
    e.checked = false;
    e.disabled = false;
    $(e).parent().removeClass("win-line tic tac");
  });
  grid = [0, 0, 0, 0, 0, 0, 0, 0, 0];
  playerClass = $("input:radio[name ='mark-switch']:checked").val();
  cpuClass = "tictac".replace(playerClass, "");
  console.log(playerClass, cpuClass);
  modal.hide();
  if (flag) {
    delay(myMove);
  }
}

function delay(fnc, arg) {
  window.setTimeout(fnc, 500, arg);
}

function playerMove(cell) {
  cells.each(function (c, e) {
    e.disabled = true;
  });
  var cId = $(cell).data("cell");
  $(cell).parent().addClass(playerClass);
  grid[cId] = "p";
  delay(gameTest, true);
}

function myMove() {
  //can we win
  var move = canWin(cw);
  if (move !== false) {
    makeMove(move);
    return;
  }
  //can player win - block him
  move = canWin(pw);
  if (move !== false) {
    makeMove(move);
    return;
  }
  //center cell
  if (grid[4] === 0) {
    makeMove(4);
    return;
  }
  //try corners
  move = randomEmptyCell(corners);
  if (move !== false) {
    makeMove(move);
    return;
  }
  //try sides
  move = randomEmptyCell(sides);
  if (move !== false) {
    makeMove(move);
    return;
  }
}

function makeMove(cell) {
  cells[cell].checked = true;
  $(cells[cell]).parent().addClass(cpuClass);
  $(cells[cell]).disabled = true;
  grid[cell] = "c";
  gameTest(false);
}

function randomEmptyCell(range) {
  var empty = range.filter(function (v) {
    return grid[v] === 0;
  });
  if (empty.length > 0) {
    return empty[Math.floor(Math.random() * empty.length)];
  } else {
    return false;
  }
}
function canWin(wm) {
  //var wm=["cc0","c0c","0cc"];
  var m = lines.reduce(function (p, l, i) {
    var a = l.split("").map(function (c) {
      return grid[c];
    }).join("");
    var b = wm.indexOf(a);
    if (b === -1) {
      return p || false;
    } else {
      return p || l.charAt(b);
    }
  }, false);
  return m;
}

function gameTest(isPlayer) {
  if (isWin()) {
    gameWon();
  } else if (isEnd()) {
    gameTie();
  } else {
    if (isPlayer) {
      myMove();
    } else {
      cells.each(function (i, e) {
        if (!e.checked) {
          e.disabled = false;
        }
      });
    }
  }
}

function gameWon() {
  lines[winObj.line].split("").forEach(function (v) {
    $(cells[v]).parent().addClass("win-line");
  });
  if (winObj.player === "ppp") {
    modal.message("You WON !!!");
  } else if (winObj.player === "ccc") {
    modal.message("You LOSE :-(");
  }
  delay(modal.show);
}

function gameTie() {
  modal.message("It's TIE");
  delay(modal.show);
}

function isWin() {
  var res = lines.reduce(function (p, c, i) {
    var lineRes = c.split("").map(function (a) {
      return grid[a];
    }).join("");
    if (lineRes === "ppp" || lineRes === "ccc") {
      winObj.line = i;
      winObj.player = lineRes;
      winObj.win = true;
    }
    return p || winObj.win;
  }, false);
  return res;
}

function isEnd() {
  return grid.filter(function (a) {
    return a != 0;
  }).length === 9;
}

var Modal = function () {
  var self = this;
  this.el = document.querySelector(".modal");
  var body = this.el.querySelector(".mod-body");

  this.el.onclick = function () {
    //self.hide();
  };

  this.show = function () {
    self.el.style.top = 0;
  };
  this.hide = function () {
    self.el.style.top = "-100%";
  };
  this.message = function (msg) {
    body.innerHTML = msg;
  };
};
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.