basti1012.bplaced.net

Du siehst gerade eine vereinfachte Darstellung unserer Inhalte. Normale Ansicht mit richtiger Formatierung.
    Einfaches Tetris Spiel was eigentlich fast jeder aus der Gameboy Zeit noch kennen sollte

    Code

                                        
                                    <!DOCTYPE html>
    <!-- saved from url=(0035)https://pranx.com/tetris/index.html -->
    <html lang="en" data-lt-installed="true">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Online Tetris Game</title>
    <!--
    <link rel="canonical" href="https://pranx.com/tetris/">
    -->
    <style>
    body, html      { font-family: Helvetica, sans-serif; background-color: transparent;cursor: default !important;	}
    #tetris   { margin: 0 auto; padding: 0; color: #444; }
    #stats    { display: none; vertical-align: top; }
    #canvas   { display: inline-block; vertical-align: top; border: 2px solid #333; background-color: #ffffff;}
    #menu     { display: inline-block; vertical-align: top; position: relative; }
    #menu p   { margin: 0.5em 0; text-align: center; }
    #start	  { Color: #F00;}
    #menu p a {	text-decoration: none;		color: #000;		font-weight: bold;	}
    #focusLost {
    position: fixed;
    z-index: 1000;
    top: 0;
    display: none;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(0,0,0,0.8);
    font-size: 19px;
    font-weight: bold;
    color: #FFF;
    text-align: center;
    padding-top: 22%;
    }
    #upcoming { display: block; margin: 0 auto; background-color: #E0E0E0; }
    #score    { color: #444; font-weight: bold; vertical-align: middle; }
    #rows     { color: #444; font-weight: bold; vertical-align: middle; }
    #stats    { position: absolute; bottom: 0em; right: 1em; }
    @media screen and (min-width:   0px) and (min-height:   0px)  { #tetris { font-size: 0.75em; width: 250px; } #menu { width: 100px; height: 200px; } #upcoming { width:  50px; height:  50px; } #canvas { width: 100px; height: 200px; } } /* 10px chunks */
    @media screen and (min-width: 400px) and (min-height: 400px)  { #tetris { font-size: 1.00em; width: 350px; } #menu { width: 150px; height: 300px; } #upcoming { width:  75px; height:  75px; } #canvas { width: 150px; height: 300px; } } /* 15px chunks */
    @media screen and (min-width: 500px) and (min-height: 500px)  { #tetris { font-size: 1.25em; width: 450px; } #menu { width: 200px; height: 400px; } #upcoming { width: 100px; height: 100px; } #canvas { width: 200px; height: 400px; } } /* 20px chunks */
    @media screen and (min-width: 600px) and (min-height: 600px)  { #tetris { font-size: 1.50em; width: 550px; } #menu { width: 250px; height: 500px; } #upcoming { width: 125px; height: 125px; } #canvas { width: 250px; height: 500px; } } /* 25px chunks */
    @media screen and (min-width: 700px) and (min-height: 700px)  { #tetris { font-size: 1.75em; width: 650px; } #menu { width: 300px; height: 600px; } #upcoming { width: 150px; height: 150px; } #canvas { width: 300px; height: 600px; } } /* 30px chunks */
    @media screen and (min-width: 800px) and (min-height: 800px)  { #tetris { font-size: 2.00em; width: 750px; } #menu { width: 350px; height: 700px; } #upcoming { width: 175px; height: 175px; } #canvas { width: 350px; height: 700px; } } /* 35px chunks */
    @media screen and (min-width: 900px) and (min-height: 900px)  { #tetris { font-size: 2.25em; width: 850px; } #menu { width: 400px; height: 800px; } #upcoming { width: 200px; height: 200px; } #canvas { width: 400px; height: 800px; } } /* 40px chunks */
    </style>
    
    <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','GTM-5RJ4ST6');</script>
    </head>
    <body onblur="showAlert()">
    
     <div id="tetris">
        <div id="menu">
          <p id="start">
          <a href="javascript:play();"><strong>Click Here To START</strong></a>
          </p>
          <p><canvas id="upcoming" width="50" height="50"></canvas></p>
          <p>score <span id="score">00000</span></p>
          <p>rows <span id="rows">0</span></p>
          
        <div id="stats" style="cursor: pointer; width: 80px; opacity: 0.9; z-index: 10001;">
        
        
        <div style="background-color: rgb(8, 8, 24); padding: 2px 0px 3px;">
        
        <div style="font-family: Helvetica, Arial, sans-serif; text-align: left; font-size: 9px; color: rgb(0, 255, 255); margin: 0px 0px 1px 3px;">
        <span style="font-weight:bold">60 FPS</span> (17-60)</div>
        
        <canvas width="74" height="30" style="display: block; margin-left: 3px;"></canvas>
            
        </div>
        </div>
        </div>
        <canvas id="canvas" width="100" height="200">
          Canvas not supported!
        </canvas>
      </div>
    
      <script>
          var loc = window.location.href + '';
    if (loc.indexOf('http://') == 0) {
        window.location.href = loc.replace('http://', 'https://');
        // https redirect
    }
    var Stats = function() {
        function s(a, g, d) {
            var f, c, e;
            for (c = 0; c < 30; c++)
                for (f = 0; f < 73; f++)
                    e = (f + c * 74) * 4,
                    a[e] = a[e + 4],
                    a[e + 1] = a[e + 5],
                    a[e + 2] = a[e + 6];
            for (c = 0; c < 30; c++)
                e = (73 + c * 74) * 4,
                c < g ? (a[e] = b[d].bg.r,
                a[e + 1] = b[d].bg.g,
                a[e + 2] = b[d].bg.b) : (a[e] = b[d].fg.r,
                a[e + 1] = b[d].fg.g,
                a[e + 2] = b[d].fg.b)
        }
        var r = 0, t = 2, g, u = 0, j = (new Date).getTime(), F = j, v = j, l = 0, w = 1E3, x = 0, k, d, a, m, y, n = 0, z = 1E3, A = 0, f, c, o, B, p = 0, C = 1E3, D = 0, h, i, q, E, b = {
            fps: {
                bg: {
                    r: 16,
                    g: 16,
                    b: 48
                },
                fg: {
                    r: 0,
                    g: 255,
                    b: 255
                }
            },
            ms: {
                bg: {
                    r: 16,
                    g: 48,
                    b: 16
                },
                fg: {
                    r: 0,
                    g: 255,
                    b: 0
                }
            },
            mb: {
                bg: {
                    r: 48,
                    g: 16,
                    b: 26
                },
                fg: {
                    r: 255,
                    g: 0,
                    b: 128
                }
            }
        };
        g = document.createElement("div");
        g.style.cursor = "pointer";
        g.style.width = "80px";
        g.style.opacity = "0.9";
        g.style.zIndex = "10001";
        g.addEventListener("click", function() {
            r++;
            r == t && (r = 0);
            k.style.display = "none";
            f.style.display = "none";
            h.style.display = "none";
            switch (r) {
            case 0:
                k.style.display = "block";
                break;
            case 1:
                f.style.display = "block";
                break;
            case 2:
                h.style.display = "block"
            }
        }, !1);
        k = document.createElement("div");
        k.style.backgroundColor = "rgb(" + Math.floor(b.fps.bg.r / 2) + "," + Math.floor(b.fps.bg.g / 2) + "," + Math.floor(b.fps.bg.b / 2) + ")";
        k.style.padding = "2px 0px 3px 0px";
        g.appendChild(k);
        d = document.createElement("div");
        d.style.fontFamily = "Helvetica, Arial, sans-serif";
        d.style.textAlign = "left";
        d.style.fontSize = "9px";
        d.style.color = "rgb(" + b.fps.fg.r + "," + b.fps.fg.g + "," + b.fps.fg.b + ")";
        d.style.margin = "0px 0px 1px 3px";
        d.innerHTML = '<span style="font-weight:bold">FPS</span>';
        k.appendChild(d);
        a = document.createElement("canvas");
        a.width = 74;
        a.height = 30;
        a.style.display = "block";
        a.style.marginLeft = "3px";
        k.appendChild(a);
        m = a.getContext("2d");
        m.fillStyle = "rgb(" + b.fps.bg.r + "," + b.fps.bg.g + "," + b.fps.bg.b + ")";
        m.fillRect(0, 0, a.width, a.height);
        y = m.getImageData(0, 0, a.width, a.height);
        f = document.createElement("div");
        f.style.backgroundColor = "rgb(" + Math.floor(b.ms.bg.r / 2) + "," + Math.floor(b.ms.bg.g / 2) + "," + Math.floor(b.ms.bg.b / 2) + ")";
        f.style.padding = "2px 0px 3px 0px";
        f.style.display = "none";
        g.appendChild(f);
        c = document.createElement("div");
        c.style.fontFamily = "Helvetica, Arial, sans-serif";
        c.style.textAlign = "left";
        c.style.fontSize = "9px";
        c.style.color = "rgb(" + b.ms.fg.r + "," + b.ms.fg.g + "," + b.ms.fg.b + ")";
        c.style.margin = "0px 0px 1px 3px";
        c.innerHTML = '<span style="font-weight:bold">MS</span>';
        f.appendChild(c);
        a = document.createElement("canvas");
        a.width = 74;
        a.height = 30;
        a.style.display = "block";
        a.style.marginLeft = "3px";
        f.appendChild(a);
        o = a.getContext("2d");
        o.fillStyle = "rgb(" + b.ms.bg.r + "," + b.ms.bg.g + "," + b.ms.bg.b + ")";
        o.fillRect(0, 0, a.width, a.height);
        B = o.getImageData(0, 0, a.width, a.height);
        try {
            performance && performance.memory && performance.memory.totalJSHeapSize && (t = 3)
        } catch (G) {}
        h = document.createElement("div");
        h.style.backgroundColor = "rgb(" + Math.floor(b.mb.bg.r / 2) + "," + Math.floor(b.mb.bg.g / 2) + "," + Math.floor(b.mb.bg.b / 2) + ")";
        h.style.padding = "2px 0px 3px 0px";
        h.style.display = "none";
        g.appendChild(h);
        i = document.createElement("div");
        i.style.fontFamily = "Helvetica, Arial, sans-serif";
        i.style.textAlign = "left";
        i.style.fontSize = "9px";
        i.style.color = "rgb(" + b.mb.fg.r + "," + b.mb.fg.g + "," + b.mb.fg.b + ")";
        i.style.margin = "0px 0px 1px 3px";
        i.innerHTML = '<span style="font-weight:bold">MB</span>';
        h.appendChild(i);
        a = document.createElement("canvas");
        a.width = 74;
        a.height = 30;
        a.style.display = "block";
        a.style.marginLeft = "3px";
        h.appendChild(a);
        q = a.getContext("2d");
        q.fillStyle = "#301010";
        q.fillRect(0, 0, a.width, a.height);
        E = q.getImageData(0, 0, a.width, a.height);
        return {
            domElement: g,
            update: function() {
                u++;
                j = (new Date).getTime();
                n = j - F;
                z = Math.min(z, n);
                A = Math.max(A, n);
                s(B.data, Math.min(30, 30 - n / 200 * 30), "ms");
                c.innerHTML = '<span style="font-weight:bold">' + n + " MS</span> (" + z + "-" + A + ")";
                o.putImageData(B, 0, 0);
                F = j;
                if (j > v + 1E3) {
                    l = Math.round(u * 1E3 / (j - v));
                    w = Math.min(w, l);
                    x = Math.max(x, l);
                    s(y.data, Math.min(30, 30 - l / 100 * 30), "fps");
                    d.innerHTML = '<span style="font-weight:bold">' + l + " FPS</span> (" + w + "-" + x + ")";
                    m.putImageData(y, 0, 0);
                    if (t == 3)
                        p = performance.memory.usedJSHeapSize * 9.54E-7,
                        C = Math.min(C, p),
                        D = Math.max(D, p),
                        s(E.data, Math.min(30, 30 - p / 2), "mb"),
                        i.innerHTML = '<span style="font-weight:bold">' + Math.round(p) + " MB</span> (" + Math.round(C) + "-" + Math.round(D) + ")",
                        q.putImageData(E, 0, 0);
                    v = j;
                    u = 0
                }
            }
        }
    };
    
    //-------------------------------------------------------------------------
    // base helper methods
    //-------------------------------------------------------------------------
    
    function get(id) {
        return document.getElementById(id);
    }
    function hide(id) {
        get(id).style.visibility = 'hidden';
    }
    function show(id) {
        get(id).style.visibility = null;
    }
    function html(id, html) {
        get(id).innerHTML = html;
    }
    
    function timestamp() {
        return new Date().getTime();
    }
    function random(min, max) {
        return (min + (Math.random() * (max - min)));
    }
    function randomChoice(choices) {
        return choices[Math.round(random(0, choices.length - 1))];
    }
    
    if (!window.requestAnimationFrame) {
        // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
        window.requestAnimationFrame = window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback, element) {
            window.setTimeout(callback, 1000 / 60);
        }
    }
    
    //-------------------------------------------------------------------------
    // game constants
    //-------------------------------------------------------------------------
    
    var KEY = {
        ESC: 27,
        SPACE: 32,
        LEFT: 37,
        UP: 38,
        RIGHT: 39,
        DOWN: 40
    }
      , DIR = {
        UP: 0,
        RIGHT: 1,
        DOWN: 2,
        LEFT: 3,
        MIN: 0,
        MAX: 3
    }
      , stats = new Stats()
      , canvas = get('canvas')
      , ctx = canvas.getContext('2d')
      , ucanvas = get('upcoming')
      , uctx = ucanvas.getContext('2d')
      , speed = {
        start: 0.6,
        decrement: 0.005,
        min: 0.1
    }
      , // how long before piece drops by 1 row (seconds)
    nx = 10
      , // width of tetris court (in blocks)
    ny = 20
      , // height of tetris court (in blocks)
    nu = 5;
    // width/height of upcoming preview (in blocks)
    
    //-------------------------------------------------------------------------
    // game variables (initialized during reset)
    //-------------------------------------------------------------------------
    
    var dx, dy, // pixel size of a single tetris block
    blocks, // 2 dimensional array (nx*ny) representing tetris court - either empty block or occupied by a 'piece'
    actions, // queue of user actions (inputs)
    playing, // true|false - game is in progress
    dt, // time since starting this game
    current, // the current piece
    next, // the next piece
    score, // the current score
    vscore, // the currently displayed score (it catches up to score in small chunks - like a spinning slot machine)
    rows, // number of completed rows in the current game
    step;
    // how long before current piece drops by 1 row
    
    //-------------------------------------------------------------------------
    // tetris pieces
    //
    // blocks: each element represents a rotation of the piece (0, 90, 180, 270)
    //         each element is a 16 bit integer where the 16 bits represent
    //         a 4x4 set of blocks, e.g. j.blocks[0] = 0x44C0
    //
    //             0100 = 0x4 << 3 = 0x4000
    //             0100 = 0x4 << 2 = 0x0400
    //             1100 = 0xC << 1 = 0x00C0
    //             0000 = 0x0 << 0 = 0x0000
    //                               ------
    //                               0x44C0
    //
    //-------------------------------------------------------------------------
    
    var i = {
        size: 4,
        blocks: [0x0F00, 0x2222, 0x00F0, 0x4444],
        color: 'cyan'
    };
    var j = {
        size: 3,
        blocks: [0x44C0, 0x8E00, 0x6440, 0x0E20],
        color: 'blue'
    };
    var l = {
        size: 3,
        blocks: [0x4460, 0x0E80, 0xC440, 0x2E00],
        color: 'orange'
    };
    var o = {
        size: 2,
        blocks: [0xCC00, 0xCC00, 0xCC00, 0xCC00],
        color: 'yellow'
    };
    var s = {
        size: 3,
        blocks: [0x06C0, 0x8C40, 0x6C00, 0x4620],
        color: 'green'
    };
    var t = {
        size: 3,
        blocks: [0x0E40, 0x4C40, 0x4E00, 0x4640],
        color: 'purple'
    };
    var z = {
        size: 3,
        blocks: [0x0C60, 0x4C80, 0xC600, 0x2640],
        color: 'red'
    };
    
    //------------------------------------------------
    // do the bit manipulation and iterate through each
    // occupied block (x,y) for a given piece
    //------------------------------------------------
    function eachblock(type, x, y, dir, fn) {
        var bit, result, row = 0, col = 0, blocks = type.blocks[dir];
        for (bit = 0x8000; bit > 0; bit = bit >> 1) {
            if (blocks & bit) {
                fn(x + col, y + row);
            }
            if (++col === 4) {
                col = 0;
                ++row;
            }
        }
    }
    
    //-----------------------------------------------------
    // check if a piece can fit into a position in the grid
    //-----------------------------------------------------
    function occupied(type, x, y, dir) {
        var result = false
        eachblock(type, x, y, dir, function(x, y) {
            if ((x < 0) || (x >= nx) || (y < 0) || (y >= ny) || getBlock(x, y))
                result = true;
        });
        return result;
    }
    
    function unoccupied(type, x, y, dir) {
        return !occupied(type, x, y, dir);
    }
    
    //-----------------------------------------
    // start with 4 instances of each piece and
    // pick randomly until the 'bag is empty'
    //-----------------------------------------
    var pieces = [];
    function randomPiece() {
        if (pieces.length == 0)
            pieces = [i, i, i, i, j, j, j, j, l, l, l, l, o, o, o, o, s, s, s, s, t, t, t, t, z, z, z, z];
        var type = pieces.splice(random(0, pieces.length - 1), 1)[0];
        return {
            type: type,
            dir: DIR.UP,
            x: Math.round(random(0, nx - type.size)),
            y: 0
        };
    }
    
    //-------------------------------------------------------------------------
    // GAME LOOP
    //-------------------------------------------------------------------------
    
    function run() {
    
        showStats();
        // initialize FPS counter
        addEvents();
        // attach keydown and resize events
    
        var last = now = timestamp();
        function frame() {
            now = timestamp();
            update(Math.min(1, (now - last) / 1000.0));
            // using requestAnimationFrame have to be able to handle large delta's caused when it 'hibernates' in a background or non-visible tab
            draw();
            stats.update();
            last = now;
            requestAnimationFrame(frame, canvas);
        }
    
        resize();
        // setup all our sizing information
        reset();
        // reset the per-game variables
        frame();
        // start the first frame
    
    }
    
    function showStats() {
        stats.domElement.id = 'stats';
        get('menu').appendChild(stats.domElement);
    }
    
    function addEvents() {
        document.addEventListener('keydown', keydown, false);
        window.addEventListener('resize', resize, false);
    }
    
    function resize(event) {
        canvas.width = canvas.clientWidth;
        // set canvas logical size equal to its physical size
        canvas.height = canvas.clientHeight;
        // (ditto)
        ucanvas.width = ucanvas.clientWidth;
        ucanvas.height = ucanvas.clientHeight;
        dx = canvas.width / nx;
        // pixel size of a single tetris block
        dy = canvas.height / ny;
        // (ditto)
        invalidate();
        invalidateNext();
    }
    
    function keydown(ev) {
        var handled = false;
        if (playing) {
            switch (ev.keyCode) {
            case KEY.LEFT:
                actions.push(DIR.LEFT);
                handled = true;
                break;
            case KEY.RIGHT:
                actions.push(DIR.RIGHT);
                handled = true;
                break;
            case KEY.UP:
                actions.push(DIR.UP);
                handled = true;
                break;
            case KEY.DOWN:
                actions.push(DIR.DOWN);
                handled = true;
                break;
            case KEY.ESC:
                lose();
                handled = true;
                break;
            }
        } else if (ev.keyCode == KEY.SPACE) {
            play();
            handled = true;
        }
        if (handled)
            ev.preventDefault();
        // prevent arrow keys from scrolling the page (supported in IE9+ and all other browsers)
    }
    
    //-------------------------------------------------------------------------
    // GAME LOGIC
    //-------------------------------------------------------------------------
    
    function play() {
        hide('start');
        reset();
        playing = true;
    }
    function lose() {
        show('start');
        setVisualScore();
        playing = false;
    }
    
    function setVisualScore(n) {
        vscore = n || score;
        invalidateScore();
    }
    function setScore(n) {
        score = n;
        setVisualScore(n);
    }
    function addScore(n) {
        score = score + n;
    }
    function clearScore() {
        setScore(0);
    }
    function clearRows() {
        setRows(0);
    }
    function setRows(n) {
        rows = n;
        step = Math.max(speed.min, speed.start - (speed.decrement * rows));
        invalidateRows();
    }
    function addRows(n) {
        setRows(rows + n);
    }
    function getBlock(x, y) {
        return (blocks && blocks[x] ? blocks[x][y] : null);
    }
    function setBlock(x, y, type) {
        blocks[x] = blocks[x] || [];
        blocks[x][y] = type;
        invalidate();
    }
    function clearBlocks() {
        blocks = [];
        invalidate();
    }
    function clearActions() {
        actions = [];
    }
    function setCurrentPiece(piece) {
        current = piece || randomPiece();
        invalidate();
    }
    function setNextPiece(piece) {
        next = piece || randomPiece();
        invalidateNext();
    }
    
    function reset() {
        dt = 0;
        clearActions();
        clearBlocks();
        clearRows();
        clearScore();
        setCurrentPiece(next);
        setNextPiece();
    }
    
    function update(idt) {
        if (playing) {
            if (vscore < score)
                setVisualScore(vscore + 1);
            handle(actions.shift());
            dt = dt + idt;
            if (dt > step) {
                dt = dt - step;
                drop();
            }
        }
    }
    
    function handle(action) {
        switch (action) {
        case DIR.LEFT:
            move(DIR.LEFT);
            break;
        case DIR.RIGHT:
            move(DIR.RIGHT);
            break;
        case DIR.UP:
            rotate();
            break;
        case DIR.DOWN:
            drop();
            break;
        }
    }
    
    function move(dir) {
        var x = current.x
          , y = current.y;
        switch (dir) {
        case DIR.RIGHT:
            x = x + 1;
            break;
        case DIR.LEFT:
            x = x - 1;
            break;
        case DIR.DOWN:
            y = y + 1;
            break;
        }
        if (unoccupied(current.type, x, y, current.dir)) {
            current.x = x;
            current.y = y;
            invalidate();
            return true;
        } else {
            return false;
        }
    }
    
    function rotate() {
        var newdir = (current.dir == DIR.MAX ? DIR.MIN : current.dir + 1);
        if (unoccupied(current.type, current.x, current.y, newdir)) {
            current.dir = newdir;
            invalidate();
        }
    }
    
    function drop() {
        if (!move(DIR.DOWN)) {
            addScore(10);
            dropPiece();
            removeLines();
            setCurrentPiece(next);
            setNextPiece(randomPiece());
            clearActions();
            if (occupied(current.type, current.x, current.y, current.dir)) {
                lose();
            }
        }
    }
    
    function dropPiece() {
        eachblock(current.type, current.x, current.y, current.dir, function(x, y) {
            setBlock(x, y, current.type);
        });
    }
    
    function removeLines() {
        var x, y, complete, n = 0;
        for (y = ny; y > 0; --y) {
            complete = true;
            for (x = 0; x < nx; ++x) {
                if (!getBlock(x, y))
                    complete = false;
            }
            if (complete) {
                removeLine(y);
                y = y + 1;
                // recheck same line
                n++;
            }
        }
        if (n > 0) {
            addRows(n);
            addScore(100 * Math.pow(2, n - 1));
            // 1: 100, 2: 200, 3: 400, 4: 800
        }
    }
    
    function removeLine(n) {
        var x, y;
        for (y = n; y >= 0; --y) {
            for (x = 0; x < nx; ++x)
                setBlock(x, y, (y == 0) ? null : getBlock(x, y - 1));
        }
    }
    
    //-------------------------------------------------------------------------
    // RENDERING
    //-------------------------------------------------------------------------
    
    var invalid = {};
    
    function invalidate() {
        invalid.court = true;
    }
    function invalidateNext() {
        invalid.next = true;
    }
    function invalidateScore() {
        invalid.score = true;
    }
    function invalidateRows() {
        invalid.rows = true;
    }
    
    function draw() {
        ctx.save();
        ctx.lineWidth = 1;
        ctx.translate(0.5, 0.5);
        // for crisp 1px black lines
        drawCourt();
        drawNext();
        drawScore();
        drawRows();
        ctx.restore();
    }
    
    function drawCourt() {
        if (invalid.court) {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            if (playing)
                drawPiece(ctx, current.type, current.x, current.y, current.dir);
            var x, y, block;
            for (y = 0; y < ny; y++) {
                for (x = 0; x < nx; x++) {
                    if (block = getBlock(x, y))
                        drawBlock(ctx, x, y, block.color);
                }
            }
            ctx.strokeRect(0, 0, nx * dx - 1, ny * dy - 1);
            // court boundary
            invalid.court = false;
        }
    }
    
    function drawNext() {
        if (invalid.next) {
            var padding = (nu - next.type.size) / 2;
            // half-arsed attempt at centering next piece display
            uctx.save();
            uctx.translate(0.5, 0.5);
            uctx.clearRect(0, 0, nu * dx, nu * dy);
            drawPiece(uctx, next.type, padding, padding, next.dir);
            uctx.strokeStyle = 'black';
            uctx.strokeRect(0, 0, nu * dx - 1, nu * dy - 1);
            uctx.restore();
            invalid.next = false;
        }
    }
    
    function drawScore() {
        if (invalid.score) {
            html('score', ("00000" + Math.floor(vscore)).slice(-5));
            invalid.score = false;
        }
    }
    
    function drawRows() {
        if (invalid.rows) {
            html('rows', rows);
            invalid.rows = false;
        }
    }
    
    function drawPiece(ctx, type, x, y, dir) {
        eachblock(type, x, y, dir, function(x, y) {
            drawBlock(ctx, x, y, type.color);
        });
    }
    
    function drawBlock(ctx, x, y, color) {
        ctx.fillStyle = color;
        ctx.fillRect(x * dx, y * dy, dx, dy);
        ctx.strokeRect(x * dx, y * dy, dx, dy)
    }
    
    //-------------------------------------------------------------------------
    // FINALLY, lets run the game
    //-------------------------------------------------------------------------
    
    run();
    
    function showAlert() {
        document.getElementById("focusLost").style.display = "table-cell";
    }
    function hideAlert() {
        document.getElementById("focusLost").style.display = "none";
    }
    
      </script>
    
      
      <div id="focusLost" onclick="hideAlert()">
    	Click Here to Continue
      </div>
    
    
    
    </body></html>