123

Pen Settings

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

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

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

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

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.

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 lang="en">
<head>
    <meta name="viewport" content="width=device-width">
    <meta charset="UTF-8">
    <meta name="apple-mobile-web-app-capable" content="yes"/>
    <title id="page-title">Tic Tac Toe Game</title>
    <!--link rel="shortcut icon" href="icon.png"-->

    <!-- META TAGS -->
    <meta property="og:title" content="TicTacToe">
    <meta property="og:description" content="Enjoy playing Tic Tac Toe.">
    <meta property="og:author" content="JacobBogers">


    <!-- Google Font(s) Import -->
    <link href='https://fonts.googleapis.com/css?family=Lato:100,100italic,300,300italic,400italic,700,900,700italic,900italic|Open+Sans:400,300,300italic,400italic,600,600italic,700italic,800,700,800italic|Julius+Sans+One'
          rel='stylesheet' type='text/css'>
    <link href="https://fonts.googleapis.com/css?family=Raleway:300" rel="stylesheet">

    <!-- CSS CDN's -->
    <!--link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"-->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.2/css/font-awesome.min.css"/>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.1/animate.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/hover.css/2.0.2/css/hover-min.css">

    <!-- MY CSS -->
    <link rel="stylesheet" href="./tictactoe.css"/>
    <script src="./tictactoe.js"></script>
</head>
<body>
<div
     class="container flex-column-flow flex-column-valign-center flex-column-halign-center">
    <div id="place-holder" class="all-margin-auto fit ">
        <div id="inner-canvas" class="fit ">
            <div id="make-choice" class="choice-bar hide">
                <div id="descr-choice" class="bck-darkened fadeInDown animated">
                    <p class="txt-center-xy white-txt txt-p">Choose your pawn</p>
                    <p class="txt-center-xy white-txt txt-p">( <i class="fa fa-times black-txt"></i> starts first )</p>
                </div>
                <ul id="choice-btnz">
                    <li>
                        <span>
                            <div id="select-cross" class="allow btn jumbo bg-white black-txt txt-center-xy">
                                <i class="fa fa-times "></i>
                            </div>
                        </span>
                        <span>
                            <div id="select-circle" class="allow btn jumbo  bg-white red-txt  txt-center-xy">
                                <i class="fa fa-circle-o"></i>
                            </div>
                        </span>
                    </li>
                </ul>
            </div>
            <div id="game" class="hide">
                <div id="model"  class="model-show" ></div>
                <div id="game-header" class="bck-darkened user-select-none ">
                    <ul>
                        <li>
                        <span>
                        <div class="fit txt-center-xy white-txt header-btn"><i class="fa fa-user"></i> You</div>
                        </span>
                        <span>
                            <div class="fit header-btn  txt-center-xy white-txt "><i class="fa fa-hand-peace-o"></i> Tie</div>
                        </span>
                        <span>
                            <div class="fit header-btn  txt-center-xy white-txt "><i class="fa fa-laptop"></i> A.I.</div>
                        </span>
                        </li>
                        <li>
                        <span>
                            <div id="human-score" class=" header-btn-sm fit  txt-center-xy white-txt"><i class="fa fa-trophy "></i> 907</div>
                        </span>
                        <span>
                            <div id="tie-score" class="header-btn-sm fit  txt-center-xy white-txt">04</div>
                        </span>
                        <span>
                            <div id="ai-score" class="header-btn-sm fit  txt-center-xy white-txt"><i class="fa-trophy fa"></i> 24</div>
                        </span>
                        </li>
                    </ul>
                </div>
                <div id="game-grid" class="">
                    <ul>
                        <li style="white-space: nowrap;">
                        <span>
                            <div id="cell0" class="allow btn s-jumbo bg-white txt-center-xy fa fa-circle-o red-txt"></div>
                        </span>
                        <span>
                            <div id="cell1" class="allow btn s-jumbo bg-white black-txt txt-center-xy"></div>
                        </span>
                        <span>
                            <div id="cell2" class="allow btn s-jumbo bg-white black-txt txt-center-xy"></div>
                        </span>
                        </li>
                        <li>
                        <span>
                            <div id="cell3" class="btn s-jumbo bg-white black-txt txt-center-xy">
                            </div>
                        </span>
                        <span>
                            <div id="cell4" class="btn s-jumbo bg-white black-txt txt-center-xy"></div>
                        </span>
                        <span>
                            <div id="cell5" class="btn s-jumbo bg-white black-txt txt-center-xy"></div>
                        </span>
                        </li>
                        <li>
                       <span>
                           <div id="cell6" class="btn s-jumbo bg-white black-txt txt-center-xy"></div>
                       </span>
                        <span>
                            <div id="cell7" class="btn s-jumbo bg-white black-txt txt-center-xy"></div>
                        </span>
                        <span>
                            <div id="cell8" class="btn s-jumbo bg-white black-txt txt-center-xy"></div>
                        </span>
                        </li>
                    </ul>
                </div>
            </div><!-- game -->
        </div><!-- inner-canvas -->
    </div><!-- place holder -->
</div><!-- container -->
<div id="modal-canvas" class="modal-overlay modal-canvas">
    <div class="container flex-column-flow flex-column-valign-center flex-column-halign-center">
        <div class="all-margin-auto fit">
            <div id="dialog" class="xx usr dialog bg-white black-txt fit user-select-none">
                <div class="dlg-header txt-center-xy">
                    <p class="medium usr-display"><i class="fa fa-user"></i>&nbsp;You have won!</p>
                    <p class="medium ai-display"><i class="fa fa-laptop"></i>&nbsp;A.I. has won</p>
                    <p class="medium tie-display"><i class="fa fa-flag-o"></i>&nbsp;It is a Tie</p>
                </div>
                <div class="dlg-body txt-center-xy">
                    <p class="medium">Your Pawn Is Now:</p>
                    <p class="o-disp jumbo red-txt"><i class="fa fa-circle-o "></i></p>
                    <p class="x-disp jumbo black-txt"><i class="fa fa-times "></i></p>
                </div>
                <div class="dlg-btn-bar txt-center-xy">
                    <a id="next" class="dlg-button txt-center-xy fit">
                        <span class="medium ">
                            <i class="fa fa-gamepad"></i>
                                &nbsp;Next&nbsp;Game!
                        </span>
                    </a>
                </div>
            </div>
        </div>
    </div>
</div>
<div id="backdrop" class="modal-overlay backdrop fade" ></div>
</body>
</html>
            
          
!
            
              

/**
 ___   ___  _ _  ___  ___  _  ___   ___  ___  _ _  _    _  _ _  ___
/  _> | __>| \ || __>| . \| ||  _> / __>|_ _|| | || |  | || \ |/  _>
| <_/\| _> |   || _> |   /| || <__ \__ \ | | \   /| |_ | ||   || <_/\
`____/|___>|_\_||___>|_\_\|_|`___/ <___/ |_|  |_| |___||_||_\_|`____/

*/

button, input, select, textarea {
    font-size: 100%;
    margin: 0;
    vertical-align: baseline;
}

/* stop that crazy shit */
/* stop that crazy shit */
/* stop that crazy shit */
html, body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, a, form, fieldset, input[type="search"], textarea, p, blockquote, th, td {
    margin: 0;
    padding: 0;
}

input:focus, textarea:focus, keygen:focus, select:focus {
    outline-offset: -2px;
}

div:before, select, * {
    box-sizing: border-box;
}

button, input {
    line-height: normal;
}

html,
body {
    font-family: 'Open Sans';
    font-weight: 300;
    line-height: 1;
    box-sizing: border-box;
    height: 100%;
    margin: 0;
}

/* FLEX-BOX STUFF AND OTHER ALIGNMENT STUFF */

.flex-column-flow {
    display: -webkit-box;
    /* OLD - iOS 6-, Safari 3.1-6 */
    display: -moz-box;
    /* OLD - Firefox 19- (buggy but mostly works) */
    display: -ms-flexbox;
    /* TWEENER - IE 10 */
    display: -webkit-flex;
    /* NEW - Chrome */
    display: flex;
    /* NEW, Spec - Opera 12.1, Firefox 20+ */
    display: flex;
    flex-direction: column;

}

.flex-row-flow {
    display: -webkit-box;
    /* OLD - iOS 6-, Safari 3.1-6 */
    display: -moz-box;
    /* OLD - Firefox 19- (buggy but mostly works) */
    display: -ms-flexbox;
    /* TWEENER - IE 10 */
    display: -webkit-flex;
    /* NEW - Chrome */
    display: flex;
    /* NEW, Spec - Opera 12.1, Firefox 20+ */
    display: flex;
    flex-direction: row;

}

.flex-column-halign-center {

    align-items: center;

}

.flex-column-valign-center {

    justify-content: center;
    height: 100%;

}

.flex-stretch {
    align-items:stretch;
}

.h-center {
    text-align: center;
}

.hide {
    display: none;
    visibility: hidden;
}

.invisible {
    visibility: hidden;
}

.user-select-none {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

.fit {

    width: -moz-fit-content;
    width: fit-content;

}

.all-margin-auto {
    margin-top: auto;
    margin-bottom: auto;
    margin-left: auto;
    margin-right: auto;

}

/* MARKING ELEMENTS */

/* debug markers */
/* debug markers */
/* debug markers */
.debug-white {
    border: 1px white solid;
}

.debug-black {
    border: 1px solid black;
}

.debug-red {
    border: 1px solid red;
}

.debug-blue {
    border: 1px solid blue;
}

.outline-r {
    outline: 1px solid red;
}

.outline-g {
    outline: 1px solid green;
}

.outline-b {
    outline: 1px solid blue;
}

/*general decoration*/
/*general decoration*/
/*general decoration*/

.rounded {
    border-radius: 1rem;
}

.bck-w {
    background-color: white !important;
}

.ncursor {
    cursor: unset !important;
}

.dcursor {
    cursor: default !important;
}

.p-small {
    font-size: 0.7rem;
    font-weight: bold;
}

/** buttons */
/** buttons */
/** buttons */

.j-btn {
    display: inline-block;
    margin-bottom: 0;
    text-align: center;
    white-space: nowrap;
    vertical-align: middle;
    -ms-touch-action: manipulation;
    touch-action: manipulation;
    cursor: pointer;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    background-image: none;
    border: 1px solid transparent;
}

/*
 ___  ___  ___  _    _  ___  ___  ___  _  ___  _ _
| . || . \| . \| |  | ||  _>| . ||_ _|| || . || \ |
|   ||  _/|  _/| |_ | || <__|   | | | | || | ||   |
|_|_||_|  |_|  |___||_|`___/|_|_| |_| |_|`___'|_\_|

*/

/*elements*/
/*elements*/
/*elements*/
body {
    background: linear-gradient(#7FB1C9,#A570CC);
    font-family: 'Open Sans', "Helvetica Neue",Helvetica,Arial,sans-serif;
    font-size: 16px;
}

ul {
    display:table;
    table-layout: fixed;
    max-width:320px;
    width:100%;
}

li {
    display:table-row;
    white-space: nowrap;

}

ul li > span   {
    display: table-cell;
}

/*generic classes */
/*generic classes */
/*generic classes */

.s-jumbo {
    font-size:5.4em !important;
}

.jumbo {
    font-size: 4em !important;
}

.large {
    font-size:2em;
}

.medium {
    font-size:1.2em;
}

.btn {
    position:relative;
    display: inline-block;

    /*width:1em;
    height:1em;*/

    width:1em;
    height:1em;

    border-radius: 5px;
    box-shadow: 2px 5px 8px rgba(0,0,0,.2);

    -webkit-transition: all 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
    transition: all 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
    margin: 0.125em;
}

.btn::after {
    content: "";
    border-radius: 5px;
    position: absolute;

    /* z-index: -1;*/

    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
    opacity: 0;
    -webkit-transition: all 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
    transition: all 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
}

.clickable .btn.allow:hover {

    -webkit-transform: scale(1.25, 1.25);
    transform: scale(1.25, 1.25);

}

.clickable .btn.allow:hover::after {
    opacity: 1;
}

.bck-darkened {

    background-color:rgba(0,0,0,  0.2);
    border-radius: 5px;
    padding: calc( 2* 0.125em ) 0em;
    box-shadow: 2px 5px 8px rgba(0,0,0,.2);

    /*opacity: 0.5;*/

}

.inverted {

    background-color: white;
    color:black !important;
}


.header-btn {
    padding-top: 0.5em;
    padding-bottom: 0.5em;
    padding-left:0.5em;
    padding-right:0.5em;
    margin-left:auto;
    margin-right:auto;
    border-radius: 4px;
}

.header-btn-sm {
    padding-top: 0.25em;
    padding-bottom: 0.25em;
    padding-left:0.25em;
    padding-right:0.25em;
    margin-left:auto;
    margin-right:auto;
    border-radius: 2px;
}

.txt-center-xy {

    text-align: center;
    vertical-align: middle;

}

.txt-p {

    padding-bottom:0.25em;
    padding-top:0.25em;

}

.bg-white {

    background-color: white;

}

.bg-very-dark {

}

.red-txt {
    color:red;
}

.black-txt {
    color:black;
}

.white-txt {
    color:white;
}

.choice-bar {
    max-width: 10rem;
}

/* specific elements */
/* specific elements */
/* specific elements */

#header > ul li > span {
    padding-top: 0.0em;
    padding-bottom: 0.0em;
    padding-left: 0.0em;
    padding-right: 0.0em;
}

#game-header > ul li > span {
    align-items: center;
    display: table-cell;
}

.container {
    height: 100%;
    width: 100%;
}

/* button in #game-header */

#game-grid > ul li > span {
    padding: 0em 0em;
    /*border:1px green solid;*/
}

ul#choice-btnz li > span {
    width:50%;
}

#descr-choice {

    margin: 0em calc( 4* 0.125em );

}

/* for modal dark dialog background */

.fade {
    opacity: 0;
    -webkit-transition: opacity 0.15s linear;
    -o-transition: opacity 0.15s linear;
    transition: opacity 0.15s linear;
}

.backdrop {
    z-index:-1;
    background-color:#000;
    opacity:0;
}

.backdrop.in {
    z-index: 99; /* backdrop above everything else */
    opacity:0.5 !important;
}

.modal-canvas {
    z-index:-1; /* not visible*/
    opacity:0;
}

.modal-canvas.in {
    z-index:102; /* above the backdrop*/
    opacity:1;
}


.show {
    display:block !important;
}

.modal-overlay {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    display: block;
    -webkit-overflow-scrolling: touch;
    outline: 0;
}

.dialog {
    font-family:Raleway;
    border-radius: 5px;
}

.dialog * {
    cursor:default;
}


.dlg-header {
    padding: 1em 1em 0.25em 1em;
    font-weight:bold;
}

.dlg-btn-bar {
    padding: 0.5em 1em 1em 1em;
}

.dlg-body {
    border-top: 1px solid #DDD;
    border-bottom: 1px solid #DDD;
    padding: 0.5em 1em 0.5em 1em;
}

.dlg-button, .dlg-button:hover, .dlg-button:focus, .dlg-button:active {
    text-decoration: none;
    outline:none;
}
.dlg-button, .dlg-button * {
    curosr:pointer;
}


.dlg-button {
    background: #F0F0F0;
    padding: 10px 12px;
    border-radius: 2px;
    color: #333;
    font-size: 13px;
    font-weight: 500;
    display:inline-block;
}

.dlg-button:active {
    background-color: #333;
    color: #F0F0F0;
}

.usr-display , .ai-display, .tie-display {
    display:none;
}

.usr .usr-display , .ai .ai-display, .tie .tie-display {
    display:inline-block !important;
}

.o-disp, .x-disp {
  display:none;
}

.oo .o-disp , .xx .x-disp {
  display: inline-block !important;
}






            
          
!
            
              

function set_arr(arr, value) {
    for (var i = 0; i < arr.length; i++) {
        arr[i] = value;
    }
}

var t_game;

t_game = (function () {

    /**/

    var _grid = new Array(9);

    /* 9 pos of grid*/

    var game = {
        /**
         * state machine:
         *   init -> 0 ( animated choice box down )
         *   0-> 1     ( animate choice box out )
         *   1-> 2     ( animate game grid in )
         *   2 ->3     ( play game, substates : {rc,res} )
         *   3-> 4     animated game result in ( game over, AI won, Player win, or Tie )
         *   4-> 5     animated game result out, animate game grid out
         *   4-> 0     ( animate choice box down )
         * */
        state: {},
        ai_pawn: 0, /* either 'x' or 'o' */
        ai_score: 0,
        human_score: 0,
        tie_score: 0
    };

    var winning_paths = [
        [0, 1, 2],
        [3, 4, 5],
        [6, 7, 8],
        [0, 3, 6],
        [1, 4, 7],
        [2, 5, 8],
        [0, 4, 8],
        [2, 4, 6]
    ];

    var btn_handlers = [];

    /*
     some private functions and vars go here
     */

    function did_player_win(player_pawn) {
        var subset = winning_paths.filter(function (subset) {

            var res = subset.reduce(function (prev, cur, idx, arr) {
                    if (_grid[cur] == player_pawn) {

                        prev.cnt++;
                    }
                    return prev;
                },
                {cnt: 0}
            );
            if (res.cnt == 3) {//won!!
                return true;
            }
            return false;
        });
        console.log(subset);
        if (subset && subset.length > 0) {
            if (subset.length > 1) {
                throw new Error('Error, More then 1 player won?' + JSON.stringify(subset));
            }
            return ({ans: true, usr: player_pawn, set: subset[0]});

        }
        return ( {ans: false, usr: player_pawn} );
    }


    function process_move() {

        var x_player = did_player_win('x');
        var o_player = did_player_win('o');

        /*  */

        if (x_player.ans || o_player.ans) {
            game.state = {rc: 3, res: "won", player: o_player.ans ? "o" : 'x'};
        }
        if (is_tie()) {
            game.state = {rc: 3, res: "tie"};
        }
        /**
         DEBUG LOGGING STUFF
         */

        /**
         display grid
         */

    }

    /**
     Common sense obvious moves:
     */

    function is_tie() {
        var idx = _grid.findIndex(function (v) {
            if (v == '0') {
                return true;
            }
            return false;
        });
        return (idx < 0);
    }

    function block_or_win(_set) {
        console.log(_set);
        for (var i = 0; i < _set.length; i++) {
            if (_grid[_set[i]] == "0") {
                _grid[_set[i]] = game.ai_pawn;
                break;
            }
        }
    }

    function can_someone_win_in_next_move(func) {
        /*
         patterns, expressed in positions
         */
        console.log(_grid);
        var result = winning_paths.findIndex(
            function (vset) {
                var can_use_this_set = vset.reduce(function (prev, v) {
                    if (_grid[v] == '0') {
                        return prev;
                    }
                    if (_grid[v] == game.ai_pawn) {
                        prev.ai++;
                        return prev;
                    }
                    if (_grid[v] != game.ai_pawn) {
                        prev.human++;
                        return prev;
                    }
                    // TODO error condition
                    throw new Error('internal fault!!');
                }, {ai: 0, human: 0});
                //evaluate
                console.log(can_use_this_set);
                return ( func(can_use_this_set) ); // we found a set where we can win

            });
        return result; //yes you can win in this index position

    }

    function can_human_win() {
        /* patterns, expressed in positions */
        var human_win = can_someone_win_in_next_move(function (obj) {

            return (obj.human == 2 && obj.ai == 0);

        });

        if (human_win >= 0) {//  prevent human from winning
            block_or_win(winning_paths[human_win]);
            console.log('human could have won in next move, blocked!');
            return true;
        }
        return false; // this move was played
    }

    function can_AI_win() {
        /* patterns, expressed in positions */
        var ai_win = can_someone_win_in_next_move(function (obj) {

            return (obj.human == 0 && obj.ai == 2);

        });

        if (ai_win >= 0) {// win outright in next move
            block_or_win(winning_paths[ai_win]);
            console.log('AI can win in next move, go for it!');
            return true;
        }
        return false; //this move was played
    }


    /* AI , dont make it too smart */
    function pick_random_move() {
        // can i claim center, if it can
        if (_grid[4] == "0"){
            _grid[4] = game.ai_pawn;
            return 4;
        }

        // find empty spots and select random one
        var temp = _grid.reduce(function (prev, v, idx) {
            if (v == "0") {
                //console.log(idx + '-->' + v);
                prev.push(idx);
            }
            return prev;
        }, []);
        // 0--1--2--3--4//--i
        var rand = Math.random();
        var idx = rand * (temp.length);
        var pickler = Math.trunc(idx);
        var pos = temp[pickler];

        _grid[pos] = game.ai_pawn;

        return temp[pickler];

    }


    function eval_next_move() {
        if (!can_AI_win()) {
            if (!can_human_win()) {
                pick_random_move();
            }
        }
        process_move();
    }

    /* UI functions and event handling */
    /* UI functions and event handling */
    /* UI functions and event handling */

    function arr_from_node_list( nl ) {

        var rc = [];

        for (var i = 0; i < nl.length; i++) {
            rc.push(nl.item(i));
        }

        return rc;
    }

    function wrap_button_evt_handler(func, value) {

        return function (evt) {
            evt.extra = value; //enrich event
            func(evt);
        }

    }

    function set_content(ids, value) {

        if (!(ids instanceof Array)) {
            ids = [ids];
        }

        for (var i = 0; i < ids.length; i++) {
            var ui = document.querySelector(ids[i]);
            if (!ui) {
                throw new Error("oops, no #" + id + " found in DOM");
            }
            ui.textContent = ( value != undefined ? '' + value : '');
        }

        return ui;
    }

    function expose(id) {
        var ui = document.querySelector(id);
        if (!ui) {
            throw new Error("oops, no #" + id + " found in DOM");
        }
        return ui;
    }

    /*
     example:
     add_classes(elt, "class1").remove_classes("class3");
     */

    function add_classes(elt, arr) {

        if (typeof elt == "string"){
            elt = expose(elt);
        }

        if (!(arr instanceof Array)) {
            arr = [arr];
        }
        arr.forEach(function (_class) {
            elt.classList.add(_class);
        });

        var k = remove_classes.bind(undefined, elt);

        return {
            remove_classes: k
        };
    }

    /*
     example:
     remove_classes(elt, "class1").add_classes("class3");
     */

    function remove_classes(elt, arr) {

        if (typeof elt == "string"){
            elt = expose(elt);
        }

        if (!(arr instanceof Array)) {
            arr = [arr];
        }

        arr.forEach(function (_class) {
            elt.classList.remove(_class);
        });

        var k = add_classes.bind(undefined,elt);

        return {
            add_classes: k
        }
    }

    /* game end result */
    /* game end result */
    /* game end result */


    function end_animation_notify_box( evt ){

        var next = expose("#next");

        if (evt.extra.o == "in"){
            next.addEventListener( "click", dlg_bnt_next);
            dialog.removeEventListener( "animationend" , end_fade_in_notify_box);
            dialog.addEventListener( "animationend" , end_fade_out_notify_box);
        }

        if (evt.extra.o == "out") {
            dunk_notify_box();
            /* start new game */
            /* start new game */
            /* start new game */
            turn_on_buttons();
            game.ai_pawn = (game.ai_pawn == "x") ? "o" : "x";
            init.reset();
            update_game_board();
        }
    }

    var end_fade_in_notify_box = wrap_button_evt_handler(end_animation_notify_box,{o:"in"});
    var end_fade_out_notify_box = wrap_button_evt_handler(end_animation_notify_box,{o:"out"});


    function  dlg_bnt_next( evt ) {

        var dialog = expose("#dialog");

        remove_classes( dialog , ["fadeInDown", "faceOutUp", "animated"] );
        add_classes(dialog, ["fadeOutUp", "animated"]);
        remove_classes( "#backdrop", "in");
    }


    function show_notification_dlg(){

        var dialog = expose("#dialog");
        var dlg_class = [];

        if (game.state.res == "won"){
            if (game.state.player == game.ai_pawn){
                dlg_class.push("ai");
            }
            else{
                dlg_class.push("usr");
            }
        }
        else {
           dlg_class.push("tie");
        }

        if (game.ai_pawn == "x"){
            dlg_class.push("xx");
        }
        else {
            dlg_class.push("oo");
        }
        add_classes(dialog, dlg_class);
        //dialog.addEventListener( "animationend" ,end_animation_notify_box);
        dialog.addEventListener( "animationend" , end_fade_in_notify_box);
        dialog.removeEventListener( "animationend" , end_fade_out_notify_box);

        add_classes("#backdrop",["in"]);
        add_classes("#modal-canvas",["in"]);
        add_classes(dialog,["fadeInDown","animated"]);

    }

    function dunk_notify_box(){

        remove_classes( "#backdrop", "in");
        remove_classes( "#modal-canvas", "in");
        var dialog = expose("#dialog");
        remove_classes( dialog , ["fadeInDown","fadeOutUp","animated","xx","usr","oo","ai","tie"]);
        dialog.removeEventListener( "animationend" , end_fade_in_notify_box);
        dialog.removeEventListener( "animationend" , end_fade_out_notify_box);
        expose("#next").removeEventListener( "click" , dlg_bnt_next);

    }


    /* game grid */
    /* game grid */
    /* game grid */

    function update_game_board() {

        for (var i = 0; i < 9; i++){
            var elt = expose("#cell"+i);
            var val = _grid[i];
            switch ( val ){
                case 0:
                    add_classes(elt, "allow").remove_classes(["fa","fa-circle-o","fa-times","red-text","black-txt"]);
                    break;
                case 'x':
                    add_classes(elt, ["fa","fa-times","black-txt"]).remove_classes(["allow","fa-circle-o","red-txt"]);
                    elt.removeEventListener("click", btn_handlers[i] );
                    break;
                case 'o':
                    add_classes( elt, ["fa","fa-circle-o","red-txt"]).remove_classes(["allow","fa-times","black-txt"]);
                    elt.removeEventListener("click", btn_handlers[i] );
                    break;
                default:
                    remove_classes(elt, "allow");
                    elt.removeEventListener("click", btn_handlers[i] );
            }
        }

        /* update scores */

        set_content("#human-score", game.human_score);
        set_content("#tie-score", game.tie_score);
        set_content("#ai-score", game.ai_score);


    }

    function grid_pos_selected(evt) {
        var btn_list, idx, btn, dialog;
        var pos = evt.extra.btn_id;
        init.move({position:pos});
        /* check if someone won or not */
        if (game.state.res) {
            if (game.state.res == "won") {
                if (game.state.player == game.ai_pawn) {
                    game.ai_score++;
                }
                else {
                    game.human_score++;
                }
            }
            if (game.state.res == "tie") {
                game.tie_score++;
            }
            console.log("disabling-grid");
            for (idx = 0; idx < 9; idx++){
                if ( _grid[idx] == '0'){
                    _grid[idx] = "-";
                }
            }
        }
        update_game_board();
        if (game.state.res){
            dunk_notify_box();
            show_notification_dlg();
        }
    }


    function dunk_buttons() {

        for (var i= 0; i < 9 ; i++){
            var btn = expose("#cell"+i);
            btn.removeEventListener("click", btn_handlers[ i ]);
            remove_classes(btn, ["allow","black-txt" ,"red-txt","fa", "fa-times", "fa-circle-o"]);
        }
    }

    function turn_on_buttons() {
        for (var i= 0; i < 9 ; i++){
            var btn = expose("#cell"+i);
            btn.addEventListener("click", btn_handlers[i]);
            add_classes(btn, ["allow"]);
        }
    }

    function dunk_game_grid() {

        var game_box = expose("#game");
        add_classes(game_box, "hide");
        remove_classes(game_box, ["animated", "zoomIn", "zoomOut", "clickable"]);

        var game_grid = expose("#game-grid");
        remove_classes(game_grid, "clickable");

        dunk_buttons();
    }

    function end_animation_game_grid() {
        console.log('animation game grid ended');
        var game_box = expose("#game");
        remove_classes(game_box, ["animated", "zoomIn", "zoomOut"]);

        if (game.state.rc == 2) {
            turn_on_buttons();
            game_box.removeEventListener("animationend", end_animation_game_grid);

            /* start new game */
            /* start new game */
            /* start new game */

            init.reset();
            update_game_board();

            return;
        }
        remove_classes(gam_box, "clickable");
        //TODO comming from state 4 (after notification)
    }


    function zoom_out_game_grid() {
        //TODO

    }

    function zoom_in_game_grid() {
        var game = expose("#game");
        add_classes(game, ["animated", "zoomIn", "clickable"]);
        game.addEventListener("animationend", end_animation_game_grid);
        remove_classes(game, "hide");//fire it off
    }


    /* choice box */
    /* choice box */
    /* choice box */

    function end_animation_choice_box(evt) {

        var txt_descr;
        var btnz;
        var bnt_x_choose;
        var bnt_o_choose;
        var m_choice_box;
        game.state.cnt--;
        console.log(game.state);

        if (game.state.cnt == 0) { /* fade in animation ended */

            m_choice_box = expose("#make-choice");
            txt_descr = expose("#descr-choice");
            btnz = expose("#choice-btnz");

            bnt_x_choose = expose("#select-cross");
            bnt_o_choose = expose("#select-circle");

            if (game.state.rc == 0) {    /* animation fade in */
                add_classes(btnz, "clickable");
                bnt_x_choose.addEventListener("click", x_choose);
                bnt_o_choose.addEventListener("click", o_choose);
                console.log('event listeners added');
            }
            else {                     /* animation fade out */
                remove_classes(btnz, "clickable");
                bnt_x_choose.removeEventListener("click", x_choose);
                bnt_o_choose.removeEventListener("click", o_choose);
                add_classes(m_choice_box, "hide");
                console.log('event listeners removed');
                /* MOVE TO NEXT STATE BRING IN GAME GRID */
                dunk_game_grid();
                game.state = {rc: 2, cnt: 1};
                zoom_in_game_grid();

                dunk_notify_box();
                //TODO fade_in_game_grid()
            }

            remove_classes(txt_descr, ["fadeInDown", "fadeOutUp", "animated"]);
            remove_classes(btnz, ["animated", "fadeOutDown", "fadeInUp"]);

            txt_descr.removeEventListener("animationend", end_animation_choice_box);
            btnz.removeEventListener("animationend", end_animation_choice_box);
        }
    }


    function dunk_choice_box() {
        var m_choice_box = expose("#make-choice");
        var txt_descr = expose("#descr-choice");
        var btnz = expose("#choice-btnz");
        var bnt_x_choose = expose("#select-cross");
        var bnt_o_choose = expose("#select-circle");

        add_classes(m_choice_box, "hide");
        remove_classes(txt_descr, ["fadeInDown", "animated"]);
        remove_classes(btnz, ["clickable", "animated", "fadeOutDown", "fadeInUp"]);
        txt_descr.removeEventListener("animationend", end_animation_choice_box);
        btnz.removeEventListener("animationend", end_animation_choice_box);

        bnt_x_choose.removeEventListener("click", x_choose);
        bnt_o_choose.removeEventListener("click", o_choose);

    }

    function fade_in_choice_box() {

        var m_choice_box = expose("#make-choice");
        var txt_descr = expose("#descr-choice");
        var btnz = expose("#choice-btnz");

        var bnt_x_choose = expose("#select-cross");
        var bnt_o_choose = expose("#select-circle");

        add_classes(txt_descr, ["fadeInDown", "animated"]);
        add_classes(btnz, ["fadeInUp", "animated"]);

        /* */
        remove_classes(m_choice_box, "hide"); //fire it off

        /* */
        txt_descr.addEventListener("animationend", end_animation_choice_box);
        btnz.addEventListener("animationend", end_animation_choice_box);

        /* */
        bnt_x_choose.addEventListener("click", x_choose);
        bnt_o_choose.addEventListener("click", o_choose);
    }

    function fade_out_choice_box() {

        dunk_game_grid();

        dunk_notify_box();

        /* disable choice buttons */

        var bnt_x_choose = expose("#select-cross");
        var bnt_o_choose = expose("#select-circle");
        bnt_x_choose.removeEventListener("click", x_choose);
        bnt_o_choose.removeEventListener("click", o_choose);

        /* disable button hover animaton */

        var btnz = expose("#choice-btnz");
        remove_classes(btnz, "clickable");

        var txt_descr = expose("#descr-choice");

        add_classes(txt_descr, ["fadeOutUp", "animated"]);
        add_classes(btnz, ["fadeOutDown", "animated"]);

        txt_descr.addEventListener("animationend", end_animation_choice_box);
        btnz.addEventListener("animationend", end_animation_choice_box);

    }


    function choice(evt) {
        console.log({t: 'choice_made:', d: evt.extra});
        game.ai_pawn = (evt.extra.pawn == 'x' ? 'o' : 'x');
        game.state = {rc: 1, cnt: 2};
        fade_out_choice_box();
    }

    var x_choose = wrap_button_evt_handler(choice, {pawn: "x"});
    var o_choose = wrap_button_evt_handler(choice, {pawn: "o"});






    /* public interface */
    function init() {
        var i;
        set_arr(_grid, 0);
        game.ai_pawn = 0;
        game.state = 0;

        dunk_choice_box();
        set_content(["#human-score", "#tie-score", "#ai-score"], 0);
        dunk_game_grid();
        dunk_notify_box();
        game.state = {rc: 0, cnt: 2};
        fade_in_choice_box();

        /* only do this once, pre-cook handlers */
        for (i = 0; i < 9; i++) {
            var func = wrap_button_evt_handler(grid_pos_selected, {btn_id: i});
            btn_handlers.push(func);
        }
        /* remove this*/

    }

    /* reset game */
    init.reset = function () {

        set_arr(_grid, 0);

        game.state = {rc: 3};

        if (game.ai_pawn == "x") {
            _grid[4] = game.ai_pawn; // best first move
        }

        return;
    };

    /*user makes move */
    init.move = function (move) {

        if (game.state.rc != 3) {
            throw new Error('game not initialized');
        }

        if (!move) {
            throw new Error('move argument not defined');
        }

        if (move.position == undefined) {
            throw new Error('move.position not defined');
        }

        if (typeof move.position != "number") {
            throw new Error('move position should be a number.');
        }

        if (move.position < 0 || move.position > 8 || _grid[move.position] != 0) {
            throw new Error('move position not available.');
        }

        _grid[move.position] = (game.ai_pawn == 'x' ? 'o' : 'x');

        process_move();
        if (game.state.res == undefined) {
            eval_next_move(); //process_move() is called here
        }

        return ;

    };
    console.log('returning init');
    return init;


})();


window.onload = t_game;
            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.

Console