Rozwiąż deterministyczną wersję 2048, używając jak najmniej bajtów

17

Napisz program, który generuje zwycięską sekwencję ruchów do deterministycznego wariantu gry 2048. Sekwencja powinna być w postaci ciągu liczb 0-3, z 0: góra, 1: prawo, 2: dół, 3: lewo. Na przykład ciąg „1132” oznacza prawy prawy lewy dół. Zwycięski program to najkrótszy kod źródłowy, który dostaje się do 2048 roku!

Zasady deterministycznej 2048: Gra toczy się na siatce 4x4, początkowo zawierającej 1 płytkę, w lewym górnym rogu. Każdy ruch składa się z polecenia „w lewo”, „w prawo”, „w górę” lub „w dół”. Polecenie w lewo przesuwa wszystkie kafelki na siatce w lewo, a następnie łączy i sumuje jak kafelki zaczynające się od lewej. Podobnie, prawe polecenie przesuwa kafelki w prawo, a następnie łączy zaczynając od prawej.

Każdy kafelek może uczestniczyć tylko w jednej kombinacji na ruch.

Po przeniesieniu tworzony jest nowy 2 kafelek w pierwszej kolumnie od lewej z dostępnym miejscem, w pierwszym dostępnym miejscu od góry w tej kolumnie.

Na przykład sekwencja „prawy prawy lewy dół” prowadzi do stanów

2___
____
____
____

2__2
____
____
____


2__4
____
____
____


24__
2___
____
____


2___
____
____
44__

Prawo polecenia zastosowane do wiersza _ 2 2 2 powoduje, że _ _ 2 4 Prawo polecenia zastosowane do wiersza 2 2 2 2 powoduje, że _ _ 4 4

To pytanie zainspirowane http://jmfork.github.io/2048/

QuadmasterXLII
źródło
2
Wyzwania powinny być samodzielne - a co, jeśli ten link umrze?
Klamka
2
To pytanie wydaje się być nie na temat, ponieważ jest to zasadniczo „pytanie tylko do linku”.
Klamka
2
$(".tile-container").addItem("<div class="tile tile-2048 tile-position-3-4">2048</div>");
TheDoctor
1
@QuadmasterXLII możesz wyjaśnić w swoim opisie oczekiwane zachowanie dla 3 kolejnych (identycznych) liczb
Martin Ender
1
Świetny! Zamknięte głosowanie wycofane. Nadal mam tutaj problem: ponieważ jest deterministyczny, czy ludzie nie mogą po prostu znaleźć najkrótszej produkcji, a następnie po prostu ją wydać?
Klamka

Odpowiedzi:

26

Python, 740 znaków (skompresowanych 665 znaków)

Kod :

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

(Miesza tabulatory ze spacjami do wcięcia, aby zaoszczędzić kilka bajtów)

Musiałem go obciągać, ponieważ jeśli tylko skompresuję powyższy kod, kodowanie base-64 go koduje, i execto tylko 665 znaków. Poniższe jest dokładnie równoznaczne z powyższym, brak zakodowanego rozwiązania lub cokolwiek innego:

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')

Odpowiedź :

Znalezienie sekwencji 1111 ruchów zajmuje ~ 47 sekund (17 sekund bez golfa):

2221230232213120120232222222221221203211012312310123123101223113322222123230210302321222323223212322101202323123322032132021233212312332023123312111123231223113312312322312232123222021221332111332221012222312222302232021233212312332023212222222123221202332023120312123223221232232222222122122323222222212212232222222221322233231222322200232122312232313132022322212312332121332312320212211332312323223212320232322322133223213212323202123123321231313332122232310112113322212323222220130231233211313332122232312312223232231231232312222220232212312220212232312232123222021221332111332221012222312222302232021233212312332023212222222123221202332023120312123223221322323223312230230323312232313133232223233212312323123323222332222222132221321320323233223232121323212232013221323233032021223320231233220322203132123202123321231233202131321221111231213232131210212312232332132103123130213133213232213321323212332332212222123323322202302333121220222323232113123323221223032131201123212133123131222323313133313300123231332011222221223232331313313112312113230231121232332122323232321312323213212232313212323211330231231012

Z następującą ostateczną pozycją na planszy i ruchem:

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

Ciekawostki: rozwiązanie ma 309 bajtów zgzipowanych i 418 bajtów, jeśli zgzipowanych i zakodowanych w base64. Byłby to więc krótszy program, który po prostu odkoduje to i wydrukuje, ale to wcale nie jest zabawne .

Objaśnienie :

Oto tabliczka z niegolfowaną wersją, która drukuje planszę po każdym ruchu, bardzo fajnie się ogląda!

To bardzo prosta sztuczna inteligencja. Przypisuje EV do każdej pozycji na planszy:

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

Przeszukuje dogłębnie cztery ruchy do przodu i wybiera ścieżkę, która prowadzi do najwyższej EV w czterech ruchach. Funkcja ev zachęca ją do posprzątania tablicy i trzymania najcenniejszych elementów w rogu, co ostatecznie jest całkiem optymalne. Wystarczy go tam dostać!

Jeśli zmodyfikujesz funkcję EV, aby umieścić wyższą wartość na innych miejscach na planszy, coś takiego:

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

Ta funkcja pozwala uzyskać:

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

16k :

Eureka! Z 5-stopniowym wyprzedzeniem zamiast 4 i następującymi wagami:

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

To prawie prawie 32k, kończąc na:

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

Sekwencja jest tutaj .

32k :

Tak, panie i panowie, osiągnęliśmy próg 32 tys. Funkcja EV, zamiast mnożenia kwadratów przez stałą, podnosi każdy kwadrat do następujących mocy i dodaje je. xoznacza, że ​​kwadrat nie jest zaangażowany:

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

Nadal sumuje wszystkie wartości raz i dodaje 256 dla każdego pustego kwadratu. Lookahead miał 4 lata aż do 32 tys., A potem podskoczył do 5, ale tak naprawdę nie robi wiele. Deska końcowa:

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

Pastebin sekwencji 24 625 ruchów .

Claudiu
źródło
1
To rozwiązanie jest genialne (uwielbiam twoją brutalną siłę + patrzenie w przód DFS), epickie wyjaśnienie, a twoje poszukiwanie coraz wyższych potęg dwóch jest najbardziej doskonałe. +1!
Programator
Niezłe! Korzystanie z heurystyki z głębokością może najpierw uniemożliwić osiągnięcie optymalnych rozwiązań (najkrótsza sekwencja ruchów). Może możesz włączyć wyszukiwanie A * :-)
Mau
tar -xzvf a.tar; python a
TheDoctor