Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel is required to process package imports. If you need a different preprocessor remove all packages first.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

HTML

            
              <div class="wrapper">
  
  <div class="dialogs">
    
    <div class="cover"></div>
    
    <div class="pick">
      <h2 class="msg">Pick</h2>
      <button class="x"></button>
      <button class="o"></button>
    </div> <!-- end-pick -->
    
    <div class="end">
      <h2 class="msg"></h2>
      <button class="replay"><i class="fa fa-refresh"></i></button>
    </div> <!-- end-end -->
    
  </div> <!-- end-dialogs -->
  
  <div class="container">
    
    <div class="game">
      
      <div class="row top">
        <div class="col"></div>
        <div class="col"></div>
        <div class="col"></div>
      </div> <!-- end-row -->

      <div class="row middle">
        <div class="col"></div>
        <div class="col"></div>
        <div class="col"></div>
      </div> <!-- end-row -->

      <div class="row bottom">
        <div class="col"></div>
        <div class="col"></div>
        <div class="col"></div>
      </div> <!-- end-row -->
      
    </div> <!-- end-game -->
    
    <div class="scores">
      <div class="row">
        <div class="col p">
          <h2>Player - <span class="char">X</span></h2>
          <u>0</u>
        </div>
        <div class="col ties">
          <h2>Ties</h2>
          <u>0</u>
        </div>
        <div class="col com">
          <h2>Computer - <span class="char">O</span></h2>
          <u>0</u>
        </div>
      </div>
    </div>
    <!-- end-scores -->
    
  </div> <!-- end-container -->
  
</div> <!-- end-wrapper -->
            
          
!

CSS

            
              @import "bourbon"
@import "neat"

// Config
$light: #FFFCCA
$color-1: #55E9BC
$color-2: #11D3BC
$dark: #537780

$base-size: 16px
$base-m: $base-size * 1.5

// Mixins
@mixin v-center()
  position: relative
  top: 50%
  +transform(translateY(-50%))
    
@mixin o()
  &:after
    content: ''
    border: solid $light
    border-radius: 50%
    border-width: rem(16)

    +media($bp-sm)
      border-width: rem(10)
  
    +media($bp-sm-h)
      border-width: rem(10)

    +size(60%)
    +position(absolute, 50% null null 50%)
    +transform(translateY(-50%) translateX(-50%))
    +animation(o .25s)
    
@mixin x()
  &:before        
    content: ''

    background-color: $light

    +size(10% 60%)
    +position(absolute, 50% null null 50%)
    +transform(translateY(-50%) translateX(-50%) rotate(45deg))
    +animation(x .25s)

  &:after
    content: ''

    background-color: $light

    +size(10% 60%)
    +position(absolute, 50% null null 50%)
    +transform(translateY(-50%) translateX(-50%) rotate(-45deg))
    +animation(x .25s)

// Typography
@import url(https://fonts.googleapis.com/css?family=Roboto)
@import url(https://fonts.googleapis.com/css?family=Montserrat)

// Base
body
  background-color: $color-1
  color: $dark
  
  font-size: $base-size
  font-family: 'Roboto', sans-serif
  
  text-align: center
  +user-select(none)

u
  text-decoration: none
  
.wrapper
  position: relative
  height: 100vh

// Grid
$fg-gutter: em(0)
$max-width: rem(480)
$grid-columns: 3

$bp-sm: new-breakpoint(max-width 520px)
$bp-sm-h: new-breakpoint(max-height 620px)
$bp-xs-h: new-breakpoint(max-height 420px)

.container
  +outer-container(rem(500))
    
  +media($bp-sm)
    +outer-container(rem(320))
  
  +media($bp-sm-h)
    +outer-container(rem(320))
  
  +media($bp-xs-h)
    +outer-container(rem(480))

.scores
  +span-columns(3)
  
  +media($bp-xs-h)
    +span-columns(1)
    +v-center
  
  .col
    +span-columns(1)
    
    +media($bp-xs-h)
      +span-columns(3)

.game
  +span-columns(3)
  
  +media($bp-xs-h)
    +span-columns(2)
    
  .row
    +row()

    .col
      +span-columns(1)
    
// Layout
.dialogs
  +position(absolute, 0 null null 0)
  z-index: 99
  
  +size(100%)
    
  .cover
    +position(absolute, 0 null null 0)
    +size(100%)
    background-color: $dark
    opacity: .8
  
  .pick,
  .end
    +v-center()
    padding: rem(15) 0
  
    .msg
      margin-top: 0
      margin-bottom: $base-m
      color: $light
      font-size: 3rem
      
      +media($bp-sm)
        font-size: 2rem
      
      +media($bp-sm-h)
        font-size: 2rem
      
    button
      position: relative
      border: none
      outline: none
      
      background-color: $color-2
      color: $light
      
      font-size: 6rem
      
      +transition(background-color .25s ease)
      
      +size(rem(160))
      margin-right: rem(5)
      
      &:last-child
        margin-right: 0
        
      &:hover
        background-color: shade($color-2, 10%)
      
      &:active
        background-color: $dark
        
      +media($bp-sm)
        +size(rem(100))
        font-size: 4rem
        
      +media($bp-sm-h)
        +size(rem(100))
        font-size: 4rem
      
      &.o
        +o()
        
      &.x
        +x()
        
  .end
    display: none
        
    
// end-dialgos

.container
  +v-center
  z-index: 1
  padding: 0 rem(10)
  
  +media($bp-xs-h)
    height: 100vh

// Game
.game
  min-width: rem(300)
  background-color: $color-2

  +media($bp-sm)
    max-width: rem(300)

  +media($bp-sm-h)
    max-width: rem(300)

  +media($bp-xs-h)
    +v-center

  .row

    &:last-child
      .col
        border-bottom: none

    .col
      +size(rem(160))
      position: relative

      cursor: pointer
      +transition(background-color .25s ease)

      border-bottom: rem(2) solid $color-1
      border-right: rem(2) solid $color-1

      color: $light
      font-size: 8rem

      +media($bp-sm)
        +size(rem(100))

      +media($bp-sm-h)
        +size(rem(100))

      +media($bp-xs-h)
        +size(rem(100))

      &:last-child
        border-right: none

      &:hover
        background-color: shade($color-2, 10%)

      &:active
        background-color: $dark
      
      +keyframes(blink)
        from
          background-color: $dark
        to
          background-color: transparent
      
      &.blink
        +animation(blink .25s 3)

      u
        +position(absolute, 0 null null 0)
        +size(100%)

        &.o
          +o()

          +keyframes(o)
            from
              +size(90%)
            to
              +size(60%)

        &.x
          +keyframes(x)
            from
              +size(15% 90%)
            to
              +size(10% 60%)

          +x()
// end-game

// Scores
.scores
  margin-top: $base-m
  cursor: pointer

  +media($bp-sm)
    max-width: rem(300)

  +media($bp-sm-h)
    max-width: rem(300)

  +media($bp-xs-h)
    max-width: rem(160)
    margin-top: 0
    +v-center

  .col
    +media($bp-xs-h)
      margin-bottom: $base-m

    &:last-child
      +media($bp-xs-h)
        margin-bottom: 0

  h2
    margin-top: 0
    margin-bottom: $base-m / 4

    +media($bp-sm)
      font-size: 1rem

    +media($bp-sm-h)
      font-size: 1rem

    .char
      font-family: 'Montserrat', sans-serif
      color: $light

  u
    font-family: 'Montserrat', sans-serif
    font-size: 3rem
    color: $light

    +media($bp-sm)
      font-size: 2rem

    +media($bp-sm-h)
      font-size: 2rem
// end-scores
          
            
          
!

JS

            
              'use strict';

(function() {
  
  function TicTacToe(args) {
    
    // Settings
    var $game = args.game,
        $scores = args.scores,
        $dialogs = args.dialogs,
        cols = [];
    
    $game.find('.row').each(function(i) {
      var row = [];
      $(this).find('.col').each(function(j) {
        row.push($(this));
      });
      cols.push(row);
    });
    
    // VARS
    var rows = [
          [cols[0][0], cols[0][1], cols[0][2]],
          [cols[1][0], cols[1][1], cols[1][2]],
          [cols[2][0], cols[2][1], cols[2][2]], // Hori

          [cols[0][0], cols[1][0], cols[2][0]],
          [cols[0][1], cols[1][1], cols[2][1]],
          [cols[0][2], cols[1][2], cols[2][2]], // Verti

          [cols[0][0], cols[1][1], cols[2][2]],
          [cols[0][2], cols[1][1], cols[2][0]] // Diago
        ],
        chars = { p: 'x', com: 'o' },
        scores = {  p: 0, ties: 0, com: 0 },
        turn = 'p',
        isComputer = false;
    
    /*
    ============================================
      UpdateScores Function.
    ============================================
    */
    function updateScores() {
      
      $scores.find('.p').find('u').html(scores.p);
      $scores.find('.ties').find('u').html(scores.ties);
      $scores.find('.com').find('u').html(scores.com);
      
    } // end-updateScores
    
    /*
    ============================================
      getCoords Function.
    ============================================
    */
    function getCoords(target) {
        
      for (var i = 0; i < cols.length; i++) {
        for (var j = 0; j < cols[i].length; j++) {
          if (target.context === cols[i][j].context) {
            return { row: i, col: j };
          }
        }
      }

    } // end-getCoords
    
    /*
    ============================================
      AppendChar Function.
    ============================================
    */
    function appendChar(target, char) {
      
      if (target.hasClass('col') && target.children().length < 1) {
        target.append($(document.createElement('u')).addClass(char));
      }
      
    } // end-appendChar
    
    /*
    ============================================
      Blink Function.
    ============================================
    */
    function blink($el) {
      
      function rmClass() {
        $el.removeClass('blink');
      }
      
      $el.addClass('blink');
      setTimeout(rmClass, 2000);
      
    } // end-blink
    
    /*
    ============================================
      SwitchTurn Function.
    ============================================
    */
    function switchTurn() {
      
      if (turn === 'p') {
        turn = 'com';
      } else {
        turn = 'p';
      }
      
    } // end-switchTurn
    
    /*
    ============================================
      Dialogs Function.
    ============================================
    */
    function dialogs(fade, dialog) {
      
      if (fade === 'out') {
        $dialogs.fadeOut(500, function() {
          $dialogs.find('.end').find('.msg').html('');
        });
      } else {
        $dialogs.children().show();
        $dialogs.find('.' + dialog).hide(0, function() {
          $dialogs.fadeIn(500);
        });
      }

    } // end-dialogs
    
    /*
    ============================================
      Action Function.
    ============================================
    */
    function action(action) {
      
      cols.forEach(function(row, i) {
        row.forEach(function(col, i) {
          
          if (action === 'replay') {
            col.children('u').remove();
          } else if (action === 'tie') {
            blink(col);
          }
          
        });
      });
      
      if (action === 'replay') {
        dialogs('out', 'pick');
        switchTurn();
        if (turn === 'com') {
          setTimeout(computer, 500);
        }
      } else if (action === 'win') {
        dialogs('in', 'pick');
      } else if (action === 'tie') {
        $dialogs.find('.msg').html('Tie');
        dialogs('in', 'pick');
      }
      
    } // end-action
    
    /*
    ============================================
      Winner Function.
    ============================================
    */
    function checkWinner() {
      
      function getRow(char) {
        
        rowsLoop:
        for (var i = 0; i < rows.length; i++) {
          for (var j = 0; j < rows[i].length; j++) {
            if (!rows[i][j].children('u').first().hasClass(char)) {
              continue rowsLoop;
            }
          }
          return rows[i];
        }
        
      } // end-getRow
            
      var p = getRow(chars.p),
          com = getRow(chars.com);
      
      if (p) {
        return {
          name: 'p',
          row: p
        };
      } else if (com) {
        return {
          name: 'com',
          row: com
        };
      }
      return false;
      
    } // end-checkWin
    
    function win(winner) {
      
      function winAction(row, text) {
        row.forEach(function(col) {
          blink(col);
        });
        $dialogs.find('.msg').html(text);
        action('win');
      } // action
      
      if (winner.name === 'p') {
        winAction(winner.row, 'You win!!');
        scores.p++
        updateScores();
      } else if (winner.name === 'com') {
        winAction(winner.row, 'Computer wins!');
        scores.com++
        updateScores();
      }

    } // end-win
    
    /*
    ============================================
      Tie Function.
    ============================================
    */
    function checkTie() {
      
      var emptyFound = false;
      colsLoop:
      for (var i = 0; i < cols.length; i++) {
        for (var j = 0; j < cols[i].length; j++) {
          if (!cols[i][j].children('u').length) {
            emptyFound = true;
            break colsLoop;
          }
        }
      }
      if (emptyFound) {
        return false;
      }
      return true;
      
    } // end-checkTie
    
    function tie() {
      
      action('tie');
      scores.ties++
      updateScores();
      
    } // end-tie
    
    /*
    ============================================
      Computer Function.
    ============================================
    */
    function computer() {
      
      if (checkWinner()) {
        isComputer = false;
        var winner = checkWinner();
        win(winner);
        return;
      } else if (checkTie()) {
        isComputer = false;
        tie();
        return;
      }
      
      isComputer = true;
      
      function getRandom(arr) {
        var randomIndex = parseInt(Math.random() * arr.length);
        return arr[randomIndex];
      }
      
      function getRows(char) {
        
        var dirtyRows = [];
        
        for (var i = 0; i < rows.length; i++) {
          var dirtyRowData = [];
          for (var j = 0; j < rows[i].length; j++) {
            if (rows[i][j].children('u').hasClass(char)) {
              dirtyRowData.push(rows[i][j]);
            }
          }
          if (dirtyRowData.length) {
            dirtyRowData.push(rows[i]);
            dirtyRows.push(dirtyRowData);
          }
        }
        
        var hasEmptyCols = [];
        
        dirtyRows.forEach(function(arr, i) {
          var row = arr[arr.length - 1];
          for (var i = 0; i < row.length; i++) {
            if (!row[i].children('u').length) {
              hasEmptyCols.push(arr);
            }
          }
        });
        
        var hasEmptyCols = hasEmptyCols.filter(function(row, i) {
          return hasEmptyCols.indexOf(row) === i;
        });
        
        hasEmptyCols.sort(function(a, b) {
          return b.length - a.length;
        });
                
        var hasHigherLength = hasEmptyCols.filter(function(row) {
          return row.length === hasEmptyCols[0].length;
        });
        
        var collection = [];
        hasHigherLength.forEach(function(row) {
          collection.push(row[row.length - 1]);
        });
        
        return collection ? collection : false;
        
      } // end-getRows
      
      function getCol() {
        
        function getEmptyCols(row) {
          var cols;
          if (row) {
            cols = row.filter(function(col) {
              return col.children('u').length === 0;
            });
          } else {
            cols = false;
          }
          return cols;
        } // end-getEmptyCols
        
        function checkWinnerRows(rows, char) {
          if (!rows) return false;
          var winnerRows = [];
          rows.forEach(function(row) {
            var dirtyCols = [];
            for (var i = 0; i < row.length; i++) {
              if (row[i].children('u').hasClass(char)) {
                dirtyCols.push(row[i]);
              }
            }
            if (dirtyCols.length === 2) {
              winnerRows.push(row);
            }
          });
          if (winnerRows.length) {
            return winnerRows;
          }
          return false;
        } // end-checkWinnerRows
        
        function getTheLastEmptyCol() {
          
          var col;
          rows.forEach(function(row) {
            for (var i = 0; i < row.length; i++) {

              if (!row[i].children('u').length) {
                col = row[i];
              }

            }
          });
          return col;

        } // end-getTheLastEmptyCol
        
        var cRows = getRows(chars.com),
            pRows = getRows(chars.p),
            cWinnerRows = checkWinnerRows(cRows, chars.com),
            pWinnerRows = checkWinnerRows(pRows, chars.p),
            randomRow = getRandom(rows);
        
        if (cWinnerRows.length) {
          return getRandom(getEmptyCols(getRandom(cWinnerRows)));
        } else if (pWinnerRows.length) {
          return getRandom(getEmptyCols(getRandom(pWinnerRows)));
        } else if (pRows.length) {
          return getRandom(getEmptyCols(getRandom(pRows)));
        } else if (cRows.length) {
          return getRandom(getEmptyCols(getRandom(cRows)));
        } else if (randomRow.length) {
          return getRandom(getEmptyCols(randomRow));
        } else {
          return getTheLastEmptyCol();
        }
        
      } // end-getCol
      
      var col = getCol();
      
      appendChar(col, chars.com);
      
      isComputer = false;
      
      if (checkWinner()) {
        var winner = checkWinner();
        win(winner);
        return;
      } else if (checkTie()) {
        tie();
        return;
      }
      
    } // end-computer
    
    
    /*
    ============================================
      Player Function.
    ============================================
    */
    function player(target) {
      
      if (isComputer || !target.hasClass('col') || target.children('u').length) {
        return;
      }
      
      var coords = getCoords(target);
      
      appendChar(cols[coords.row][coords.col], chars.p);
      
      if (checkWinner()) {
        var winner = checkWinner();
        win(winner);
        return;
      } else if (checkTie()) {
        tie();
        return;
      }
      
      isComputer = true;
      setTimeout(computer, 250);
        
    } // end-player
    
    /*
    ============================================
      Events Function.
    ============================================
    */
    $game.on('click', function(e) {
      
      var target = $(e.target);
      
      player(target);
              
    });
    
    $dialogs.find('.pick').find('button').on('click', function(e) {
      
      var target = $(e.target);      
      if (target.hasClass('x')) {
        chars.p = 'x';
        chars.com = 'o';
        $scores.find('.p').find('.char').html('X');
        $scores.find('.com').find('.char').html('O');
      } else {
        chars.p = 'o';
        chars.com = 'x';
        $scores.find('.p').find('.char').html('O');
        $scores.find('.com').find('.char').html('X');
      }
      dialogs('out', 'pick');
      
    });
    
    $dialogs.find('.end').find('.replay').on('click', function(e) {
      
      action('replay');
      
    });
    
  } // end-TicTacToe
  
  $(document).ready(function() {
    
    // DOM
    var $game = $('.game'),
        $scores = $('.scores'),
        $dialogs = $('.dialogs');
    
    var game = new TicTacToe({
      
      game: $game,
      scores: $scores,
      dialogs: $dialogs
      
    });
    
  });
  
})()
            
          
!
999px

Console