JSFiddle - React, Tailwind, and code Playground

by MPelletier

HTML

<script src="https://code.jquery.com/jquery-1.7.2.min.js"></script>
<body>
  <div>
    <h2>Tic-Tac-Toe</h2>
    <h3 id="currentPlayer">Current player: <span id="currentTurn">X</span></h3>
    <h2 id="gameWinner" class="helper-hidden">Player <span id="winningPlayer"></span> is the winner!</h2>
    <h2 id="noWinner" class="helper-hidden">Draw!</h2>
  </div>

  <div>
    <table id="game" cellpadding="0" cellspacing="0">
      <tr>
        <td></td>
        <td></td>
        <td></td>
      </tr>
      <tr>
        <td></td>
        <td></td>
        <td></td>
      </tr>
      <tr>
        <td></td>
        <td></td>
        <td></td>
      </tr>
    </table>
  </div>
</body>

CSS

body {
  background-color: #0a2126;
  color: #FFFFFF;
  font-family: "montserrat", "verdana";
  margin: 0;
  padding: 0;
  text-align: center;
}

#game {
  border-collapse: collapse;
  margin: 50px auto;
  position: relative;
}

td {
  border: 0px solid #113942;
  border-right-width: 6px;
  border-bottom-width: 6px;
  cursor: pointer;
  font-size: 80px;
  height: 170px;
  position: relative;
  text-align: center;
  width: 170px;
}

td:nth-child(3) { border-right-width: 0px; }
tr:last-child td { border-bottom-width: 0px; }

td.O  { color: #60a0ae; }
td.X  { color: #7de0b0; }

td.hover-0:after,
td.hover-1:after {
  color: #FFF;
  content: "X";
  display: block;
  font-size: 80px;
  opacity: 0.6;
  pointer-events: none;
  position: relative;
  text-align: center;
  vertical-align: center;
}

td.hover-1:after {
  content:"O";
}

td.X.hover-0:after, td.X.hover-1:after,
td.O.hover-0:after, td.O.hover-1:after {
  display:none !important;
}

.helper-hidden {
  display: none;
}

JavaScript

var Game = function() {

  this.init = function(){
    this.players = [
      { symbol: 'X', moves: [] },
      { symbol: 'O', moves: [] }
    ]
    this.activePlayer = 0;
    this.moves = 0;

    this.gameInProgress = true;

    this.board = [
      null, null, null,
      null, null, null,
      null, null, null
    ];

    this.potentialWins = [
      [0,1,2], [3,4,5], [6,7,8], [0,3,6],
      [1,4,7], [2,5,8], [0,4,8], [2,4,6]
    ];

    this.bindEvents();
    $('#game tr td').attr('class', '');
    $('#currentPlayer').removeClass('helper-hidden');
    $('#gameWinner').addClass('helper-hidden');
    $('#noWinner').addClass('helper-hidden');
    this.updateBoard();
  }

  this.bindEvents = function(){
    var self = this;

    // bind input actions
    $('#game tr td').click(function() {

      if (!self.gameInProgress) {
        return;
      }

      var col = $(this).index();
      var row = $(this).closest('tr').index();

      // Convert Row/Column into Index
      var position = col;
      if (row === 1) {
        position += 3;
      } else if (row === 2) {
        position += 6;
      }

      self.move(position);
    });

    $('#game tr td').hover(function() {
      if (!self.gameInProgress) {
        return;
      }
      $(this).addClass('hover-'+ self.activePlayer);
    }, function(){
      if (!self.gameInProgress) {
        return;
      }
      $(this).removeClass('hover-0 hover-1');
    })
  };

  this.updateActivePlayer = function() {
    var currentPlayer = this.activePlayer;
    this.activePlayer = currentPlayer === 0 ? 1 : 0;
    $('#currentTurn').text(this.players[this.activePlayer].symbol);
  };

  this.tryMove = function(input){
    if (this.board[input] == null) {
      return true;
    }
    return false;
  };

  this.move = function(position){
    var Player = this.players[this.activePlayer];

    // Check to see if the position is vacant.
    if (!this.tryMove(position)) {
      return false;
    }

    Player.moves.push(position);
...