Program a 2048 AI using an existing Framework

17

5

EDIT : Recently, my question has been proposed as a duplicate of 2048 Bot Challenge. I would like to stress that this question is different from that question, and will require answers to be thought of differently than that question. 2048 Bot Challenge asked the user to create a bot, and it would be run for an hour, with the highest score being the user's score. Additionally, it had a limit of 555 bytes. My challenge runs the code much less frequently, only 3 times. Your score is calculated by using the average score of those three times and dividing by the character length of your golfed code. My question encourages entries to be "smarter," and not try and get the highest score by brute force.

-

EDIT: The get method was changed to getTile, to avoid confliction with the JS keyword get. Additionally, a high score section was added.

Recently, I created a site that allows the popular game 2048 to be controlled using JavaScript. My site is linked here:

http://thatcoolidea.com/2048

How:

An Ace Editor is located above the board. You place code in it, which is run once every 250 ms, or 4 times per second. This is called a cycle.

Use the following methods to control the board. You can't use the arrow keys.

up();            //move up
down();          //move down
left();          //move left
right();         //move right

move(integer);   //integer is a direction. 0:up,1:right,2:down,3:left

getTile(y,x);        //gets the value of the tile in position y,x on the board. See diagram

Map of board for the get method.

The following variables are defined for your convenience:

eother        //boolean, alternates every cycle
frozen        //integer, counts how many cycles the board has remained stationary
lastDir       //integer, indicates the last direction that was tried to move in
              //uses same format as the move method above.
startup       //boolean, will always be true when the game first starts
              //you can change it as you wish
a
b             //a b and c are all persistant variables, they do not change each cycle
c             //any other variables defined in the cycle will be reset every time

Rules:

  • No Randomness, you must use logic. (Yes, I know the example code uses random.)
  • No hooking into the game functions or cheating in other ways
  • Generally, try to only call one move method per cycle. It is OK if you use more, but it screws with the animation
  • The board must start in a random state, no modification of pre-game state
  • You must provide both the uncompressed and golfed version of the code in your post.
  • You must provide a link to the site that already loads the uncompressed version of your code, served via PasteBin (For example, ...thatcoolidea.com/2048?i=pH18GWtu loads the example code.)

Scoring:

  • Your code will be scored by me.
  • Part A of your score is an average of 3 runs of the code, rounded down.
  • Part B of your score is the character length of your golfed code.
  • Your final score is Part A divided by Part B

The winner will have their code immortalized as the example code on the site, if they choose, and acknowledged in a comment in the code.

Good luck! Hope you enjoy the challenge.

Current High Score 225.22 - Freezer - user3217109

Sam Weaver

Posted 2014-09-24T23:39:12.653

Reputation: 453

10The fact that you've written a framework for 2048 is pretty awesome and very convenient for this type of challenge, but I don't see how it actually affects any of the strategies already found in our existing 2048 AI challenge. – Martin Ender – 2014-09-24T23:42:35.293

3Well I would say that mine Is different, simply because you are required to use one code base which will be the same each execution. This is much more user friendly and I don't think it would constitute a duplicate. – Sam Weaver – 2014-09-25T00:17:00.513

2The other question looks pretty dead. There were only four answers and a time limit of an hour, so I'm going to answer because this looks really cool. – krs013 – 2014-09-25T14:22:40.790

@samweaver add a note to the top of your question to explain why answers from the other question wouldnt be valid/competitive for your question, and then create a meta post for scrutiny. – rdans – 2014-09-25T20:36:29.240

If you cant do that, you will likely need to change your challenge in order to get it re-opened e.g. rules/scoring/restrictions – rdans – 2014-09-25T21:13:18.737

Clarified. Please enlighten me to create a meta post, I am not aware of the proper procedure. I am new to the SO scene. – Sam Weaver – 2014-09-26T22:24:38.883

@SamWeaver each SO site has an accompanying meta site in which users can ask about and discuss site policy. You can ask a question here and you may want to look at a few other meta questions to get a feel for what they're like. From what I've seen, you can directly reference your question in your meta question.

– krs013 – 2014-09-26T22:30:56.743

I always remember this SO post each time there is a 2048 bot challenge, because his solution is so cool, achieving tile 8192 everytime on 100 runs.

– justhalf – 2014-10-01T01:26:06.817

That's very very nice. – Sam Weaver – 2014-10-02T02:16:19.383

I will get to grading all the new submissions tomorrow. Sorry for the delay. :P – Sam Weaver – 2014-10-02T02:16:39.457

Answers

6

Sinker/Shaker, 65 bytes

Here's mine. It's as blind and simple as they come.

if(startup){startup=false;a=0}b=(a++)%4;move(frozen>2?0:b==0?2:b)

Uncompressed(ish)...

if(startup){startup=false;a=0;}
b=(a++)%4;
move(frozen>2?0:b==0?2:b)

All it does is repeats down, right, down, left, etc. and hits up once if it gets stuck. It doesn't always do very well, but it'll occasionally get 512s. My high score during testing was 7520.

krs013

Posted 2014-09-24T23:39:12.653

Reputation: 201

I am beginning the scoring process now! Thanks for the first entry! – Sam Weaver – 2014-09-26T22:25:04.103

Final Score: 67.6! Run 1: 3980 Run 2: 4080 Run 3: 5128

I really liked this, I didn't envision you could get such a high score with such a small bot. – Sam Weaver – 2014-09-26T22:32:24.450

Thanks for setting it up! I think it's pretty cool. It's sad that people have reacted this way so far. SO users tend to be very negative towards duplicate questions, usually for good reasons. – krs013 – 2014-09-26T22:32:35.257

Why thank you! I appreciate the support! This project originated from when a friend and I stayed late at work one night and wanted to see who could make the better bot. I searched through the code, but I couldn't find a way to do it well. I built this with the helper methods to make it so much easier! – Sam Weaver – 2014-09-26T22:34:58.903

3

Traffic light - 23 21 bytes

move(frozen&2|eother)

This is the link.

This will move alternatingly up and right, except when the board has remained stationary for the last two moves, in which case it will move down and left respectively.

My original, functionally equivalent submission was 23 bytes long and scored 182.72:

move((frozen&2)+eother)

me and my cat

Posted 2014-09-24T23:39:12.653

Reputation: 1 107

This is pretty much the same thing I do when I play quickly without really looking at the board. – me and my cat – 2014-09-30T05:39:19.860

Excellent work. Run 1: 2208 Run 2: 1216 Run 3: 2336 23 bytes Final Score: 182.72 – Sam Weaver – 2014-09-30T23:16:16.210

2

Whirlpool - 37 21 17 bytes - Score: 211.22

I decided to go with a "less is more" approach. My code is a simple design that tries to go up, right, down, left... I will be working on a learning AI to see a more optimal way to approach the puzzle.

a=a|0;move(a++%4)

Optimizer helped to shorten a's initialization.

Sam helped to shorten a's initialization, removed var.

Ungolfed?

var a=a|0;
a++;
move(a%4);

My top score with this AI is 5120.

Freezer - 12 bytes - Score: 225.22

This bot has move priority. It attempts to go up. If it can' go up, it goes right. If it can't go right, it does down. If it can't go down it goes left.

move(frozen)

James Bond Explanation

The encrypted code decrypts to say:

HTMLActuator.prototype.updateScore=function (score) {score*=9989800000;
  this.clearContainer(this.scoreContainer);

  var difference = score - this.score;
  this.score = score;

  this.scoreContainer.textContent = this.score;

  if (difference > 0) {
    var addition = document.createElement("div");
    addition.classList.add("score-addition");
    addition.textContent = "+" + difference;

    this.scoreContainer.appendChild(addition);
  }
}

Optimizer should have golfed his decrypted code. This could have been #Optimized.

Zylviij

Posted 2014-09-24T23:39:12.653

Reputation: 390

You have to actually define a too. So that should be added in the code length. – Optimizer – 2014-09-29T21:54:50.547

Unfortunately, the backend preserves variables through resets, so you can define/initialize a once and forget about it, but if you close the tab/window and come back to it, I don't think it will work anymore. This is why I had to add the if(startup) bit on mine. – krs013 – 2014-09-29T22:11:24.733

1you can use var a=a|0;move(a++%4) - 21 bytes – Optimizer – 2014-09-30T15:26:10.840

Thank you! I have never used javascript before, so I will make mistakes like that... – Zylviij – 2014-09-30T15:30:48.903

Actually, A does not need to be defined. A is defined in the backend, so you can reference it using just a without doing var a – Sam Weaver – 2014-09-30T23:18:15.120

In fact, in my browser, the code won't run unless I remove the var declaration. Consider your code 4 bytes less. :) – Sam Weaver – 2014-09-30T23:19:58.903

Whirlpool: Run 1: 3144 Run 2: 3132 Run 3: 4496 17 bytes Final Score: 211.22 – Sam Weaver – 2014-09-30T23:23:06.310

Freezer: Run 1: 1644 Run 2: 3628 Run 3: 2836 12 bytes Final Score: 225.22 – Sam Weaver – 2014-09-30T23:29:09.213

Well done! I would never have thought of the idea for Freezer. I apologize about the issue with get, I forgot to update this page after it was changed to getTile. I realize it is more bytes, but it is necessary to avoid conflicting with the JS keyword get. Original Post updated. – Sam Weaver – 2014-09-30T23:30:20.007

I should be less surprised that small code gets such higher scores. @Optimizer I'm tempted to steal that a=a|0; init, it's pretty slick. – krs013 – 2014-10-01T01:35:42.737

I can't get whirlpool to work - it appears to be moving upwards every time. – isaacg – 2014-10-01T07:59:10.280

1

Hanger - 20 bytes

Official score: 224.87 - 2nd place by 0.35 points

This bot uses the down, left, down, right approach, but with the unusual feature that it will never move up. I'm not sure how to score cases where it hangs and does not complete, or whether the fact that that occurs renders it illegal. Here it is, though:

b=b|0;move(b++%4||2)
OR
move(startup++%4||2)

Initialization pattern thanks to @Optimizer.

In my 3 test runs, it scored 4284, 6352 and 4232, for an average of 4956. I will update when the official test is run.


Alternate version which gets out of hangs (27 bytes):

b=b|0;move(b++%4||b%997&&2)

isaacg

Posted 2014-09-24T23:39:12.653

Reputation: 39 268

No need to leave a hang, the score will just be measured there as if the game was over. – Sam Weaver – 2014-10-02T02:15:51.170

How does the last one get out of hangs? – krs013 – 2014-10-02T03:51:46.120

@krs013 The last one will move up once every 4*997 cycles, so if up is the only way to move, it will move up. – isaacg – 2014-10-02T10:25:00.750

Gotcha. I wondered if it was something like that; I just didn't wait long enough, I guess. – krs013 – 2014-10-02T16:01:14.197

Final Score: 224.87, great job! – Sam Weaver – 2014-10-03T00:15:59.383

@SamWeaver Thanks! What were the individual scores, if you have them? – isaacg – 2014-10-03T00:29:01.197

3384, 6868, and 3240. – Sam Weaver – 2014-10-05T14:27:59.680