Tic-Tac-Toe via MVC and jQuery

In this example below you will see how to do a Tic-Tac-Toe via MVC and jQuery with some HTML / CSS and Javascript

Thumbnail
This awesome code was written by drmikeh, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright drmikeh ©

Technologies

  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Tic-Tac-Toe via MVC and jQuery</title>
  
  
  <link rel='stylesheet prefetch' href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css'>

      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <section>
  <h1>Tic Tac Toe!</h1>
  <div id="board" class="container well"></div>
  <p id="statusMessage"></p>
  <button class="btn btn-primary btn-lg" 
          onclick="TicTacToeController.reset()">New Game</button>
</section>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js'></script>

  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/drmikeh/tic-tac-toe-via-mvc-and-jquery-aBBpOx */
* {
  text-align: center;
  font-family: "Courier"
}
.cell {
  background-color: white;
  border: 1px solid black;
}
.X {
  color: green;
}
.O {
  color: red;
}


/*Downloaded from https://www.codeseek.co/drmikeh/tic-tac-toe-via-mvc-and-jquery-aBBpOx */
// MODEL
let TicTacToeGame = {
  board: [
    ['?', '?', '?'],
    ['?', '?', '?'],
    ['?', '?', '?']
  ],
  currentPlayer: 'X',

  reset: function() {
    for (let r = 0; r < this.board.length; r++) {
      let row = this.board[r];
      for (let c = 0; c < row.length; c++) {
        row[c] = '?';
      }
    }
    this.currentPlayer = 'X';
    this.winner = false;
    this.cat = false;
  },

  togglePlayer: function() {
    this.currentPlayer = this.currentPlayer === 'X' ? 'O' : 'X';
  },

  move: function(r, c) {
    this.board[r][c] = this.currentPlayer;
  },

  isBoardFull: function() {
    for (let r = 0; r < this.board.length; r++) {
      let row = this.board[r];
      for (let c = 0; c < row.length; c++) {
        if (this.board[r][c] === '?') {
          return false;
        }
      }
    }
    return true;
  },

  checkForMatch: function(cell1, cell2, cell3) {
    return cell1 === cell2 && cell1 === cell3 && cell1 !== '?';
  },

  checkRows: function() {
    for (let r = 0; r < this.board.length; r++) {
      let row = this.board[r];
      if (this.checkForMatch(row[0], row[1], row[2])) {
        return true;
      }
    }
    return false;
  },

  checkColumns: function() {
    for (let c = 0; c < this.board[0].length; c++) {
      if (this.checkForMatch(this.board[0][c], this.board[1][c], this.board[2][c])) {
        return true;
      }
    }
    return false;
  },

  checkDiagonals: function() {
    return this.checkForMatch(this.board[0][0], this.board[1][1], this.board[2][2])
        || this.checkForMatch(this.board[2][0], this.board[1][1], this.board[0][2]);
  },

  checkForEndOfGame: function() {
    let rowMatch = this.checkRows();
    let colMatch = this.checkColumns();
     let diagMatch = this.checkDiagonals();
     this.winner = rowMatch || colMatch || diagMatch;
     this.cat = !this.winner && this.isBoardFull();
     return this.winner || this.cat;
  }
};

// CONTROLLER
let TicTacToeController = {
  $board: null,
  $statusMessage: null,

  showCurrentPlayer: function() {
    this.$statusMessage.text('Current Player: ' + TicTacToeGame.currentPlayer);
  },

  showWinner: function() {
    this.$statusMessage.text('Player ' + TicTacToeGame.currentPlayer + ' has won!');
  },

  showCat: function() {
    this.$statusMessage.text('CAT!!!');
  },

  getCell: function(r, c) {
    let id = 'cell' + r + c;
    return $('#' + id);
  },

  move: function(r, c) {
    TicTacToeGame.move(r, c);
    let $cell = this.getCell(r, c);
    $cell.text(TicTacToeGame.currentPlayer)
         .addClass(TicTacToeGame.currentPlayer)
         .prop('disabled', true);
    if (TicTacToeGame.checkForEndOfGame() === false) {
      TicTacToeGame.togglePlayer();
      this.showCurrentPlayer();
    }
    else if (TicTacToeGame.winner) {
      this.showWinner();
      $('.cell').prop('disabled', true);   // winner means no more moves
    }
    else {
      this.showCat();
    }
  },

  buildGameBoard: function() {
    for (let r = 0; r < TicTacToeGame.board.length; r++) {
      let $row = $('<div>');
      for (let c = 0; c < TicTacToeGame.board[r].length; c++) {
        let id = 'cell' + r + c;
        let $button = $('<button>')
          .addClass('btn btn-lg cell')
          .click( () => this.move(r, c) ) // need a closure here to bind to r and c.
          .attr('id', id)
          .text('?');
        $row.append($button);
      }
      this.$board.append($row);
    }
  },

  reset: function() {
    TicTacToeGame.reset();
    $('.cell').text('?').removeClass('X O').prop('disabled', false);
    this.showCurrentPlayer();
  }
};

$(function() {
  TicTacToeController.$board = $('#board');
  TicTacToeController.$statusMessage = $('#statusMessage');
  TicTacToeController.buildGameBoard();
  TicTacToeController.reset();
});

Comments