(???) !DOCTYPE html>
 (???) html>
 (???)  <head>
 (???)    <meta charset="utf-8">
 (???)    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 (???)    <title>JavaScript Tetris in 1.5 kB</title>
 (???)    <link href="/css/black-no6.css" rel="stylesheet">
 (???)    <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="https://joriszwart.nl/feed/rss.xml">
 (???)    <link rel="alternate" type="application/atom+xml" title="Atom Feed" href="https://joriszwart.nl/feed/atom.xml">
 (???)    <link rel="alternate" type="application/json" title="JSON Feed" href="https://joriszwart.nl/feed/feed.json">
 (???)    <meta property="og:title" content="JavaScript Tetris in 1.5 kB">
 (???)    <meta property="og:description" content="JavaScript Tetris in 1.5 kB">         
 (???)    <meta property="og:image" content="https://joriszwart.nl/images/projects/jstetris.png">   
 (???)    <meta property="og:url" content="https://joriszwart.nl/games/javascript-tetris-1.5kb">
 (???)    
 (???)  </head>
 (???)  <body>
 (???)    <nav class="fixed-top sticky light">
 (???)      
 (???)      <ul>
 (???)        <li><a href="/articles">My articles</a></li>
 (???)        <li><a href="/games">My games</a></li>
 (???)        <li><a href="/projects">My projects</a></li>
 (???)        <li><a href="/talks">My talks</a></li>
 (???)        <li><a href="/contact">Contact</a></li>
 (???)      </ul>
 (???)    </nav>
 (???)    <header>
 (???)      
 (???)      <a href="/">
 (???)        
 (???)        <img src="/images/joriszwart-logo.png" alt="joriszwart.nl" width="577" height="74">
 (???)        <p class="uppercase">Code golf
 (???)  </p>
 (???)      </a>
 (???)    </header>
 (???)    <main>
 (???)    
 (???)      <article>
 (???)        <header>
 (???)          <div class="tags" aria-label="tags">
 (???)            <a href="/tags/a-language-a-year-keeps-the-doc-away" rel="tag">A language a year keeps the doc away</a>
 (???)            <a href="/tags/code-golf" rel="tag">Code golf</a>
 (???)            <a href="/tags/games" rel="tag">Games</a>
 (???)            <a href="/tags/javascript" rel="tag">JavaScript</a>
 (???)            <a href="/tags/optimization" rel="tag">Optimization</a>
 (???)            <a href="/tags/performance" rel="tag">Performance</a>
 (???)            <a href="/tags/size-coding" rel="tag">Size coding</a>
 (???)            <a href="/tags/tetris" rel="tag">Tetris</a>
 (???)          </div>
 (???)        </header>
 (???)         <h1 id="javascript-tetris-in-15-kb">JavaScript Tetris in 1.5 kB</h1>
 (???) p><img src="/images/projects/jstetris.png" alt="jstetris.html"></p>
 (???) h2>Introduction</h2>
 (???) p><em>jstetris.html</em> is an attempt to write Tetris in JavaScript and also an exercise in size coding.
 (???) /p>
 (???) p>Around the time (2004) it was probably the most performant Tetris in JavaScript available.</p>
 (???) p>
 (???) a href="/games/javascript-tetris-1.5kb/jstetris.html" class="button">Play it!</a>
 (???) a href="#source-code" class="button">Source code</a>
 (???) /p>
 (???) !-- TODO dl class="compact">
 (???) dt><kbd>▼</kbd> <kbd>I</kbd></dt><dd>Rotate</dd>
 (???) dt><kbd>▲</kbd> <kbd>K</kbd></dt><dd>Down</dd>
 (???) dt><kbd>◀</kbd></dt><dd>Rotate</dd>
 (???) dt><kbd> SPACE </kbd></dt><dd>Drop</dd>
 (???) dt><kbd>▲</kbd></dt><dd>Rotate</dd>
 (???) /dl -->
 (???) h3>Controls</h3>
 (???) p>
 (???) se cursor keys <kbd>▲</kbd> <kbd>▶</kbd> <kbd>▼</kbd> <kbd>◀</kbd> <kbd> SPACE </kbd> or 
 (???) <kbd>I</kbd> <kbd>J</kbd> <kbd>K</kbd> <kbd>L</kbd> <kbd>M</kbd> <kbd> SPACE </kbd> to control the game.
 (???) /p>
 (???) h2>About performance</h2>
 (???) p>
 (???) ther versions used absolute positioned images or <code>div</code>s to make up the blocks. 
 (???) sing a <code>table</code> with CSS-styled cell borders as a grid seemed logical.
 (???) /p>
 (???) p>
 (IMG)  tried different ways of accessing the table cells:
 (???) /p>
 (???) ul><!-- TODO show <meter> with timing for each method -->
 (???) li><code>getElementsByTagName('td')</code> (slow!)</li>
 (???) li><code>nextSibling</code></li>
 (???) li><code>table.rows[y].cells[x]</code></li>
 (???) li><code>childNodes</code></li>
 (???) /ul>
 (???) p>We're talking 30-40 <em>milli</em>seconds here BTW, not <em>micro</em>seconds (remember, 2004) to iterate
 (???) hrough the cells. Accessing it by <code>table.rows[y].cells[x]</code>
 (???) as almost as fast as <code>nextSibling</code> but more convenient in terms of code-size and readability :-)</p>
 (???) p>The same is true for using table methods <code>insertRow</code> and <code>deleteRow</code>. Less code and more speed than moving the cells individually.</p>
 (???) h2>About size</h2>
 (???) p>Nowadays you can bring it down to 1 KB or even 512 bytes, but I did not want to give up on the scoring system, preview and VIM-bindings :-) Another time maybe!</p>
 (???) !-- TODO template "includefile" "/games/tetris.html" -->
 (???) h2 id="source-code">The code</h2>
 (???) p>The code is 45 lines and ofcourse <del>a great mess</del><ins>obfuscated</ins> but pretty readable if you beautify it.</p>     
 (???) pre data-lang="JavaScript">
 (???) code>&lt;title&gt;1½ kB Tetris&lt;/title&gt;&lt;style&gt;table{border:4px groove #6b0;font-size:9}td{width:1em;border:solid #fff}pre{margin:9;float:left}&lt;/style&gt;&lt;body onkeydown=k(event)&gt;&lt;pre id=s&gt;&lt;/pre&gt;&lt;table id=t cellspacing=0&gt;&lt;/table&gt;&lt;script&gt;var d=document,W=10,H=25,s=l=0,Y,t</code>
 (???) code>function a(){for(r=B.insertRow(0),x=W;x--;)r.insertCell(0).appendChild(d.createTextNode('Â '))}</code>
 (???) code>function T(b,R,a){for(i=4;i--;){q='defgaeimdefgaeimdefjaeibdhijibfjdhefaeijhifjabfjeifjeifjeifjeifjheifaefjheifaefjdeifaeifheijebfjdeijeibfdeijeibf'.charCodeAt(b*16+R*4+i)-96</code>
 (???) code>a(q%4,q&gt;&gt;2)}}function D(c,Y,b,r){T(b,r,function(x,y){p=' #'+(c?'0ff00f808'.substr(b,3):'fff')</code>
 (???) code>v=S[Y+y].cells[X+x]</code>
 (???) code>o=v.style</code>
 (???) code>o.background=p</code>
 (???) code>o.border=(c?'outset':'solid')+p</code>
 (???) code>v.s=c</code>
 (???) code>})}function M(O,P,R){</code>
 (???) code>D(0,Y,b,r)</code>
 (???) code>c=4</code>
 (???) code>T(b,R,function(x,y){x+=X+O</code>
 (???) code>y+=Y+P</code>
 (???) code>if(x&lt;0||x&gt;=W||y&gt;=H||S[y].cells[x].s)c=0})</code>
 (???) code>if(c){X+=O</code>
 (???) code>Y+=P</code>
 (???) code>r=R}D(1,Y,b,r)</code>
 (???) code>return c}function C(){X=3</code>
 (???) code>D(0,-1,n,0)</code>
 (???) code>for(p=0,y=Y;y&lt;H;y++){for(f=0,x=W;x--;)f|=!S[y].cells[x].s</code>
 (???) code>if(!f){B.deleteRow(y)</code>
 (???) code>a()</code>
 (???) code>p++}}d.getElementById('s').innerHTML='Score: '+(s+=9&lt;&lt;p)+'\nLines: '+(l+=p)+'\n\n© MMIV Joris Zwart'</code>
 (???) code>clearInterval(t)</code>
 (???) code>t=setInterval(F,650-l)</code>
 (???) code>b=n</code>
 (???) code>n=new Date()%7</code>
 (???) code>D(1,-1,n,0)</code>
 (???) code>Y=1</code>
 (???) code>r=0</code>
 (???) code>if(!M(0,1,r)){clearInterval(t)</code>
 (???) code>alert(':-(')}}function F(){if(!M(0,1,r))C()}function k(e){switch(e.which||event.keyCode){case 74:case 37:M(-1,0,r)</code>
 (???) code>break</code>
 (???) code>case 75:case 38:M(0,0,(r+1)%4)</code>
 (???) code>break</code>
 (???) code>case 76:case 39:M(1,0,r)</code>
 (???) code>break</code>
 (???) code>case 32:clearInterval(t)</code>
 (???) code>t=setInterval(F,9)</code>
 (???) code>case 73:case 40:case 77:F()}}B=d.getElementById('t')</code>
 (???) code>n=new Date()%7</code>
 (???) code>S=B.rows</code>
 (???) code>for(y=H;y--;)a()</code>
 (???) code>C()&lt;/script&gt;</code>
 (???) /pre>
 (???) !-- TODO move technical tags to general tags -->
 (???) aside>
 (???) dl>
 (???) dt>Where</dt>
 (???) dd><a href="/">joriszwart.nl</a></dd>
 (???) dt>When</dt>
 (???) dd>2004</dd>
 (???) dt>Technical</dt>
 (???) dd>JavaScript</dd>
 (???) dt>Url</dt>
 (???) dd>/games/javascript-tetris-1.5kb/jstetris.html</dd>
 (???) /dl>
 (???) /aside>
 (???)         
 (???)         <div>      
 (???)           <time datetime="2004-12-21 02:41:05 &#43;0000 &#43;0000">Tue, 21 Dec 2004 02:41:05 &#43;0000</time>
 (???)         </div>
 (???)         
 (???)      </article>
 (???)    <div class="prevnext" id="prevnext">
 (???)        <a href="/games/sirtet" rel="prev">
 (???)            <strong>previous</strong><br>
 (???)            Sirtet
 (???)        </a>
 (???)        <a href="/games/esnextris" rel="next">
 (???)            <strong>next</strong><br>
 (???)            ESNextTris
 (???)        </a>
 (???)    </div>
 (???)      <section>
 (???)      
 (???)        <h2>Related</h2>
 (???)    <div class="gallery">
 (???)      <a href="/talks/tetris4life">
 (???)       <figure>
 (???)         <img src="/talks/tetris4life.svg" alt="Semi generic tetris logo inspired by the Elm logo" loading="lazy">
 (???)          <figcaption>[Talk] Tetris4life</figcaption>
 (???)        </figure>
 (???)      </a>
 (???)      <a href="/math/fixed-point">
 (???)       <figure>
 (???)         <img src="/images/bits.svg" alt="Bits" loading="lazy">
 (???)          <figcaption>Fixed point explanatorial</figcaption>
 (???)        </figure>
 (???)      </a>
 (???)      <a href="/articles/pico-search-50-lines">
 (???)       <figure>
 (???)         <img src="/img/fallback.svg" alt="" loading="lazy">        
 (???)          <figcaption>PicoSearch - TF-IDF in 50 lines</figcaption>
 (???)        </figure>
 (???)      </a>
 (???)      <a href="/articles/minimalistic-svg-library">
 (???)       <figure>
 (???)         <img src="/images/icons/svg-logo-v.svg" alt="SVG Logo" loading="lazy">
 (???)          <figcaption>Minimalistic SVG library</figcaption>
 (???)        </figure>
 (???)      </a>
 (???)      <a href="/graphics/simple-svg-javascript">
 (???)       <figure>
 (???)         <img src="/images/icons/svg-logo-v.svg" alt="W3 SVG Logo" loading="lazy">
 (???)          <figcaption>Creating SVG from JavaScript</figcaption>
 (???)        </figure>
 (???)      </a>
 (???)      <a href="/c64/tetris">
 (???)       <figure>
 (???)         <img src="/c64/tetris/screen09-wip.png" alt="Tetris screenshot WIP" loading="lazy">
 (???)          <figcaption>Tetris for Commodore 64</figcaption>
 (???)        </figure>
 (???)      </a>
 (???)      <a href="/projects/hacker-news">
 (???)       <figure>
 (???)         <img src="/hn/hn.svg" alt="Hacker news logo" loading="lazy">
 (???)          <figcaption>Hacker News Client</figcaption>
 (???)        </figure>
 (???)      </a>
 (???)      <a href="/c64/tetris-inner-loop-6510">
 (???)       <figure>
 (???)         <img src="/articles/tetris-inner-loop-6510/tetris-innerloop.png" alt="Tetris Block" loading="lazy">
 (???)          <figcaption>Tetris inner loop MOS6510 / C=64</figcaption>
 (???)        </figure>
 (???)      </a>
 (???)      <a href="/c64/hextris">
 (???)       <figure>
 (???)         <img src="/c64/hextris-wip.png" alt="Hextris screenshot WIP" loading="lazy">
 (???)          <figcaption>Hextris C=64</figcaption>
 (???)        </figure>
 (???)      </a>
 (???)      <a href="/c64/c64js">
 (???)       <figure>
 (???)         <img src="/img/fallback.svg" alt="" loading="lazy">        
 (???)          <figcaption>Commodore 64 emulator</figcaption>
 (???)        </figure>
 (???)      </a>
 (???)    </div>
 (???)      </section>
 (???)    </main>
 (???)        <footer id="footer">
 (???)      <nav>
 (???)        <ul>
 (???)          
 (???)          <li><a href="/search">Search</a></li>
 (???)          <li><a href="/categories">Categories</a></li>
 (???)          <li><a href="/tags">Tags</a></li>
 (???)          
 (???)        </ul>
 (???)      </nav>
 (???)      <div>
 (???)        <a href="/"><img src="/images/joriszwart-logo.png" alt="" width="265" height="34"></a>
 (???)      </div>
 (???)    </footer>
 (???)  </body>
 (???) /html>