<div class="title">Tic Tac Toe</div>
<button class="but"></button>
<button class="but"></button>
<button class="but"></button>
<button class="but"></button>
<button class="but"></button>
<button class="but"></button>
<button class="but"></button>
<button class="but"></button>
<button class="but"></button>
<button id="reset" class="but">Reset</button>
@import url("https://fonts.googleapis.com/css?family=Raleway:400,400i,700");

:root {
  --body-bg-color: #a2a2a2;
  --tiles-bg-color: rgba(255, 255, 255, 0.8);
  --tiles-bg-color-hover: rgba(230, 230, 230, 0.8);;
  --tiles-blue-bg-color: #4f62ff;
  --tiles-red-bg-color: #d22f2f;
  --cell-size: 100px;
  --cell-spacing: 10px;
  --title-height: 30px;
  --reset-height: 50px;
}

html, body {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}

body {
  background-color: var(--body-bg-color);
  display: grid;
  grid-template-columns: var(--cell-size) var(--cell-size) var(--cell-size);
  grid-template-rows: var(--reset-height) var(--cell-size) var(--cell-size) var(--cell-size) var(--reset-height);
  grid-gap: var(--cell-spacing);
  justify-content: center;
  align-content: center;
}

.title {
  font-family: Raleway, sans-serif;
  font-size: 28px;
  text-align: center;
  width: 100%;
  height: var(--title-height);
  line-height: var(--title-height);
  grid-column-start: 1;
  grid-column-end: 4;
}

.but {
  font-family: Raleway, sans-serif;
  font-size: 20px;
  background-color: var(--tiles-bg-color);
  width: var(--cell-size);
  height: var(--cell-size);
  border: none;
  display: block;
  cursor: pointer;
  padding: 0;
  border-radius: 5px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5), 0 0 0 rgba(0, 0, 0, 0.5) inset;
  transition: 0.1s box-shadow ease-out;
}

.but:active,
.but.ai-active {
  box-shadow: 0 0 0 rgba(0, 0, 0, 0.5), 0 2px 5px rgba(0, 0, 0, 0.5) inset;
}

.but:hover {
  background-color: var(--tiles-bg-color-hover);
}

.but.blue:after {
  content: '✕';
  color: var(--tiles-blue-bg-color);
  font-size: 72px;
  width: var(--cell-size);
  height: var(--cell-size);
  line-height: var(--cell-size);
  display: block;
}

.but.red:after {
  content: '〇';
  color: var(--tiles-red-bg-color);
  font-size: 72px;
  width: var(--cell-size);
  height: var(--cell-size);
  line-height: var(--cell-size);
  display: block;
}

#reset {
  width: 100%;
  height: var(--reset-height);
  grid-column-start: 1;
  grid-column-end: 4;
}
class Tic {
  constructor() {
    this.storage   = new Array();
    this.pattern   = new Array();
    this.button    = document.querySelectorAll('.but');
    this.play      = 1;
    this.winPlay   = null;
  }
  
  buildPattern() {
    this.pattern.push(
      [0, 1, 2],
      [3, 4, 5],
      [6, 7, 8],
      [0, 3, 6],
      [1, 4, 7],
      [2, 5, 8],
      [0, 4, 8],
      [2, 4, 6]
    );
  }

  buildStorage() {
    this.storage = [0, 0, 0, 0, 0, 0, 0, 0, 0];
  }
  
  getWin(getPlay, getPattern) {
    var count = 0;
    
    for (var i in getPattern) {
      if (this.storage[getPattern[i]] === getPlay) {
        count++;
      }
    }

    if (count === 3) {
      this.winPlay = getPlay;
    }
  }
  
  confirmPattern(getPlay, aiValidate) {
    var returnValue = false;

    for (var i in this.pattern) {
      var matchCount = 0;

      for (var j in this.pattern[i]) {
        var matchIndex = this.pattern[i][j];
        
        if (this.storage[matchIndex] === getPlay) {
          matchCount++;
        }
        else if (this.storage[matchIndex] > 0) {
          matchCount--;
        }
      }
      
      if (matchCount > 1 && aiValidate) {
        returnValue = this.pattern[i];

        break;
      }
      else if (matchCount > 2 && !aiValidate) {
        returnValue = this.pattern[i];

        break;
      }
    }

    return returnValue;
  }
  
  computerMove() {
    var patternResult = this.confirmPattern(1, true);
    
    if (!patternResult) {
      var isNext = true;

      while (isNext) {
        var random = Math.floor(Math.random() * 9);
        
        if (this.storage[random] === 0) {
          this.storage[random] = this.play;

          isNext = false;
          
          this.buildTable();
          this.play = 1;
        }
        else {
          for (var i in this.storage) {
            isNext = false;

            if (this.storage[i] === 0) {
              isNext = true;

              break;
            }
          }
        }
      }
    }
    else {
      for (var i in patternResult) {
        if (this.storage[patternResult[i]] === 0) {
          this.storage[patternResult[i]] = this.play;
    
          this.buildTable();
          this.play = 1;
        }
      }
    }
  }
  
  buildTable() {
    var tic          = this;
    var countStorage = 0;
    
    for (var i in this.storage) {
      if (this.storage[i] == 0) {
        countStorage++;
      }
    }

    Array.prototype.forEach.call(this.button, function(btn, i) {
      btn.classList.remove('blue');
      btn.classList.remove('red');

      switch(tic.storage[i]) {
        case 1:
          btn.classList.add('blue');
          
          break;
        case 2:
          btn.classList.add('red');
          
          break;
      }
    });

    if (this.play === 0) {
      this.play = 1;
    }
    else if (this.play === 1) {
      this.play = 2;
      
      tic.computerMove();
    }

    tic.getWin(1, tic.confirmPattern(1, false));
    tic.getWin(2, tic.confirmPattern(2, false));

    if (!!this.winPlay) {
      if (confirm('PLAYER ' + this.winPlay + ' WINS! Play again?')) {
        this.buildStorage();
        this.reset();
      }
    }
    else if (countStorage == 0) {
      if (confirm('It\'s a draw! Do you like to try again?')) {
        this.reset();
      }
    }
  }
  
  main() {
    this.buildPattern();
    this.buildStorage();
  }

  reset() {
    this.play    = 0;
    this.winPlay = null;

    this.buildStorage();
    this.buildTable();
  }
}

var tic = new Tic();

tic.main();

Array.prototype.forEach.call(tic.button, function(btn, i) {
  btn.addEventListener('click', function() {
    if (tic.play === 1) {
      if (tic.storage[i] === 0) {
        tic.storage[i] = tic.play;
        
        tic.buildTable();
      }
    }
  });
});

document.querySelector('#reset').addEventListener('click', function() {
  if (confirm('Are you sure you want to reset the game?')) {
    tic.reset();
  }
});

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css

External JavaScript

This Pen doesn't use any external JavaScript resources.