使用最少的字节来解决2048的确定性版本


17

编写一个程序,该程序将生成到游戏2048的确定性变式的获胜顺序。该顺序应为数字字符串0-3的形式,其中0:向上,1:向右,2:向下,3:剩下。例如,字符串“ 1132”表示右右左下。获胜的程序是到2048的最短源代码!

确定性2048的规则:游戏在4x4网格上进行游戏,该网格最初包含1个图块,位于左上角。每个移动都由命令“左”,“右”,“上”或“下”组成。左命令将网格上的所有图块向左滑动,然后像从左开始的图块一样进行合并和求和。同样,右命令将图块向右滑动,然后从右开始进行组合。

每个图块一次只能加入一个组合。

移动后,将在左侧的第一列中创建一个具有可用空间的新2磁贴,在该列的顶部中的第一个可用空间中将创建一个新的2磁贴。

例如,序列“右右左下”会导致状态

2___
____
____
____

2__2
____
____
____


2__4
____
____
____


24__
2___
____
____


2___
____
____
44__

应用于行_ 2 2 2的命令权限将导致_ _ 2 4。应用于行2 2 2 2的命令权限将导致_ _ 4 4

这个问题的灵感来自http://jmfork.github.io/2048/


2
挑战应该是独立的-如果该链接消失,该怎么办?
门把手

2
这个问题似乎是题外话,因为它本质上是一个“仅链接问题”。
门把手

2
$(".tile-container").addItem("<div class="tile tile-2048 tile-position-3-4">2048</div>");
TheDoctor 2014年

1
@QuadmasterXLII,您可以在描述中阐明3个连续(相同)数字的预期行为
Martin Ender 2014年

1
大!近距离投票已撤回。我这里还有一个问题:由于它是确定性的,人们难道不能只找到最短的输出然后再输出那个吗?
门把手

Answers:


26

Python,740个字符(压缩665个字符)

代码

R=range
G=lambda:[[0]*4for _ in R(4)]
J=[(0,4,1),(2,-1,-1),(1,4,1)]
H=[0,-1,1]
def M(P,d):
 C=G();g,z=[(0,-1),(1,0),(0,1),(-1,0)][d];Q=H[g];W=H[z]
 while 1:
    N=[r[:]for r in P]
    for x in R(*J[g]):
     for y in R(*J[z]):
        s=N[y][x];q,w=y-W,x-Q;d=N[q][w];a,b,c=(((0,s,d),(1,0,s+d))[s==d],(0,0,s or d))[s<1 or d<1];
        if 2-a-(C[y][x]+C[q][w]>0):N[y][x]=b;N[q][w]=c;C[q][w]+=a
    if N==P:break
    P=N
 return N
def F(N):
 for x in R(4):
    for y in R(4):
     if N[y][x]==0:N[y][x]=2;return N
def Z(P,i):
 X=[d for d in R(4)if M(P,d)!=P]
 return i==0and(sum((256,c)[c>0] for v in P for c in v)+P[3][3]*10+P[3][2]*9,-1)or max((Z(F(M(P,d)),i-1)[0],d)for d in X)if X else(-1,-1)
B=G()
B[0][0]=2
h=''
while B[3][3]!=2048:_,X=Z(B,4);h+=`X`;B=F(M(B,X))
print h

(混合选项卡,带有缩进空间以节省一些字节)

我一定很喜欢打高尔夫球,因为如果我只是压缩上面的代码,对它进行base-64编码,exec那么它只有665个字符。以下内容与上面的内容完全相同,没有硬编码的解决方案或任何其他内容:

exec"""eJxVUl1vozAQfMa/wn2qnRjJcNzpDnf7QKS2qlRE+1IUy2oJkARdwl2hbT5+/a0NiXqSZXYH78zY
u0/QFe2qJrewKbaLqoi1lmYSLf909IU2LX1iETfkHjSTIhIBFywUfoALo8AhhtyBlhYMDKnqJX1g
mah4TOgMbhlXK3F01WOJxF06It8mRldGPcKdXhn1jJ+jIXS3bjY1DWLipaA7HRvrprNuMkM8m+wH
a5N7LEMlj1rwcAaPDvR6SPXB6L1Rb2IHB/9Z7P1HVSH6ZvTOqEIsRAmMoZ8eHTt3op9WnOseoDLW
KAIUuR12FbjwKjAK2ZslDf3CZ7NBYzobWK8lj0dZWKhRCko1/p5CQWxpCpDFi64ufhMvg5TQrn7/
6Fqauie8Yal9wC9XjeyNvtzS5dQSjVogz7Kh+o9sjv1oLF0OunKc1YmjOXXrAvBpTx4aJCvaivUf
W8bC7z9EyXV5LY2r/XR9cGFpw08+zfQ3g2sSyCEMzeSXbTce2RZ7xubshg0yXDSI44RhfDaSWxs5
rTd9zYbRIomdHJLgQVwQkjVcXpJhLJJB7AJCGf2MX0QOc5aIiKv1FF7zV5WAFUtEzjn52zXtO13/
AwRvylc=""".decode('base64').decode('zip')

花费约47秒(未投放时间为17秒)找到1111移动顺序:

2221230232213120120232222222221221203211012312310123123101223113322222123230210302321222323223212322101202323123322032132021233212312332023123312111123231223113312312322312232123222021221332111332221012222312222302232021233212312332023212222222123221202332023120312123223221232232222222122122323222222212212232222222221322233231222322200232122312232313132022322212312332121332312320212211332312323223212320232322322133223213212323202123123321231313332122232310112113322212323222220130231233211313332122232312312223232231231232312222220232212312220212232312232123222021221332111332221012222312222302232021233212312332023212222222123221202332023120312123223221322323223312230230323312232313133232223233212312323123323222332222222132221321320323233223232121323212232013221323233032021223320231233220322203132123202123321231233202131321221111231213232131210212312232332132103123130213133213232213321323212332332212222123323322202302333121220222323232113123323221223032032201120112321213312313122232331313331331331312330013323133201112222212232323313133131123121132302311212323321223223232232213213123123123123123123123123123123123123123123123123123122122122122122122123123

随着以下最终电路板位置的移动:

   4    2   16    4
   2    8  128    8
   2    .    . 1024
   .    .    . 1024
Best move: s, with EV=25654

琐事:解决方案是压缩309字节,如果压缩并以base64编码,则为418字节。因此,将其解码并打印出来将是一个更短的程序,但这一点都不有趣

说明

是非高尔夫球版本的粘贴框,每次移动后都将其打印出来,非常有趣!

这是一个非常简单的蛮力AI。它为每个电路板位置分配一个EV:

ev =   256 * number of spaces 
     + sum_of_values 
     + 10 * board_bottom_right 
     +  9 * board_bottom_2nd_right

它先进行深度优先搜索四步,然后选择四步中导致最高EV的路径。ev函数鼓励其清理电路板并将最有价值的部分保留在角落,这最终是非常理想的。到那里就足够了!

如果您修改EV功能,以便在其他木板位置上放置较高的值,则类似:

1  1  1  1
1  1  1  1
1  1  9 10
1  9 10 11 

该功能可以达到以下目的:

   2    8    4    2
  16   32   64   16
  64  128  512 1024
   2  256 2048 8192

16k

尤里卡!使用5步前瞻(而不是4步),并具有以下权重:

1  1  4  4 
1  1  4 10
1  1 14 16
1 16 18 20 

它几乎几乎达到32k,结束于:

   2  128    4     2
  64  256  512     4
   4  128 1024  4096
  16 2048 8192 16384

序列在这里

32k

是的,女士们,先生们,我们已经达到了32k。EV函数不是将平方乘以一个常数,而是将每个平方提高到以下幂并将其相加。x表示不涉及广场:

x x x 3
x x x 4 
x x 5 6
x 6 7 8

它仍然将所有值相加一次,并为每个空平方加256。Lookahead一直是4,直到32k,然后又增加到5k,但实际上并没有太大作用。端板:

   2  128    8     2
  64  256  512     4
   4  128 1024  2048
  16 4096 8192 32768

24,625-move序列的Pastebin


1
该解决方案非常出色(我爱您的蛮力+前瞻性DFS),史诗般的解释以及您对更高的2的幂次幂的追求是最出色的。+1!
ProgrammerDan

好一个!首先使用深度试探法可能会使您无法获得最佳解决方案(最短移动顺序)。也许您可以加入A *搜索:-)
2014年

tar -xzvf a.tar; 蟒蛇
TheDoctor 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.