Threes!1k

JS1k entry

by evan

HTML

<canvas id="c"></canvas>
		<script>
			var a = document.getElementsByTagName('canvas')[0];
			var b = document.body;
      var d = function(e){ return function(){ e.parentNode.removeChild(e); }; }(a);
      // unprefix some popular vendor prefixed things (but stick to their original name)
      var AudioContext =
        window.AudioContext ||
        window.webkitAudioContext;
      var requestAnimationFrame =
        window.requestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function(f){ setTimeout(f, 1000/30); };
      // stretch canvas to screen size (once, wont onresize!)
      a.style.width = (a.width = innerWidth) + 'px';
      a.style.height = (a.height = innerHeight) + 'px';

      var c = a.getContext('2d');
		</script>

CSS

html, body { margin: 0; padding: 0; border: 0; }
      #c { display: block; } /* kill scrollbars from hell */

JavaScript

// Styles to be set once
b.bgColor="#eee";
c.font='17pt cursive';
c.textAlign="center";

// Some variables I'll want to use later.
E='';

// canvas drawing methods
S='fillStyle';
c.T=c.fillText;
L=function (v,x,y) {
    // Set the fill color for rectangle using the current value
    // 0,1,2 are listed, otherwise it falls through to W which is white
    c[S]=[X,Z,Y][v] || W;
    c.fillRect(x,y,40,45);
};

// Colors I use a few times.
V='#000';    // Black
W='#FFF';    // White
X='#DDD';    // Dark gray
Y='#F68';    // Pink
Z='#7CF';    // Blue

M=Math;
R=M.random;

// Highest starts out at 3
H = 3;

// Pick an upcoming (next) tile
U = G();

// get a tile value of less than or equal to the highest.
// We also use this a lot for drawing random numbers.
// A value for the first argument triggers alternate behavior.
function G(a) {
    // Draw a number up to 3.
    g = ~~(R()*3)+1;
    
    // If the number is 3, and the highest number is lower than 3,
    // flip a (weighted) coin to decide whether we should double the value.
    // This gives us increasingly slim opportunities to spawn high value tiles.
    // I haven't spent a TON of time balance-testing this. Seems fairly OK.
    while (g > 2 && g < H && R() < .4) {
        g*=2;
    }
    return a ? g-2 : g;
}

// rotate the field t through 4 rotations and squish on the r'th rotation (1,2,3,4)
// returns how many squishes it did OR how many were possible
// r: which rotation to squish on, or undefined to run a test on all directions
// Also draws the field- probably wastes CPU, but saves several bytes for another loop
function O(r) {
    
    // reset the flag that tracks whether we performed any squishes
    // To save bytes we're not going to return s at the end, just access it globally
    p=s=0;
    
    // rotate through 4 sides
    for (k=1; k<5; k++) {
        
        // Do the squish calculations before the r'th rotation-
        // or always if we're not saving squishes
        if (k==r || !r) {
      ...