Create a simple 2048 game clone

53

12

2048 is an incredibly fun and addictive game in which the goal is to create a tile with 2048 on it.

Here's a short description of the game:


Pressing an arrow key will slide all the blocks in the stage in that direction. For example, if x represents a block, and you pressed the up arrow in this case:

...x
.x..
..x.
xx..

Then the board would become

xxxx
.x..
....
....

Furthermore, the blocks are numbered, starting at 2. If two of the same numbered blocks are moved together, they will merge into the next number. For example, pressing "up" on this board:

.2..
..22
.2..
....

Would create this:

.422
....
....
....

And then after pressing "right," it would become ..44, and therefore pressing right again would create an "8" block, and so on.

Each turn, a new "2" block is created on a random open square. (It's actually not always a "2," but for simplicity let's keep it at that.) If there are no possible moves left (i.e., the board is full and you can't merge anything), the game is lost, and if a 2048 block is created, you win!


Your challenge is to recreate this game, golfed!

  • For edge-cases, such as pressing "right" on this board:

    ....
    .222
    ....
    ....
    

    you must merge the tiles closest to the edge of the arrow key pressed. For example, this would become ..24, because the second and third "2"s are the closest to the right edge.

  • If the player presses an invalid move (such as "up" on a board like 2.2. / .... / .... / ....), you must ignore the move.

  • Moves can be accepted in any way, such as clicking, arrow keys, ULRD, etc.

  • The tiles must all be the same shape—a "1024" tile should be the same size as a "2" tile.

  • The tiles must be separated in some way. For example, |1024| 2|1024|1024| is a valid example of a row (assuming that the tiles are squares), while 1024 210241024 is not.

  • You must output "you win" if the player creates a 2048 tile, or "you lose" if there are no valid moves left.

  • This is , so the shortest code in bytes will win!

Doorknob

Posted 2014-03-14T01:02:26.820

Reputation: 68 138

@Doorknob I'm pretty sure that 2048 doesn't quit upon obtaining a 2048 tile. Many of my friends have gotten a 4096 tile or even higher. So making this as close as possible to the original would remove that restriction. – mbomb007 – 2015-02-24T18:04:02.297

@Doorknob Do the cells only need to always have the same shape, or does the number of rows (in a text based answer) used by a cell have to equal the number of columns? The currently accepted answer only keeps them constant, but not "square".

– Adám – 2016-08-02T01:48:13.723

@Adám Huh, the challenge claims that the tiles have to be congruent squares but apparently I didn't actually enforce that rule. I guess I can't really invalidate nearly all the answers, so I suppose I have to go with the former. – Doorknob – 2016-08-02T06:50:24.950

@Doorknob In that case, you have a new winner ;-)

– Adám – 2016-08-02T07:03:36.630

Does outputting Colored squares count? @RohanRjhunjhunwala offered a no-deadline bounty on this (500 rep) for writing one in S.I.L.O.S, and an extra 250 with GUI. however, S.I.L.O.S only has rectangle/ellipse drawing. I could, however, draw different colored squares though. – Matthew Roh – 2017-03-23T09:56:11.593

Instead of accepting either rows of single characters (first five examples) and/or separated tiles (last one), why not assign ascending powers of two to individual characters to normalize the output? – millinon – 2014-03-14T03:41:16.903

@millinon Because it's supposed to be as similar as possible to the actual 2048 game (it would make the title meaningless), and it would remove some of the challenge. – Doorknob – 2014-03-14T03:50:06.833

1"If there are no possible merges left, the game is lost" Shouldn't there be an "and the board is full" in there somewhere? – Peter Taylor – 2014-03-14T08:25:27.890

does space suffice as a tile separator? – John Dvorak – 2014-03-14T10:41:08.053

If the starting board is a single 2, no merges are possible. Does that mean the task is to render a 4x4 square with a random 2 inside, and then the message "you lose"? – John Dvorak – 2014-03-14T10:48:57.303

@Peter s/merge/move/ :-P Edited – Doorknob – 2014-03-14T11:48:45.127

@Jan Yes, space is a valid separator. – Doorknob – 2014-03-14T11:49:07.517

5Funny how all your questons get a ton of votes, but not many answers. – TheDoctor – 2014-03-14T13:02:21.503

@Doorknob Actually it is always a 2 on a random position (i played it to see how it worked) but it can be a 4 when the random position already contains a 2. At least thats what it seemed to be. – Teun Pronk – 2014-03-14T13:22:42.323

@TheDoc I've been trying to post more interesting and difficult challenges; I'm beginning to feel more and more that challenges you can complete in only 5 minutes or so just aren't as fun. – Doorknob – 2014-03-14T14:58:28.380

@Teun Well, for simplicity let's just assume it can only be a 2, since we're still not sure of the exact details (what happens if a 2 appears on a 8? Are there any other factors? Etc) – Doorknob – 2014-03-14T14:59:40.670

@Doorknob probably find another cell :P but I agree.. My code is long enough already lol – Teun Pronk – 2014-03-14T15:00:25.693

@TeunPronk The source code says: var value = Math.random() < 0.9 ? 2 : 4;, so on any given new tile there is a 10% chance it will be 4. – The Guy with The Hat – 2014-03-14T15:01:12.160

Now its your fault I´ve been playing 2048 the whole weekend and today the productivity of our office has dropped to 0. – asr – 2014-03-17T10:09:27.760

hmm... will Bash strike back here... hmm... – None – 2014-04-06T10:43:06.973

Answers

7

APL (Dyalog APL), 153 150 167 156 155 151 bytes

'you ',{2048∊⍵:'win'
(z/∊n)[?+/z←0=∊n←⍵]←2
⎕←4↑¨⍕¨n
1∊(⍉2=⌿n),(2=/n),0=n:∇{⍵≡r←R⍣¯1⎕UCS{4↑⍺⍺t⎕R(1⌽∪¨t←2/¨⍺⍺2*⍳16)⍺⍺⍵~0}¨(R←↓⍉∘⌽⍣⎕)⍵:∇⍵⋄r}n
'lose'}4 4⍴0

Prompts for move; 0=Left, 1=Up 2=Right, 3=Down

Try it online!

Ungolfed, with whitespace

C ← ⎕UCS
'you ', {
    2048 ∊ ⍵: 'win'
    n ← ⍵
    z ← 0 = ∊n
    (z / ∊n)[? +/z] ← 2
    ⎕ ← 4 ↑¨ ⍕¨n
    1 ∊ (⍉ 2 =⌿ n) , (2 =/ n) , 0 = n: ∇ {
        R←↓⍉∘⌽⍣⎕
        r ← R⍣¯1 ⎕UCS {
            t ← 2 /¨ ⍺⍺ 2 * ⍳16
            4 ↑ ⍺⍺ t ⎕R (1 ⌽ ∪¨t) ⍺⍺ ⍵ ~ 0
        }¨ R ⍵
        ⍵ ≡ r: ∇ ⍵
        r
    } n
    'lose'
} 4 4⍴0

Explanation

Blank lines indicate a newline, while blocks of lines belong on a single line

'you ', "you" prepended to the result of the function {...

2048 ∊ ⍵: 'win' if the argument (the board) contains 2048, then return "win"

n ← ⍵ assign the right argument to n (so it may be modified in-place)

z ← 0 = ∊nz gets the Boolean list where flattened z is 0

(z / ∊n)z filters the flattened n (to get only the zeros)
[? +/z] use a random number between 1 and the count of zeros (the sum of the Boolean z) to select which zero-containing position
← 2 gets a 2

⎕ ← output the
4 ↑¨ each extended-to-length-4 (with spaces)
⍕¨n string representation of each number

1 ∊ if any of the following are found;
(⍉2=⌿n) pairwise vertical equalities (transposed to be concatenable)
, or (concatenated to)
(2=/n) pairwise horizontal equalities
, or (concatenated to)
0=n zeros
: then:
 call this function on the result of the function {...

R ←R (for Rows of Rotated) is
 the split-into-rows
⍉∘⌽⍣⎕ prompt for numeric input, then rotate (literally mirror horizontally, then transpose) the argument (the board) –90° times the inputted number

r ←r (for result) gets
R⍣¯1 the inverse of R (rotate back, then merge rows into matrix) applied to the result of the function ⎕UCS{... (where ⍺⍺ means convert to/from UCS points)

t ←t gets
2 /¨ two of each of
⍺⍺ the characters corresponding to the code points
2 * ⍳16 2¹, 2², 2³,... 2¹⁶

4↑ pad with zeros on the right until length 4
C convert the following UCS characters to code points
t ⎕R (1 ⌽ ∪¨t) regex replace each pair t with the unique characters from the next t on the right
C ⍵~0 the argument (board) without zeros (compacted to the left), then converted to UCS code points

 [end of function] applied to each of
R ⍵R applied to the argument (the board)

⍵ ≡ r: if the argument (the old board state) is identical to r (new board state), then:
∇⍵ call this function on the unmodified argument (because the user made an invalid move), else

r return r (the new board state)

} n [end of function] applied to n (the new board state), else

'lose' return "lose"

} 4 4 ⍴ 0 [end of function] applied to a 4-by-4 table of zeros (the initial state)

Adám

Posted 2014-03-14T01:02:26.820

Reputation: 37 779

20

GolfScript, 323 characters

1,16*{16,{1$=!},.,rand=)/()2++\[]*+4/{.['-----']4*'+'*'++'1/*n+:^\{'|''     ':X'|'+4*n++:Y.@{X\`+-5>'|'\+}%'|'+n+Y+Y+^+}%+puts}:P~"wasd":Q{1$.@{Q\?[{zip}{}{-1%zip-1%}{{-1%}%}]=\1$~{0-[{.2$={+)}*}*0...]4<{1|(}%}%\~}:^~=!},:F{0{;'"#{'9.?rand';STDIN.getc()}"'++~.F\?0<}do^[]*.2048?0<.!{'you win'@@}*}{'you lose'@@*0}if}do 4/P;

The keys you have to use are wasd but you can change the constant in the code to whatever keys you like. It gracefully ignores any unknown key or illegal move. Unfortunately you have to press enter after each key.

Example 2048ascii

256 character solution

1,16*{16,{1$=!},.,rand=)/())+\[]*+4/{.{{.9>7*+48+}%n+}%puts}:P~"wasd":Q{1$.@{Q\?[{zip}{}{-1%zip-1%}{{-1%}%}]=\1$~{0-[{.2$={;21+}*}*0...]4<{20%}%}%\~}:^~=!},:F{0{;'"#{'9.?rand';STDIN.getc()}"'++~.F\?0<}do^[]*.10?0<.!{'you win'@@}*}{'you lose'@@*0}if}do 4/P;

Here the output is hexadecimal logarithmic, i.e. 0 stands for ., 1 for 2, 2 for 4, 3 for 8 ... B for 2048. Since we all know hexadecimals and the powers of two this shouldn't be a limitation at all.

Example run (first moves):

0000
0000
0010
0000
w
0011
0000
0000
0000
a
2000
0000
0001
0000
s
0000
0000
0100
2001
d
0000
0000
1001
0021
w
1022
0000
0001
0000
a
1301
0000
1000
0000
s
0000
1000
0000
2301
d
0000
1001
0000
0231

Howard

Posted 2014-03-14T01:02:26.820

Reputation: 23 109

Tiles should be seperated though, but nice job. – Teun Pronk – 2014-03-14T15:55:40.377

@TeunPronk I'm working on it. Unfortunately it breaks the nice power of two score. – Howard – 2014-03-14T15:57:06.283

7+unlimited for being exactly 256 chars – SztupY – 2014-03-14T16:25:35.137

yay...2^7 characters!! – Mukul Kumar – 2014-03-14T16:36:14.063

1Nice! Didn't know how to do input in golfscript before. Personally I like the 256 char solution more, easier to read. And I would say the tiles are separated because each tile is only 1 character long. there is never any ambiguity. – Claudiu – 2014-03-14T19:14:23.667

12

J - 240 230 216 char

This counts the trailing newline, because you need it to start running the game at the console. Play by typing one of udlr and then hitting Enter. Moves that do nothing to the board are handled properly, but the program will get mad at you if you give it any bad input.

'you ',>lose`win{~$:@".@('o b=:2 t}^:(1-b-:])s ',' b',~1!:1@1:)`w@.((w=:2048 e.,)+(s d-:s u=:l d=:r(&.|:))*s r-:(s=:[:p(2(=/(0,+/^:)@{.,}.),)/@p=:\:=&0)l=:&.|.r=:"1)(o=:[2:1!:2~4<@":"0])b=:2(t=:(?&#{])[:I.0=,)}4 4$0

The readable version and explanation are a little too large to fit comfortably into the post: you can find a writeup at this link.

Usage:

   'you ',>lose`win{~$:@".@('o b=:2 t}^:(1-b-:])s ',' b',~1!:1@1:)`w@.((w=:2048 e.,)+(s d-:s u=:l d=:r(&.|:))*s r-:(s=:[:p(2(=/(0,+/^:)@{.,}.),)/@p=:\:=&0)l=:&.|.r=:"1)(o=:[2:1!:2~4<@":"0])b=:2(t=:(?&#{])[:I.0=,)}4 4$0
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   2|   0|   0|   0|
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
r
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   0|   0|   0|   2|
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   0|   2|   0|   0|
+----+----+----+----+
u
+----+----+----+----+
|   0|   2|   0|   2|
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   0|   0|   0|   2|
+----+----+----+----+
d
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   2|   0|   0|   0|
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   0|   2|   0|   4|
+----+----+----+----+
l
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   2|   0|   0|   0|
+----+----+----+----+
|   0|   0|   2|   0|
+----+----+----+----+
|   2|   4|   0|   0|
+----+----+----+----+
d
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   0|   2|   0|   0|
+----+----+----+----+
|   4|   4|   2|   0|
+----+----+----+----+
r
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   0|   0|   0|   2|
+----+----+----+----+
|   0|   0|   0|   2|
+----+----+----+----+
|   0|   0|   8|   2|
+----+----+----+----+
d
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   0|   0|   0|   0|
+----+----+----+----+
|   0|   2|   0|   2|
+----+----+----+----+
|   0|   0|   8|   4|
+----+----+----+----+

algorithmshark

Posted 2014-03-14T01:02:26.820

Reputation: 8 144

Great. Unfortunately the squares size differs when the contents change and that was one requirement stated in the question. – Howard – 2014-03-14T18:52:26.370

@Howard I'm of the persuasion that making the tiles rigidly squarelike is a lot uglier than letting them be, but there, it's fixed. – algorithmshark – 2014-03-14T19:16:25.330

9

Mathematica, 484 chars

Very ugly.

m@l=#//.{{x___,0,a_/;a>0,y___}:>{x,a,0,y},{x___,a_/;a>0,a_,y___}:>{x,2 h@a,0,y}}/.h@a_:>a&;{m@u,m@d,m@r}=Composition[#,m@#2,#]&@@@{{Thread,l},{Reverse,u},{Thread,d}};a=ReplacePart[#,RandomChoice@Position[#,0]->2]&;g=a@ConstantArray[0,{4,4}];EventHandler[Dynamic[GraphicsGrid@Map[Graphics@Text@#&,g,{2}]],(#2<>"ArrowKeyDown":>If[g!=m[#]@g,g=a[m[#]@g];Which[And@@(g==m[#]@g&/@{u,l,r,d}),Print@"you lose",!FreeQ[g,2048],Print@"you win"]])&@@@{{l,"Left"},{r,"Right"},{u,"Up"},{d,"Down"}}]

Controlled by arrow keys.

enter image description here


Ungolfed:

move[Left] = # //. {{x___, 1, a_ /; a > 1, y___} :> {x, a, 1, y},
      {x___, a_ /; a > 1, a_, y___} :> {x, 2 Hold@a, 1, y}} /. 
    Hold@a_ :> a &;
move[Up] = Composition[Transpose, move[Left], Transpose];
move[Down] = Composition[Reverse, move[Up], Reverse];
move[Right] = Composition[Transpose, move[Down], Transpose];
addTile = ReplacePart[#, RandomChoice@Position[#, 1] -> 2] &;
keyDown = If[grid != move[#][grid], grid = addTile[move[#][grid]];
    Which[And @@ (grid == move[#][grid] & /@ {Left, Right, Up, Down}),
      status = "Can't move...",
     ! FreeQ[grid, 2048], status = "2048!"]] &;
grid = addTile@ConstantArray[1, {4, 4}];
status = "";
EventHandler[Dynamic[ArrayPlot[Log2@grid/11,
   ColorFunction -> "StarryNightColors",
   ColorFunctionScaling -> False,
   Mesh -> All,
   Epilog -> {MapIndexed[
      Text[Style[#1, "Section"] //. 1 -> "", #2 - {0.5, 0.5}] &, 
      Transpose@Reverse@grid, {2}],
     Text[Style[status, "Section"], {2, 2}]}]],
 {"LeftArrowKeyDown" :> keyDown[Left],
  "RightArrowKeyDown" :> keyDown[Right],
  "UpArrowKeyDown" :> keyDown[Up],
  "DownArrowKeyDown" :> keyDown[Down]}]

enter image description here

alephalpha

Posted 2014-03-14T01:02:26.820

Reputation: 23 988

2I like the looks of the ungolfed one! – tomsmeding – 2014-03-22T06:31:44.857

7

Delphi XE3 (Waaay to many {whispers} 2.979 bytes -> ungolfed 4.560 bytes)

I like to call this "2048 code the novel"
Used more bytes than I like but it works and it was fun to do.

Im still going to try make it shorter later on.

Game in progress

The game

Golfed

uses System.SysUtils,Windows;type TDir=(dUp,dDown,dLeft,dRight,dInv);const t='_____________________________';er='|      |      |      |      |';nr='| %s | %s | %s | %s |';br='|______|______|______|______|';fn='%d';procedure mycls;var S:String;H:DWORD;CO:_COORD;begin H:=GetStdHandle(STD_OUTPUT_HANDLE);CO.X:=0;CO.Y:=0;SetConsoleCursorPosition(H,CO);S:=StringOfChar(Chr(32),2000);Writeln(S);SetConsoleCursorPosition(H,CO);end;var a:array[1..4,1..4]of integer;c,rx,ry,i,j:int8;m:string;GameOver,gs:boolean;function hz:boolean;var b,q:int8;begin for b:=1to 4do for q:=1to 4do if a[b,q]=0 then exit(true);end;function HM:boolean;var b,q:int8;begin if hz then exit(true);for b:=1to 4do for q:=1to 4do begin c:=a[b,q];if c in [a[b-1,q],a[b+1,q],a[b,q-1],a[b,q+1]] then result:=true;end;end;procedure rn(out n,m:int8);var z:int8;begin z:=0;repeat n:=Random(4)+1;m:=Random(4)+1;z:=z+1;until(a[n,m]=0)and(z>=3);end;function gn(n:integer):string;begin if n=0 then exit('    ');Result:=IntToStr(n).PadLeft(4,' ');end;procedure pm(d:TDir;score:boolean);var b,q,z:int8;begin case d of dUp:for z:=1to 3do for b:=1to 4do for q:=1to 3do begin if score then begin if a[q,b]=a[q+1,b] then begin a[q,b]:=a[q,b]+a[q+1,b];a[q+1,b]:=0;end;end else if a[q,b]=0 then begin a[q,b]:=a[q+1,b];a[q+1,b]:=0;end;end;dDown:for z:=1to 3do for b:=1to 4do for q:=2to 4do begin if score then begin if a[q,b]=a[q-1,b] then begin a[q,b]:=a[q,b]+a[q-1,b];a[q-1,b]:=0;end;end else if a[q,b]=0 then begin a[q-1,b]:=a[q,b];a[q-1,b]:=0;end;end;dLeft:for z:=1to 3do for q:=1to 4do for b:=1to 3do begin if score then begin if a[q,b]=a[q,b+1] then a[q,b]:=a[q,b]+a[q,b+1];a[q,b+1]:=0;end else if a[q,b]=0 then begin a[q,b]:=a[q,b+1];a[q,b+1]:=0;end;end;dRight:for z:=1to 3do for q:=1to 4do for b:=2to 4do begin if score then begin if a[q,b]=a[q,b-1] then begin a[q,b]:=a[q,b]+a[q,b-1];a[q,b-1]:=0;end;end else if a[q,b]=0 then begin a[q,b]:=a[q,b-1];a[q,b-1]:=0;end;end;end;end;function gd(s:string):TDir;begin s:=lowercase(s);if s='u'then exit(dUp);if s='d'then exit(dDown);if s='l'then exit(dLeft);if s='r'then exit(dRight);exit(dInv)end;procedure dg;var z:int8;begin writeln(t);for z:=1to 4do begin writeln(er);Writeln(Format(nr,[gn(a[z,1]),gn(a[z,2]),gn(a[z,3]),gn(a[z,4])]));Writeln(br);end;end;function hw:boolean;var b,q:int8; begin for b:=1to 4do for q:=1to 4do if a[b,q]=2048 then result:=true;end;function dm:boolean;var d:Tdir;begin d:=gd(m);if d=dInv then if not gs then exit(false)else exit(true);pm(d,false);pm(d,true);pm(d,false);exit(true);end;begin gs:=true;m:='';for j:=1to 4do for i:=1to 4do begin a[i,j]:=0;end;rx:=0;ry:=0;rn(rx,ry);a[rx,ry]:=2;repeat if (dm) then begin if hz then begin rn(rx,ry);a[rx,ry]:=2;end;gs:=false;end;mycls;GameOver:=true;if hw then WriteLn('You have won!')else if HM then begin GameOver:=false;dg;writeln('Direction: [U]=up, [D]=Down, [L]=Left, [R]=Right');readln(m);end else WriteLn('Game Over, no more possible moves :('#13#10'Try again next time')until GameOver;readln;end.

Ungolfed

uses
  System.SysUtils,Windows;
type
  TDir=(dUp,dDown,dLeft,dRight,dInv);
const
  t='_____________________________';
  er='|      |      |      |      |';
  nr='| %s | %s | %s | %s |';
  br='|______|______|______|______|';
  fn='%d';
procedure mycls;
var
  S:String;
  H:DWORD;
  CO:_COORD;
begin
  H:=GetStdHandle(STD_OUTPUT_HANDLE);
  CO.X:=0;
  CO.Y:=0;
  SetConsoleCursorPosition(H,CO);
  S:=StringOfChar(Chr(32),2000);
  Writeln(S);
  SetConsoleCursorPosition(H,CO);
end;
var
  a:array[1..4,1..4]of integer;
  c,rx,ry,i,j:int8;
  m:string;
  GameOver,gs:boolean;
function hz:boolean;
var b,q:int8;
begin
  for b:=1to 4do
    for q:=1to 4do
      if a[b,q]=0 then exit(true);
end;
function HM:boolean;
var b,q:int8;
begin
  if hz then exit(true);
  for b:=1to 4do
    for q:=1to 4do
    begin
      c:=a[b,q];
      if c in [a[b-1,q],a[b+1,q],a[b,q-1],a[b,q+1]] then
        result:=true;
    end;
end;
procedure rn(out n,m:int8);
var z:int8;
begin
z:=0;
  repeat
    n:=Random(4)+1;
    m:=Random(4)+1;
    z:=z+1;
  until(a[n,m]=0)and(z>=3);
end;
function gn(n:integer):string;
begin
  if n=0 then exit('    ');
  Result:=IntToStr(n).PadLeft(4,' ');
end;
procedure pm(d:TDir;score:boolean);
var
  b,q,z:int8;
begin
  case d of
    dUp:
      for z:=1to 3do
        for b:=1to 4do
          for q:=1to 3do
          begin
            if score then
            begin
              if a[q,b]=a[q+1,b] then
              begin
                a[q,b]:=a[q,b]+a[q+1,b];a[q+1,b]:=0;
              end;
            end
            else
              if a[q,b]=0 then
              begin
                a[q,b]:=a[q+1,b];a[q+1,b]:=0;
              end;
          end;
    dDown:
      for z:=1to 3do
        for b:=1to 4do
          for q:=2to 4do
          begin
            if score then
            begin
              if a[q,b]=a[q-1,b] then
              begin
                a[q,b]:=a[q,b]+a[q-1,b];a[q-1,b]:=0;
              end;
            end
            else
              if a[q,b]=0 then
              begin
                a[q-1,b]:=a[q,b];
                a[q-1,b]:=0;
              end;
          end;
    dLeft:
      for z:=1to 3do
        for q:=1to 4do
          for b:=1to 3do
          begin
            if score then
            begin
              if a[q,b]=a[q,b+1] then
                a[q,b]:=a[q,b]+a[q,b+1];a[q,b+1]:=0;
            end
            else
              if a[q,b]=0 then
              begin
                a[q,b]:=a[q,b+1];a[q,b+1]:=0;
              end;
          end;
    dRight:
      for z:=1to 3do
        for q:=1to 4do
          for b:=2to 4do
          begin
            if score then
            begin
              if a[q,b]=a[q,b-1] then
              begin
                a[q,b]:=a[q,b]+a[q,b-1];a[q,b-1]:=0;
              end;
            end
            else
              if a[q,b]=0 then
              begin
                a[q,b]:=a[q,b-1];a[q,b-1]:=0;
              end;
          end;
  end;
end;

function gd(s:string):TDir;
begin
  s:=lowercase(s);
  if s='u'then exit(dUp);
  if s='d'then exit(dDown);
  if s='l'then exit(dLeft);
  if s='r'then exit(dRight);
  exit(dInv)
end;
procedure dg;
var z:int8;
begin
  writeln(t);
  for z:=1to 4do
  begin
    writeln(er);
    Writeln(Format(nr,[gn(a[z,1]),gn(a[z,2]),gn(a[z,3]),gn(a[z,4])]));
    Writeln(br);
  end;
end;
function hw:boolean;
var b,q:int8;
begin
  for b:=1to 4do
    for q:=1to 4do
      if a[b,q]=2048 then
        result:=true;
end;
function dm:boolean;
var
  d:Tdir;
begin
  d:=gd(m);
  if d=dInv then if not gs then exit(false)else exit(true);
  pm(d,false);
  pm(d,true);
  pm(d,false);
  exit(true);
end;
begin
    gs:=true;m:='';
    for j:=1to 4do
      for i:=1to 4do
      begin
        a[i,j]:=0;
      end;
   rx:=0;ry:=0;
   rn(rx,ry);
   a[rx,ry]:=2;
  repeat
    if (dm) then
    begin
      if hz then
      begin
        rn(rx,ry);
        a[rx,ry]:=2;
      end;
      gs:=false;
    end;
    mycls;
    GameOver:=true;
    if hw then
      WriteLn('You have won!')
    else if HM then
    begin
      GameOver:=false;
      dg;
      writeln('Direction: [U]=up, [D]=Down, [L]=Left, [R]=Right');
      readln(m);
    end
    else
      WriteLn('Game Over, no more possible moves :('#13#10'Try again next time')
  until GameOver;
  readln;
end.

Teun Pronk

Posted 2014-03-14T01:02:26.820

Reputation: 2 599

Keep this in mind when parsing numbers input by users! – Zev Eisenberg – 2015-02-26T13:34:33.210

1Good thing this question doesn't have a leaderboard... – Patrick Roberts – 2016-08-05T01:13:21.563

22.979 bytes? Is it supposed to be kilobytes? – None – 2014-03-14T16:54:40.807

9Some places in the world use commas in numbers the way we use periods, I would not be all that surprised if the reverse was also true. – undergroundmonorail – 2014-03-15T04:55:58.030

1@undergroundmonorail True, in Europe the number one thousand and twelve comma six is often written as 1.012,6 instead of the American 1,012.6 :) – tomsmeding – 2014-03-22T06:29:31.907

CodeGolf taught me that you can interchange , and . in numbers! – Tejas Kale – 2014-04-08T09:52:19.323

7

C (C89 standard), 881 bytes

Use wasd keys to move. Compiles in GCC and clang by default, unless set to C99 standard (I guess). Uses termios.h, worked in Linux and MacOS X. Not sure about Windows.

#include<termios.h>
#define R return
#define H while
char t[17],*Q,*W="adws",D,x,y,X;m(x,y){R!D?x+y*4:D==1?3-x+y*4:D==2?y+x*4:y+(3-x)*4;}c(){for(y=0;y<3;++y)for(x=0;x<3;++x){D=t[x+y*4];if(t[x+1+y*4]==D||t[x+4+y*4]==D)x=y=9;}R y>4;}d(){if(strlen(t)==16)R 0;H(t[x=(rand()&15)]);R t[x]=1;}r(x){putchar(x);}b(){y=0;r(10);H(y<21)r(y++%5?45:43);r(10);}f(){for(x=0;x<17;++x)if(X=(t[x]==11))x=32;R x<18;}struct termios z;main(){srand(time(tcgetattr(0,&z)));z.c_lflag&=~ICANON;tcsetattr(0,0,&z);H(f()&&(d()||c())){x=0;H(x<16){if(!(x&3)){b();r('|');}if(y=t[x++])printf("%4u|",1<<y);else printf("    |");}b();r(10);H(!(Q=strchr(W,getchar())));D=Q-W;for(y=0;y<4;++y)for(X=0,x=1;x<4;++x)if(t[m(x,y)]){if(t[m(x,y)]==t[m(X,y)]&&t[m(X,y)]++)t[m(x,y)]=0;X=x;}do{for(y=0;y<4;++y)for(x=0;x<3;++x)if(!t[m(x,y)]&&(X=t[m(x+1,y)])){t[m(x,y)]=X;t[m(x+1,y)]=0;x=y=9;}}H(y>4);}puts(X?"you win":"you lose");}

Broken in some lines:

#include<termios.h>
#define R return
#define H while
char t[17],*Q,*W="adws",D,x,y,X;m(x,y){R!D?x+y*4:D==1?3-x+y*4:D==2?y+x*4:y+(3-x)*4;}
c(){for(y=0;y<3;++y)for(x=0;x<3;++x){D=t[x+y*4];if(t[x+1+y*4]==D||t[x+4+y*4]==D)x=y=9;}R y>4;}
d(){if(strlen(t)==16)R 0;H(t[x=(rand()&15)]);R t[x]=1;}
r(x){putchar(x);}
b(){y=0;r(10);H(y<21)r(y++%5?45:43);r(10);}
f(){for(x=0;x<17;++x)if(X=(t[x]==11))x=32;R x<18;}
struct termios z;
main(){srand(time(tcgetattr(0,&z)));z.c_lflag&=~ICANON;tcsetattr(0,0,&z);
H(f()&&(d()||c())){x=0;H(x<16){if(!(x&3)){b();r('|');}if(y=t[x++])printf("%4u|",1<<y);else printf("    |");}
b();r(10);H(!(Q=strchr(W,getchar())));D=Q-W;for(y=0;y<4;++y)for(X=0,x=1;x<4;++x)
if(t[m(x,y)]){if(t[m(x,y)]==t[m(X,y)]&&t[m(X,y)]++)t[m(x,y)]=0;X=x;}
do{for(y=0;y<4;++y)for(x=0;x<3;++x)if(!t[m(x,y)]&&(X=t[m(x+1,y)]))
{t[m(x,y)]=X;t[m(x+1,y)]=0;x=y=9;}}H(y>4);}puts(X?"you win":"you lose");}

The looks:

+----+----+----+----+
|   8|   4|   8|   2|
+----+----+----+----+
|    |  16|    |    |
+----+----+----+----+
|    |   2|    |    |
+----+----+----+----+
|    |    |    |   2|
+----+----+----+----+

It can be improved for sure.

asr

Posted 2014-03-14T01:02:26.820

Reputation: 361

5

Java: 1346 1269

Edit So although this contest is done, sometimes I can't let go when improvements can be made. This version boasts a leaner, meaner, in-place folding function, the eviction of most boolean types except where it would be more verbose without them, and slightly smaller cells (4x4 instead of 5x5) to cut out a few extra characters there.

So this was a fun one. Thanks for posting! Ungolfed, this was 2856 bytes, golfed I shrunk it to 1346 bytes. Being Java, I'm not going to win, but I wanted to put in a good showing. Figuring out a "general" roll-up function to handle tile joins and moves was fun -- you can of course check out my "progress" by looking through the commits on my github repository for this solution.

Golfed:

import java.util.*;class T{public static void main(String[]a){(new T()).s();}int[][]b=new int[4][4];int d,p,i,j,x,y,v,q,r;boolean I,V;void s(){p();do{d();do{char a=(new Scanner(System.in)).nextLine().charAt(0);y=a=='u'?f(0,1):a=='d'?f(1,1):a=='l'?f(0,0):a=='r'?f(1,0):0;}while(y<1);p();}while((x=n())>0);d();c("you "+(x<0?"win":"lose"));}int h(){for(int[]y:b)for(int x:y)if(x<2)return 1;return 0;}int n(){for(y=0;y<4;y++){for(x=0;x<4;x++){i=b[y][x];if(x<3&&i==b[y][x+1]||y<3&&i==b[y+1][x])return 1;if(i>2047)return -1;}}return h();}int f(int w,int z){I=w>0;V=z>0;for(i=d=0;i<4;i++){p=I?3:0;for(j=1;j<4;){v=V?i:j;x=I?3-v:v;v=V?j:i;y=I?3-v:v;q=V?x:p;r=V?p:y;if(b[y][x]==0||p==(V?y:x))j++;else if(b[r][q]==0){d+=b[r][q]=b[y][x];b[y][x]=0;j++;}else if(b[r][q]==b[y][x]){d+=b[r][q]*=2;b[y][x]=0;p+=I?-1:1;j++;}else p+=I?-1:1;}}return d;}int v(){return(new Random()).nextInt(4);}void p(){if(h()<1)return;do{x=v();y=v();}while(b[x][y]>0);b[x][y]=2;}void c(String a){System.out.println(a);}String l(char n,char m){String s=""+n;for(i=0;i<4;i++){for(j=0;j<4;j++)s+=m;s+=n;}return s;}void d(){c(l('+','-'));String p[]=new String[5];for(int[]y:b){p[0]=p[1]=p[3]=l('|',' ');p[2]="";for(x=0;x<4;)p[2]+=String.format("|%4d",y[x++]);p[2]+="|";p[4]=l('+','-');for(String q:p)c(q);}}}

Ungolfed: (Check my github repository for this project for an updated version, including an assertions-based test for new folding functions)

import java.util.*;
class Twe {
    public static void main(String[] a){
        (new Twe()).start();
    }
    int[][] board=new int[4][4];
    void start(){
        int x;
        placeTwo();
        do{
            drawBoard();
            resolve();
            placeTwo();
        }while((x=notDone())>0);
        drawBoard();
        wrapup(x);
    }
    int hasFree(){
        for(int[]y:board)
            for(int x:y)
                if(x<2)return 1;
        return 0;
    }
    int notDone(){
        int moves,x,y;
        for(moves=y=0;y<4;y++){
            for(x=0;x<4;x++){
                else if(x<3&&board[y][x]==board[y][x+1]||
                        y<3&&board[y][x]==board[y+1][x])moves++;
                if(board[y][x]>2047)return -1;
            }
        }
        return hasFree()+moves;
    }
    void wrapup(int k){
        if(k<0){
            chalk("you win",true);
        }else{
            chalk("you lose",true);
        }
    }
    void resolve(){
        do{
            switch((new Scanner(System.in)).nextLine().charAt(0)){
                case 'u':
                    if (fold(false,true)>0)return;
                    break;
                case 'd':
                    if (fold(true, true)>0)return;
                    break;
                case 'l':
                    if (fold(false,false)>0)return;
                    break;
                case 'r':
                    if (fold(true,false)>0)return;
                    break;
                case 'z':
                    board[0][0]=2048; // instant win;
                    return;
            }
        } while(true);
    }
    // false,true  = up
    // true, true  = down
    // false,false = left
    // true, false = right
    int fold(boolean inv, boolean vert){
        int didMove=0;
        int nextSpot,x,y,v,q,r;
        int[][] nb = new int[4][4];
        for(int i=0;i<4;i++){
            nextSpot=inv?3:0;
            for(int j=0;j<4;j++){
                v=vert?i:j;
                x=inv?3-v:v;
                v=vert?j:i;
                y=inv?3-v:v;
                q=vert?x:nextSpot;
                r=vert?nextSpot:y;
                if(board[y][x]>0){
                    if(nb[r][q]<1){
                        nb[r][q]=board[y][x];
                        didMove+=(inv?-1:1)*(vert?y-r:x-q);
                    }else if(nb[r][q]==board[y][x]){
                        nb[r][q]*=2;
                        nextSpot+=inv?-1:1;
                        didMove++;
                    }else{
                        nextSpot+=inv?-1:1;//suckage
                        q=vert?x:nextSpot;
                        r=vert?nextSpot:y;
                        nb[r][q]=board[y][x];
                        didMove+=(inv?-1:1)*(vert?y-r:x-q);
                    }
                }
            }
        }
        board=nb;
        return didMove;
    }
    int vec(){
        return (new Random()).nextInt(4);
    }
    void placeTwo(){
        if (hasFree()<1) return;
        int x,y;
        do{
            x=vec();y=vec();
        }while(board[x][y]>0);
        board[x][y]=2;
    }
    void chalk(String a, boolean nl){
        System.out.print(a+(nl?"\n":""));
    }
    String fill(char node, char mid){
        String str = ""+node;
        for(int i=0;i<4;i++){
            for(int j=0;j<5;j++)
                str+=mid;
            str+=node;
        }
        return str;
    }
    void drawBoard(){
        chalk(fill('+','-'),true);
        String p[] = new String[6];
        for(int[]y:board){
            p[0]=p[1]=p[3]=p[4]=fill('|',' ');
            p[2]="";
            for(int x=0;x<4;){
                p[2]+=adjust(y[x++]);
            }
            p[2]+="|";
            p[5]=fill('+','-');
            for (String q:p){
                chalk(q,true);
            }
        }
    }
    String adjust(int a){
        return String.format("|%5d",a);
    }
}

Using the program is simple. To build and run:

javac T.java
java T

Press u to fold up, r to fold right, d to fold down, l to fold left. Any other key is ignored, invalid (no result) moves are ignored. Being Java, press enter after each key to flush the line buffer. As required by the rules, if you win the program outputs you win, if you lose the program outputs you lose. New 2's are placed randomly in the open tiles. Merges follow the stated rules. Cells are 4x4 characters, with a border surrounding each cell. Of course, leave me a comment if I've messed something up and I'll be certain to fix it.

Example output:

$ java T
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   2|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
u
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   2|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   2|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
l
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   2|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   2|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   2|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
u
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   4|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   2|   2|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
l
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   4|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   4|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   2|
|    |    |    |    |
+----+----+----+----+
u
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   8|   2|   0|   2|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
l
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   8|   4|   2|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
l
u
d
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   2|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   8|   4|   2|   0|
|    |    |    |    |
+----+----+----+----+
d
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   2|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   8|   4|   4|   0|
|    |    |    |    |
+----+----+----+----+
l
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   2|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   2|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   8|   8|   0|   0|
|    |    |    |    |
+----+----+----+----+
l
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   2|   2|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   2|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|  16|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
d
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   2|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   4|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|  16|   2|   0|   0|
|    |    |    |    |
+----+----+----+----+
d
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   0|   0|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|   4|   2|   0|   0|
|    |    |    |    |
+----+----+----+----+
|    |    |    |    |
|    |    |    |    |
|  16|   4|   0|   0|
|    |    |    |    |
+----+----+----+----+

ProgrammerDan

Posted 2014-03-14T01:02:26.820

Reputation: 1 129

2

Lua, 622 616 615 612 592 590 575 bytes

Queries stdin for 1,2,3,4 correlating with left, down, right, up (made for numpad input); crashes if you give it bad input.

Blank squares are printed as '0's.

b={('\0'):rep(16):byte(1,16)}c=1 a=print h=unpack while{}do if c then c=z
e={}for i=1,16 do e[#e+1]=0==b[i]and i or z end _=#e==0 and
a'you lose'b[e[math.random(#e)]]=2 l=('+----'):rep(4)..'+\n'm=l:gsub('-',' ')for
i=1,13,4 do a(l..m..m..m..('+%4d+%4d+%4d+%4d+'):format(h(b,i)))end a(l)end c=z
u,v,w=h({4,1,-4,1,-4,16,4,-1,1,1,4,-4},3*io.read()-2)for i=1,4 do o=-1 for j=2,4
do if 0~=b[u*i+v*j+w]then for k=1-j,o do p=u*i-v*k+w q=p+v r=b[p]if r==0 then
b[p]=b[q]b[q]=r c=1 o=k elseif r==b[q]then _=r==1024 and a'you win'b[p]=r*2
b[q]=0 c=1 o=k-1 break end end end end end end 

Example output:

+----+----+----+----+
+    +    +    +    +
+    +    +    +    +
+    +    +    +    +
+   2+   0+   0+   0+
+----+----+----+----+
+    +    +    +    +
+    +    +    +    +
+    +    +    +    +
+   0+   0+   0+   0+
+----+----+----+----+
+    +    +    +    +
+    +    +    +    +
+    +    +    +    +
+   0+   0+   0+   0+
+----+----+----+----+
+    +    +    +    +
+    +    +    +    +
+    +    +    +    +
+   0+   0+   0+   0+
+----+----+----+----+

2
+----+----+----+----+
+    +    +    +    +
+    +    +    +    +
+    +    +    +    +
+   0+   2+   0+   0+
+----+----+----+----+
+    +    +    +    +
+    +    +    +    +
+    +    +    +    +
+   0+   0+   0+   0+
+----+----+----+----+
+    +    +    +    +
+    +    +    +    +
+    +    +    +    +
+   0+   0+   0+   0+
+----+----+----+----+
+    +    +    +    +
+    +    +    +    +
+    +    +    +    +
+   2+   0+   0+   0+
+----+----+----+----+

thenumbernine

Posted 2014-03-14T01:02:26.820

Reputation: 341

0

Clojure: 599

run it in a REPL

golfed

(defn i[b](let[f(into[](flatten b))z(seq(keep-indexed #(when(zero? %2)%1)f))]
(cond(some #{2048}f)(pr "you win")(empty? z)(pr "game over"):e(partition 4
(assoc f(rand-nth z)2)))))(def r #(remove zero? %))(loop[b(i (partition 4
(repeat 16 0)))](when((fn[v](doseq[l(for[a v](apply str(map #(format "%5d " %)a)))]
(println l "\n"))v)b)(-> b((apply comp(assoc(into[](repeat 5(fn[v]
(map(fn[n](map #(nth % n)v))[3 2 1 0]))))({"h"4 "k"3 "l"2 "j"1}(read-line))
(partial map(comp #(take 4(concat % [0 0 0 0]))(fn[v]
(r(reduce #(let[l(last %1)](if(= %2 l)(conj(pop %1)(+ l %2) 0)
(conj %1 %2)))[]v)))r)))))i recur)))

ungolfed

(defn insert-2 [board]
  (let [flat (into [] (flatten board))
        zero-indices (seq (keep-indexed
                       #(when (zero? %2) %1)
                       flat))]
    (cond
      (some #{2048} flat) (pr "you win")
      (empty? zero-indices) (pr "game over")
      :else (partition 4 (assoc flat (rand-nth zero-indices) 2)))))

(defn rotate [board]
  (map
    (fn [n]
        (map #(nth % n)
             board))
    [3 2 1 0]))

(defn remove-zeros [row]
 (remove zero? row))

(defn fill [row]
 (take 4 (concat row [0 0 0 0])))

(defn sum-up [acc x]
  (let [l (last acc)]
    (if (= x l)
      (conj (pop acc) (+ l x) 0)
      (conj acc x))))

(defn sum-pairs [v]
  (remove-zeros (reduce sum-up [] v)))

(defn render [v]
  (doseq [line (for [row v]
                 (apply str (map #(format "%5d " %) row)))]
    (println line "\n")) v)

(defn slide [board]
 (map (comp
        fill
        sum-pairs
        remove-zeros
        ) board))

(loop [board (insert-2 (partition 4 (repeat 16 0)))]
  (when (render board)
    (let [input ({"h" 4 "k" 3 "l" 2 "j" 1} (read-line))
          command (apply comp
                         (assoc (into [] (repeat 5 rotate))
                                input slide))] ;; (comp rotate rotate slide rotate rotate)
      (-> board command insert-2 recur))))

Kolja

Posted 2014-03-14T01:02:26.820

Reputation: 121