[Question]
  [
We have been [cloning](https://codegolf.stackexchange.com/questions/24134/create-a-simple-2048-game-clone) 2048, [analyzing](https://codegolf.stackexchange.com/questions/24589/would-this-number-make-a-good-2048-combo) 2048, but why haven't we played it yet? Write a 555 byte javascript snippet to play 2048 automatically, the best score after an hour will count (see scoring below).
# Setup:
Goto [2048](http://gabrielecirulli.github.io/2048/) and run:
```
 a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
```
`a` is the object to control the game.
# Rules:
After setup you may run 555 bytes of javascript from the console to control the game. The source code of the game can be [found here](http://gabrielecirulli.github.io/2048/js/game_manager.js) (including comments).
* It may only do things which are possible for the user:
	+ `a.move(n)`
	to trigger a key action in any of the 4 directions.
		- 0: up, 1: right, 2: down, 3: left
	+ `a.restart()`
	to restart the game. Restarting is allowed in the middle of the game.
* Information about the state of the game can be found in `a.grid.cells`. This information is read-only
* Hooking into any of the functions is allowed, altering their behaviour in any way is not (or changing any other data)
* Moving is allowed only once every 250ms
# Example
Just a very simple example to start from. Without comments and enters **181 bytes**.
```
//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; b(); };
//number of move fails
mfs = 0;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  a.move(Math.floor(4 * Math.random()));
  m || mfs++;
  //restart after 10 moves failed
  10 < mfs && (mfs = 0, a.restart());
}, 250);
```
# Scoring and results
I will be running the snippets for one hour straight and the best score will count. Indeed there is a chance that `randombot` above will win that way, but 1 hour should be enough to beat it:
* **King** `Bottomstacker VII`: **9912**
* *Queen* `Bottomstacker V`: **9216**
* *Prince* `Bottomstacker II`: **7520**
* *Lord* `Bottom and Right`: **6308**
* *Peasant* `Randombot`: **1413**
* ~~`Bottomstacker IV`: **12320**~~ *Disqualified for making two moves in one interval (within 250ms)*
# FAQ
* Why is this challenge not language agnostic through the terminal?
	+ For the simple reason that it is more fun like this. Watching a game play itself graphically is simply a lot more mesmerizing than seeing a console spit out numbers. Even knowing no javascript you should be able to join into this challenge as it isn't about language features primarily (just use [this tool](http://closure-compiler.appspot.com/home) to minimize the code)
  
[Answer]
I can't code javascript, so I stole your answer.
```
//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; b(); };
//number of move fails
mfs = 0;
c=1;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  a.move(c)
  c++
  if (c>3) {c=1}
  m || mfs++;
  //restart after 10 moves failed
  10 < mfs && (mfs = 0, a.restart());
}, 250);
```
It uses the strategy I also use.
EDIT: Nice, it just beat your score after about 5 minutes on my machine :D
EDIT:
Forgot to move down twice instead of just once, this is the code you should use:
```
a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; b(); };
//number of move fails
mfs = 0;
c=1;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  if (c<=3) {n=c}
  else {n=2}
  a.move(n)
  c++
  if (c>4) {c=1} 
  m || mfs++;
  //restart after 10 moves failed
  10 < mfs && (mfs = 0, a.restart());
}, 250);
```
Also, there's a bug in it that it restarts when it's not needed, but I'm not sure how to fix this.
EDIT: It currently has a highscore of 3116 (after 3 minutes). I think it's safe to say this algoritm is better than just doing random moves.
EDIT Newer version:
```
a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; mfs=0; b(); };
//number of move fails
mfs = 0;
c=1;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  if (c<=3) {n=c}
  else {n=2}
  a.move(n)
  c++
  if (c>4) {c=1} 
  m || mfs++;
  //up after 5 moves
  5 < mfs && (a.move(0));
  //restart after 10 moves failed
  10 < mfs && (mfs = 0, a.restart());
}, 250);
```
EDIT: Another new version, this one moves down directly after moving up.
```
a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; mfs=0; b(); };
//number of move fails
mfs = 0;
c=1;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  if (c<=3) {n=c}
  else {n=2}
  a.move(n)
  c++
  if (c>4) {c=1} 
  m || mfs++;
  //up after 5 moves
  5 < mfs && (a.move(0), c=4);
  //restart after 10 moves failed
  10 < mfs && (mfs = 0, a.restart());
}, 250);
```
EDIT: Update: it just broke my personal record with a pretty crazy score of 12596.
EDIT: Hey, I'm bottomstacker :D
Also:
```
b=a.addRandomTile.bind(a);m=!1;a.addRandomTile=function(){m=!0;mfs=0;b()};mfs=0;c=1;setInterval(function(){m=!1;n=3>=c?c:2;a.move(n);c++;4<c&&(c=1);m||mfs++;5<mfs&&(a.move(0),c=4);10<mfs&&(mfs=0,a.restart())},250);
```
(Not actually a change, just compressed.)
5th time's a charm? Not sure. Anyways:
```
//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; mfs=0; b(); };
//number of move fails
mfs = 0;
c=1;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  if (c<=3) {n=c}
  else {n=2}
  a.move(n)
  c++
  if (c>4) {c=1} 
  if (c==0) {c=4}
  m || mfs++;
  //up after 5 moves
  5 < mfs && (c=0);
  //restart after 10 moves failed
  10 < mfs && (mfs = 0, a.restart());
}, 250);
```
and:
```
b=a.addRandomTile.bind(a);m=!1;a.addRandomTile=function(){m=!0;mfs=0;b()};mfs=0;c=1;setInterval(function(){m=!1;n=3>=c?c:2;a.move(n);c++;4<c&&(c=1);0==c&&(c=4);m||mfs++;5<mfs&&(c=0);10<mfs&&(mfs=0,a.restart())},250);
```
Another new version:
```
a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
//bind into new tile function and change m(ove) variable when a tile was moved
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() { m = !0; mfs=0; b(); };
//number of move fails
mfs = 0;
c=1;
setInterval(function() {
  //set global moved tracking variable to false
  m = !1;
  if (c<=3) {n=c}
  else {n=2}
  a.move(n)
  c++
  if (c>4) {c=1} 
  if (c==0) {c=4}
  m || mfs++;
  //up after 5 moves
  5 < mfs && (c=0);
  //Found this in the source, as the criteria for a gameover. Might as well reset then ;)
  if (!a.movesAvailable()) {
      a.restart()
  }
}, 250);
```
and:
```
a=new GameManager(4,KeyboardInputManager,HTMLActuator,LocalStorageManager);b=a.addRandomTile.bind(a);m=!1;a.addRandomTile=function(){m=!0;mfs=0;b()};mfs=0;c=1;setInterval(function(){m=!1;n=3>=c?c:2;a.move(n);c++;4<c&&(c=1);0==c&&(c=4);m||mfs++;5<mfs&&(c=0);a.movesAvailable()||a.restart()},250);
```
(I hope it's not too much of a problem that this continues behind the gameover screen? I think you could add an `a.over=0` somewhere that gets executed often. I'll figure it out someday.)
EDIT (again):
I dropped the standard gameover way and reverted to the old way of doing things. I'm now testing out an addition that'll always merge if there are 2 tiles of 16 or more together:
```
a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
b = a.addRandomTile.bind(a);
m = !1;
a.addRandomTile = function() {
  m = !0;
  mfs = 0;
  b();
};
mfs = 0;
c = 1;
setInterval(function() {
  m = !1;
  l = 8;
  for (x = 0;x < 4;x++) {
    for (y = 0;y < 4;y++) {
      t1 = a.grid.cellContent({x:x, y:y});
      t2 = a.grid.cellContent({x:x, y:y + 1});
      t3 = a.grid.cellContent({x:x + 1, y:y + 1});
      if (t1 & t2) {
        if (t1.value == t2.value) {
          if (t1.value > l) {
            l = t1.value;
            c = 2;
          }
        }
        if (t1 & t3) {
          if (t1.value == t2.value) {
            if (t1.value > l) {
              l = t1.value;
            }
          }
        }
      }
    }
  }
  if (c <= 3) {
    n = c;
  } else {
    n = 2;
  }
  a.move(n);
  c++;
  if (c > 4) {
    c = 1;
  }
  if (c == 0) {
    c = 4;
  }
  m || mfs++;
  5 < mfs && (c = 0);
  10 < mfs && (mfs = 0, a.restart());
}, 250);
```
[Answer]
# Right and Down bot: 345 bytes
Short version
```
b=a.addRandomTile.bind(a);m=!1;t=250;d=!0;a.addRandomTile=function(){m=!0;b();d&&setTimeout(c,t)};c=function(){d=!1;a.move(2);setTimeout(function(){m=!1;d=!0;a.move(1);m||setTimeout(function(){a.move(0);m?a.grid.cells[3][0]&&a.grid.cells[3][3]&&setTimeout(function(){a.move(1)},t):setTimeout(function(){a.move(3);m||a.restart()},t)},t)},t)};c();
```
Long version
```
a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
b = a.addRandomTile.bind(a);
m = !1;
t = 250;
d = !0;
a.addRandomTile = function() {
  m = !0;
  b();
  d && setTimeout(c, t);
};
c = function() {
  d = !1;
  a.move(2);
  setTimeout(function() {
    m = !1;
    d = !0;
    a.move(1);
    m || setTimeout(function() {
      a.move(0);
      m ? a.grid.cells[3][0] && a.grid.cells[3][3] && setTimeout(function() {
        a.move(1);
      }, t) : setTimeout(function() {
        a.move(3);
        m || a.restart();
      }, t);
    }, t);
  }, t);
};
c();
```
# In words
Move down, then right, if you can't move, move up (or if you can't, move left), if both the top right and bottom right corner is filled, move right otherwise start over.
# Current highscore
My own best score was 7668, but that was run at far greater speed than `t=250` (and thus indirectly longer than an hour).
[Answer]
Somehow I ran across this older contest this morning, and since I love 2048, I love AI, and JS is one of the few languages I currently know well, I figured I'd give it a shot.
# GreedyBot (~~607~~ 536 bytes)
Short version:
```
C=function(x,y){return a.grid.cellContent({x:x,y:y})},h=[[1,3,2,0],[2,1,3,0]],V='value',A='addRandomTile';a=new GameManager(4,KeyboardInputManager,HTMLActuator,LocalStorageManager);b=a[A].bind(a);m=!1;f=d=X=Y=0;a[A]=function(){m=!0;f=0;b()};setInterval(function(){m=!1;for(var c=X=Y=0;4>c;c++)for(var e=0;4>e;e++)if(u=C(c,e),!!u){for(q=e+1;4>q;){v=C(c,q);if(!!v){u[V]==v[V]&&(Y+=u[V]);break}q++}for(q=c+1;4>q;){v=C(q,e);if(!!v){u[V]==v[V]&&(X+=u[V]);break}q++}}f<4&&a.move(h[X>Y+4?0:1][f]);m&&(f=0);m||f++;15<f&&(f=0,a.restart())},250);
```
Long version (outdated):
```
a = new GameManager(4, KeyboardInputManager, HTMLActuator,    LocalStorageManager);
b = a.addRandomTile.bind(a);
m = !1;
f = d = X = Y = 0;
a.addRandomTile = function() { m = !0; f = 0; b(); };
setInterval(function() {
    m = !1;
    X = Y = 0;
    for(var x=0;x<4;x++) {
        for(var y=0;y<4;y++) {
            u = a.grid.cellContent({x:x, y:y});
            if(u==null){continue;}
            q = y+1;
            while(q < 4) {
                v = a.grid.cellContent({x:x,y:q});
                if(v!=null){
                    if(u.value==v.value){
                        Y+=u.value;
                    }
                    break;
                }
                q++;
            }
            q = x+1;
            while(q < 4) {
                v = a.grid.cellContent({x:q,y:y});
                if(v!=null){
                    if(u.value==v.value){
                        X+=u.value;
                    }
                    break;
                }
                q++;
            }
        }
    }
    if(X>=Y){
        if(f==0)
            a.move(1);
        else if(f==1)
            a.move(3);
        else if(f==2)
            a.move(2);
        else if(f==3)
            a.move(0);
    } else {
        if(f==0)
            a.move(2);
        else if(f==1)
            a.move(0);
        else if(f==2)
            a.move(1);
        else if(f==3)
            a.move(3);
    }
    if(m)f=0;
    m || f++;
    if(15 < f) f=0,a.restart();
}, 250);
```
The longer version was not golfed at all (other than shrinking variable names), so it could be shortened quite a bit while still being readable. The shorter version was created using Closure Compiler (thanks for the link!), which ended up at 650. With some custom modifications on my part, I was able to shave off another ~~43~~ 114 bits.
Basically, it searches for through the grid for possible moves, and whenever it finds one, adds its value to either the horizontal or vertical total. After searching through every possible move, it determines which direction it should move, based on if the H or V total is higher, and the directions it has already tried. Right and Down are the first choices.
Looking back at this, I realize now that if either total is non-zero, the first attempt at sliding the tiles in that direction is guaranteed to succeed. Perhaps I could simplify the move-deciding section towards the end based on this.
I left this program running for an hour and ended up with a high score of `6080`. However, in one of the trial runs (pre-minification), it managed a high score of `6492`, only 128 behind my personal best of `6620`. Its logic could be greatly improved by having it move left-down occasionally, as the numbers tend to pile up like this:
```
 2  4  8 16
 4  8 16 32
 8 16 32 64
16 32 64 128
```
(**EDIT:** I left it running a while longer, and it managed some `7532` points. Darn, my program is smarter than me....)
One more interesting tidbit: in one of my glitched attempts at creating something useable, somehow it ended up so that anytime *any* two tiles were in the same row or column, they were combined. This led to interesting developments as the random 2s or 4s would repeatedly combine with the highest tile, doubling it every time. One time, it somehow managed to score over 11,000 in 15 seconds before I shut it off.... XD
Any suggestions for improvement are very welcome!
[Answer]
# Windshield Wipers: 454 bytes
Simply goes Right, Up, Left, Up... repeating (just like the wipers on a car) unless it gets jammed. If it gets jammed, it will attempt to turn off the wipers and turn them back on. Highest score I got in an hour was 12,156 -- However, most of the scores are somewhere between 3k - 7k.
It will output the score into the console after every attempt.
```
var move = !1;
var bad = 0;
var c = 0;
var b = a.addRandomTile.bind(a);
a.addRandomTile = function() {
    b();
    move=!0;
    bad=0;
}
setInterval(function() {
    if (!move) bad++;
    if (c>3) c=0;
    move = !1;
    if (c==3) {a.move(0);c++;}
    if (c==2) {a.move(3);c++;}
    if (c==1) {a.move(0);c++;}
    if (c==0) {a.move(1);c++;}
    if (bad>10) {a.move(2);}
    if (!a.movesAvailable()) {console.log("Score: "+a.score);a.restart();}
}, 250);
```
[Answer]
# UpAndLeftBot
As title suggests, moves up & left by stealing [David Mulder's work](https://codegolf.stackexchange.com/a/25229/11376) & swapping some numbers (I don't know jack about Javascript, so best I can do is this).
```
a = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
b = a.addRandomTile.bind(a);
m = !1;
t = 250;
d = !0;
a.addRandomTile = function() {
  m = !0;
  b();
  d && setTimeout(c, t);
};
c = function() {
  d = !1;
  a.move(0); // a.move(2)
  setTimeout(function() {
    m = !1;
    d = !0;
    a.move(3); // a.move(1)
    m || setTimeout(function() {
      a.move(2);  //a.move(0)
      m ? a.grid.cells[3][0] && a.grid.cells[3][3] && setTimeout(function() {
        a.move(3); // a.move(1)
      }, t) : setTimeout(function() {
        a.move(1);  // a.move(3)
        m || a.restart();
      }, t);
    }, t);
  }, t);
};
c();
```
]