Jak zdobyć więcej Klotskiego w moim życiu?

15

Uwielbiam przesuwane łamigłówki, ale ostatnio nie miałem na nie czasu. Dlatego potrzebuję programu, który dałby mi rozwiązanie łamigłówek z przesuwanymi kafelkami, w szczególności układanki Klotskiego.

Twoje dane będą miały następujący format:

#######
#001gg#
##.222#
.######

gdzie #reprezentuje ściany, .reprezentuje otwarty obszar, greprezentuje cel, a sąsiednie liczby reprezentują różne bloki. Możesz założyć, że:

  1. Nie będzie więcej niż 10 bloków
  2. Nie będzie dwóch bloków o tym samym numerze
  3. Wszystkie bloki zostaną otoczone ścianami
  4. Siatka jest prostokątna
  5. 0Blok jest na tyle duża, aby pokryć wszystkie kwadraty bramkowych.
  6. Istnieje prawidłowe rozwiązanie

Musisz zwrócić sekwencję ruchów, która spowoduje umieszczenie 0bloku tak, aby obejmował wszystkie pola bramkowe. Bloki nie mogą przechodzić przez ściany ani inne bloki. Dla powyższej układanki byłaby odpowiednia sekwencja

2L,1R,1R,1D,0R,0R,0R

podczas gdy reprezentuje przesunięcie 2bloku 1 kwadrat w lewo, 1blok 2 kwadraty w prawo (u góry bramki), a następnie 1 kwadrat w dół, a następnie 0blok 3 kwadraty w prawo.

W rzeczywistości istnieje kilka sekwencji, które będą działać na powyższy problem, a wyprodukowanie dowolnej z nich jest dopuszczalne. Twoje rozwiązanie powinno być optymalne, co oznacza, że ​​powinno stworzyć sekwencję, która rozwiązuje zagadkę w jak najmniejszej liczbie kroków.

Sekwencja powinna być wydrukowana jak powyżej, ale może być oddzielona przecinkiem, nową linią lub spacją. Nie obchodzi mnie, czy są przecinki lub białe spacje. Powinieneś wytworzyć wynik w rozsądnym czasie (maksymalnie 120 sekund na poniższych łamigłówkach).

Puzzle 1:

..####..
..#00#..
###00###
#......#
#.1122.#
##3124##
.#3344#.
.##55##.
..#gg#..
..####..

Puzzle 2:

######
#1002#
#1002#
#3445#
#3675#
#8gg9#
######

Puzzle 3:

.####.
##1g##
#22g3#
#4255#
#4.56#
#.006#
#7008#
######

Puzzle 4:

.####.
##00##
#.00g#
#.0.1#
#..g2#
######

To jest golf golfowy, więc wygrywa najkrótsze rozwiązanie (w bajtach)!

Nathan Merrill
źródło
Tylko myśl - czytając to, znalazłem coś nieco mylącego. Cele, będąc „ukrytymi”, były czasami trudne do zauważenia. W twoim przykładzie można je „odgadnąć” z rozsądną dokładnością, jednak w przypadku, gdy blok całkowicie pokrywa cel, powinieneś mieć sposób na wyraźne określenie całego celu. Co jeśli: litery do bloków, wielkie litery, gdy to miejsce jest na bramce? . za miejsce, * za cel? wszystko inne tak samo? czy byłoby to bardziej jasne?
Ditto,
@Ditto nigdy nie ma miejsca, w którym blok zaczyna się na polu bramkowym. Ostatni przykład ma po prostu dwa niepołączone pola bramkowe.
Nathan Merrill
Czy możemy założyć, że każda łamigłówka wejściowa ma rozwiązanie?
orlp
@orlp tak, dodam to do opisu problemu.
Nathan Merrill
@NathanMerrill Aby upewnić się, że robimy wszystko poprawnie, czy możesz dodać optymalną liczbę ruchów dla puzzli 1-4?
orlp

Odpowiedzi:

5

Python, 1761

Niby spłonęło to pytanie, więc nie mogłem zmusić się do gry w golfa. Tak czy inaczej, teraz jest to jedyne rozwiązanie, które rozwiązuje wszystko w terminie (najdłuższy, # 3, zajmuje 27 sekund).

pieces = {}
taken = set()
goals = set()

y = 0
while True:
    try:
        for x, c in enumerate(input()):
            if c == ".": continue
            if c == "g":
                goals.add((x, y))
            else:
                if c in "0123456789":
                    if c not in pieces: pieces[c] = set()
                    pieces[c].add((x, y))
                taken.add((x, y))

        y += 1

    except: break

def translate_comp(coords):
    o = min(sorted(coords))
    return set((c[0] - o[0], c[1] - o[1]) for c in coords)

similar = {}
for piece in pieces:
    k = tuple(translate_comp(pieces[piece]))
    if k not in similar: similar[k] = []
    similar[k].append(piece)


seen = set()
states = [(pieces, taken, ())]
while states:
    state = states.pop(0)
    if not goals - state[0]["0"]:
        names = {
            (-1, 0): "L",
            (1, 0): "R",
            (0, 1): "D",
            (0, -1): "U",
        }

        print(len(state[2]))
        print(" ".join(piece + names[d] for d, piece in state[2]))
        break

    for piece in pieces:
        for d in ((-1, 0), (1, 0), (0, 1), (0, -1)):
            new_pieces = state[0].copy()
            new_pieces[piece] = {(c[0] + d[0], c[1] + d[1]) for c in state[0][piece]}
            new_taken = state[1] - state[0][piece]

            # Collision
            if new_pieces[piece] & new_taken:
                continue

            gist = tuple(frozenset().union(*(new_pieces[piece] for piece in similar_set))
                         for similar_set in similar.values())

            if gist in seen:
                continue

            seen.add(gist)
            new_taken |= new_pieces[piece]
            states.append((new_pieces, new_taken, state[2] + ((d, piece),)))
orlp
źródło
Wow świetne! I na pewno nie w najszybszym języku
edc65,
Wydaje się to zupełnie inne podejście i nie rozumiem dobrze Pythona. Ale podoba mi się pomysł znalezienia elementów o tym samym kształcie. To może znacznie zmniejszyć przestrzeń odwiedzanej pozycji w moim kodzie. Czy mogę pożyczyć to dla mojego rozwiązania?
edc65,
@ edc65 Pewnie. Nie jest to jednak inne podejście, przeprowadzam również pierwsze wyszukiwanie - po prostu nie zaglądam dwa razy do tej samej planszy (i bloki o tym samym kształcie są liczone jak ta sama plansza).
orlp
4

JavaScript (ES6), 446 388

Szerokość Pierwsze wyszukiwanie, więc pierwsze znalezione rozwiązanie jest najkrótsze.
Chociaż nadal uważam, że to dobre rozwiązanie, nie jest wystarczająco dobre. Nawet po sprawdzeniu milionów pozycji (czas działania kilka minut) nie mogłem znaleźć rozwiązania na przykład 2 i 3.

Edytuj zmodyfikowaną wersję ES6 aby przekroczyć limit czasu wykonywania javascript. Puzzle 3 rozwiązane w 7 minut, 145 kroków. Puzzle 2 rozwiązane w 10 minut, 116 kroków

Edytuj 2 Duże przyspieszenie, używając pomysłu @ orlp, by uważać za równe dowolne dwa bloki o tym samym kształcie (wyłączając blok „0”, który jest specjalny). Zmniejsza to przestrzeń odwiedzanych pozycji podczas BSF. Na przykład dla łamigłówki 2 każda pozycja z zamienionym blokiem 1, 2, 3 lub 5 jest naprawdę taka sama.

Czas: najdłuższy jest układanka 3, ~ 20 sekund na moim laptopie.

Użyj Firefoksa, aby przetestować nowy JsFiddle .

F=g=>(o=>{
for(u=[i=s=''],v={},h=[],b={},k={'.':-1},l={},
g=[...g].map((c,p)=>c>'f'?(h.push(p),'.'):c<'0'?c:
l[k[c]?k[c]+=','+(p-b[c]):k[b[c]=p,c]=~(c>0),k[c]]=c),
b=Object.keys(b),b.map(c=>k[c]=l[k[c]]);
h.some(p=>g[p]!='0');[s,g]=u[++i])
b.map(b=>[-1,1,o,-o].map((d,i)=>
g.every((c,p)=>c!=b?1:(c=g[p+d])!=b&c!='.'?0:m[g[p-d]!=b?m[p]='.':1,p+d]=b,m=g.slice(0))
&&!v[q=m.map(c=>k[c]||'')+'']?v[q]=u.push([s+b+'LRUD'[i]+' ',m]):0))
})(o=~g.search(/\n/))||s

Przestarzały

EcmaScript 6 (FireFox) JSFiddle

EcmaScript 5 (Chrome) JSFiddle

Przykład

#######
#001gg#
##.222#
.######
T(ms) 10,Len7
1R 0R 1R 0R 2L 1D 0R

Łamigłówka 1

..####..
..#00#..
###00###
#......#
#.1122.#
##3124##
.#3344#.
.##55##.
..#gg#..
..####..

T(ms) 8030,Len70
1U 2U 3U 4U 5U 5L 4D 2R 1R 3U 5U 4L 4D 5R 5R 3D 1L 3D 1L 5L 5U 5U 2D 5R 
1R 5R 1R 1D 0D 4D 1D 0D 0L 0L 1U 1U 1U 1U 2L 2L 2U 5D 2R 0R 3R 3R 0D 0D
2L 2L 2L 5U 0U 3U 3U 4U 4U 4R 0D 3L 3U 5D 5L 5L 5L 4U 4U 0R 0D 0D

Puzzle 2

######
#1002#
#1002#
#3445#
#3675#
#8gg9#
######

T(ms) 646485, Checked 10566733, Len 116
8R 3D 4L 7U 9L 5D 7R 4R 3U 8L 9L 5L 7D 4R 6U 9U 8R 3D 6L 4L 2D 7D 2D 0R
1R 6U 6U 3U 3U 9L 8L 5L 7L 7U 2D 4R 5U 8R 8R 5D 1D 6R 3U 9U 5L 1D 1D 9R
9U 4L 4L 2U 8R 7D 2L 8U 7R 2D 4R 3D 6L 9U 4R 1U 1U 2L 8L 8D 4D 0D 9R 6R
3U 9R 6R 1U 5U 2U 8L 8L 7L 7L 4D 0D 6D 6R 1R 2U 2U 0L 6D 9D 6D 9D 1R 2R
3R 5U 5U 0L 9L 6U 4U 7R 8R 7R 8R 0D 9L 9L 6L 6L 4U 8U 8R 0R

Puzzle 3

.####.
##1g##
#22g3#
#4255#
#4.56#
#.006#
#7008#
######

T(ms) 433049, Checked 7165203, Len 145
3L 3U 5U 6U 0U 7U 8L 8L 8L 0D 0R 7R 7U 7R 4D 2D 8R 4D 2D 5L 5L 3D 1R 3R
1D 1D 5R 5U 3L 6U 2U 4U 7R 1D 8L 0L 7D 1R 2R 4U 4U 8U 8U 0L 2D 3D 3L 6L  
1U 7D 2R 0R 8D 4D 8D 4D 3L 3U 4U 4R 8U 8U 0L 7L 2D 1D 6R 4R 4U 1L 1L 1U
2U 2L 6D 6D 4R 1R 1U 2U 2L 6L 6U 4D 1R 6U 7U 7U 0R 8D 0R 2D 3D 8D 2D 3D
7L 6D 5D 5L 1L 1U 1L 6U 4U 7R 7R 6D 6L 4L 4U 7U 7U 0U 0U 2R 3D 2R 3R 3D 
6D 5D 1D 1L 4L 7L 7U 0U 2U 3R 6D 5D 4D 7L 3R 6R 8R 5D 4D 7D 4L 7D 7D 0L 
0U

Puzzle 4

.####.
##00##
#.00g#
#.0.1#
#..g2#
######

T(ms) 25,Len6
1L 1D 1L 1L 0D 0R
edc65
źródło
Czy możesz zweryfikować swoje rozwiązanie (i inne rozwiązania), czy możesz zaksięgować liczbę ruchów, które otrzymasz dla każdego opublikowanego problemu?
Nathan Merrill