56
\$\begingroup\$

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!

Stephen
14.2k3 gold badges57 silver badges118 bronze badges
asked Mar 14, 2014 at 1:02
\$\endgroup\$
20
  • \$\begingroup\$ 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? \$\endgroup\$ Commented Mar 14, 2014 at 3:41
  • \$\begingroup\$ @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. \$\endgroup\$ Commented Mar 14, 2014 at 3:50
  • 1
    \$\begingroup\$ "If there are no possible merges left, the game is lost" Shouldn't there be an "and the board is full" in there somewhere? \$\endgroup\$ Commented Mar 14, 2014 at 8:25
  • 7
    \$\begingroup\$ Funny how all your questons get a ton of votes, but not many answers. \$\endgroup\$ Commented Mar 14, 2014 at 13:02
  • 1
    \$\begingroup\$ Now its your fault I´ve been playing 2048 the whole weekend and today the productivity of our office has dropped to 0. \$\endgroup\$ Commented Mar 17, 2014 at 10:09

9 Answers 9

21
\$\begingroup\$

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
answered Mar 14, 2014 at 15:44
\$\endgroup\$
5
  • \$\begingroup\$ Tiles should be seperated though, but nice job. \$\endgroup\$ Commented Mar 14, 2014 at 15:55
  • \$\begingroup\$ @TeunPronk I'm working on it. Unfortunately it breaks the nice power of two score. \$\endgroup\$ Commented Mar 14, 2014 at 15:57
  • 7
    \$\begingroup\$ +unlimited for being exactly 256 chars \$\endgroup\$ Commented Mar 14, 2014 at 16:25
  • \$\begingroup\$ yay...2^7 characters!! \$\endgroup\$ Commented Mar 14, 2014 at 16:36
  • 1
    \$\begingroup\$ Nice! 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. \$\endgroup\$ Commented Mar 14, 2014 at 19:14
13
\$\begingroup\$

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 40ドル

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 40ドル
+----+----+----+----+
| 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|
+----+----+----+----+
answered Mar 14, 2014 at 18:47
\$\endgroup\$
2
  • \$\begingroup\$ Great. Unfortunately the squares size differs when the contents change and that was one requirement stated in the question. \$\endgroup\$ Commented Mar 14, 2014 at 18:52
  • \$\begingroup\$ @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. \$\endgroup\$ Commented Mar 14, 2014 at 19:16
10
\$\begingroup\$

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 = ∊n z 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 21, 22, 23,... 216

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)

answered Aug 1, 2016 at 19:39
\$\endgroup\$
10
\$\begingroup\$

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

answered Mar 15, 2014 at 4:02
\$\endgroup\$
1
  • 2
    \$\begingroup\$ I like the looks of the ungolfed one! \$\endgroup\$ Commented Mar 22, 2014 at 6:31
8
\$\begingroup\$

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.
answered Mar 14, 2014 at 16:07
\$\endgroup\$
6
  • 2
    \$\begingroup\$ 2.979 bytes? Is it supposed to be kilobytes? \$\endgroup\$ Commented Mar 14, 2014 at 16:54
  • 9
    \$\begingroup\$ Some 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. \$\endgroup\$ Commented Mar 15, 2014 at 4:55
  • 1
    \$\begingroup\$ @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 :) \$\endgroup\$ Commented Mar 22, 2014 at 6:29
  • \$\begingroup\$ CodeGolf taught me that you can interchange , and . in numbers! \$\endgroup\$ Commented Apr 8, 2014 at 9:52
  • 1
    \$\begingroup\$ Good thing this question doesn't have a leaderboard... \$\endgroup\$ Commented Aug 5, 2016 at 1:13
8
\$\begingroup\$

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.

answered Mar 18, 2014 at 0:19
\$\endgroup\$
6
\$\begingroup\$

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|
| | | | |
+----+----+----+----+
answered Mar 16, 2014 at 20:40
\$\endgroup\$
3
\$\begingroup\$

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+
+----+----+----+----+
answered Feb 25, 2015 at 3:22
\$\endgroup\$
1
\$\begingroup\$

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))))
answered Aug 13, 2017 at 14:28
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.