Gra BattleBlock Theatre czasami zawiera układankę, która jest uogólnioną wersją Lights Out . Masz trzy sąsiadujące bloki, z których każdy wskazuje poziom od 1 do 4 włącznie z paskami, np .:
|
||||
||
Jeśli dotkniesz bloku, to ten blok, podobnie jak każdy sąsiedni blok, zwiększy jego poziom (zawijając z 4 do 1). Układanka jest rozwiązana, gdy wszystkie trzy bloki pokazują ten sam poziom (nie ma znaczenia, który poziom). Ponieważ kolejność dotykania bloków nie ma znaczenia, oznaczamy rozwiązanie według częstotliwości dotykania każdego bloku. Optymalnym rozwiązaniem dla powyższych danych wejściowych byłoby 201
:
| --> || --> ||| |||
|||| | || |||
|| || || --> |||
Gra bardzo łatwo generalizuje dowolną liczbę bloków, chociaż w przypadku niektórych liczb nie wszystkie konfiguracje są rozwiązywalne.
Wyzwanie
Biorąc pod uwagę sekwencję poziomów bloków, zwróć, jak często każdy blok musi być dotykany, aby rozwiązać zagadkę. Np. Powyższy przykład zostałby podany jako 142
i mógłby dać 201
wynik. Jeśli nie ma rozwiązania, zwróć wybrane, spójne wyjście, które można odróżnić od wszystkich potencjalnych rozwiązań, np. -1
Pusty ciąg.
Możesz napisać funkcję lub program, wziąć dane wejściowe przez STDIN, argument wiersza poleceń lub argument funkcji, w dowolnym dogodnym formacie listy lub ciągu znaków, i podobnie wyprowadzić dane poprzez wartość zwracaną lub drukując do STDOUT.
Twój kod powinien zwrócić poprawne wyniki dla wszystkich przypadków testowych w ciągu minuty na rozsądnej maszynie. (Nie jest to całkowicie ścisły limit, więc jeśli twoje rozwiązanie zajmie minutę i dziesięć sekund, to dobrze, ale jeśli zajmie to 3 minuty, nie będzie. Dobry algorytm łatwo je rozwiąże w kilka sekund.)
To jest kod golfowy, więc wygrywa najkrótsza odpowiedź (w bajtach).
Przykłady
Rozwiązania nie są unikalne, więc możesz uzyskać różne wyniki.
Input Output
1 0
11 00
12 No solution
142 201
434 101
222 000
4113 0230
32444 No solution
23432 10301
421232 212301
3442223221221422412334 0330130000130202221111
22231244334432131322442 No solution
111111111111111111111222 000000000000000000000030
111111111111111111111234 100100100100100100100133
412224131444114441432434 113013201011001101012133
O ile mi wiadomo, istnieją dokładnie 4 rozwiązania dla każdego wejścia, w których liczba bloków wynosi 0 mod 3 lub 1 mod 3, a istnieją 0 lub 16 rozwiązań, w których jest to 2 mod 3.
źródło
Odpowiedzi:
Python 2, 115 bajtów
To jest wersja programu w golfa, którą napisałem podczas omawiania problemu z Martinem.
Dane wejściowe to lista za pośrednictwem STDIN. Dane wyjściowe to lista reprezentująca ostatnie znalezione rozwiązanie, jeśli istnieje rozwiązanie, lub zero, jeśli go nie ma. Na przykład:
Pyth,
3229 bajtówPort obowiązkowy. Dzięki @Jakube za oszczędność 3 bajtów.
Metoda wprowadzania jest taka sama jak powyżej, spróbuj online .
Wyjaśnienie (długie i pełne logiki!)
Po pierwsze, dwie podstawowe obserwacje:
Uwaga 1: Nie ma znaczenia, w jakiej kolejności dotkniesz bloków
Uwaga 2: Jeśli dotkniesz bloku 4 razy, jest to równoznaczne z dotknięciem go raz
Innymi słowy, jeśli istnieje rozwiązanie, wówczas istnieje rozwiązanie, w którym liczba dotknięć wynosi od 0 do 3 włącznie.
Ponieważ modulo 4 jest tak fajny, zróbmy to również z blokami. W pozostałej części tego objaśnienia poziom bloku 0 jest równoważny poziomowi bloku 4.
Teraz oznaczmy,
a[k]
że jest to bieżący poziom blokuk
ix[k]
to, ile razy dotykamy blokuk
w rozwiązaniu. Niech takżen
będzie całkowitą liczbą bloków. Jak zauważył @Jakube, rozwiązanie musi spełniać:gdzie
C
jest ostateczny poziom, na którym kończą się wszystkie bloki, od 0 do 3 włącznie (pamiętaj, że traktujemy poziom 4 jako poziom 0), a wszystkie powyższe równania są naprawdę przystające modulo 4.Oto zabawna część:
0 <= C <= 3
.Istnieją trzy przypadki oparte na liczbie bloków modulo 3. Wyjaśnienie każdego z nich jest takie samo - dla dowolnej liczby bloków istnieje podzbiór bloków, który, jeśli dotkniesz każdego z nich raz, zwiększa wszystkie poziomy bloków o dokładnie 1.
To wyjaśnia, dlaczego istnieją 4 rozwiązania dla
0 mod 3
i1 mod 3
, a zazwyczaj 16 do rozwiązania2 mod 3
. Jeśli masz już rozwiązanie, dotknięcie bloków jak wyżej daje kolejne rozwiązanie, które kończy się na wyższym poziomie bloku (owijanie się).Co to znaczy? Możemy wybrać dowolny końcowy poziom bloku,
C
jaki chcemy! WybierzmyC = 0
, ponieważ oszczędza to bajty.Teraz nasze równania stają się:
I przestawiaj:
Widzimy więc, że jeśli mamy
x[0]
, możemy użyć wszystkich równań oprócz ostatniego, aby się dowiedziećx[k]
. Ostatnie równanie jest dodatkowym warunkiem, który musimy sprawdzić.To daje nam algorytm:
x[0]
x[k]
To daje powyższe rozwiązanie.
Dlaczego więc czasami nie dostajemy rozwiązania
2 mod 3
? Spójrzmy jeszcze raz na te dwa wzory:Rozważmy teraz równania dla tych pozycji, tj. Dla pierwszego:
Dodaj je:
Po drugie:
Dodaj je ponownie:
Więc jeśli
(a[1] + a[4] + a[7] + a[10])
i(a[0] + a[3] + a[6] + a[9])
nie są równi, to nie mamy rozwiązania. Ale jeśli są równe, otrzymujemy 16 rozwiązań. Tak było wn = 11
przypadku, ale oczywiście uogólnia się na dowolną liczbę, którą jest2 mod 3
- weź sumę co trzeciego elementu, zaczynając od drugiego, i porównaj z sumą co trzeciego elementu, zaczynając od pierwszego.Czy w końcu można dowiedzieć się, co
x[0]
musi być, zamiast wypróbować wszystkie możliwości? W końcu, ponieważ ograniczyliśmy nasz poziom docelowyC
do 0, istnieje tylko jeden,x[0]
który daje rozwiązanie w przypadku0 mod 3
lub1 mod 3
(as4 solutions / 4 final levels = 1 solution for a specific final level
).Odpowiedź brzmi tak! Możemy to zrobić dla
0 mod 3
:Co przekłada się na:
Odejmowanie daje:
Podobnie
1 mod 3
możemy zrobić ten wzór:Co daje:
Te oczywiście uogólniają się, rozszerzając indeksy o 3.
Ponieważ
2 mod 3
, ponieważ mamy dwa podzbiory, które obejmują każdy blok, możemy wybrać dowolnyx[0]
. W rzeczywistości dotyczy tox[0], x[1], x[3], x[4], x[6], x[7], ...
(w zasadzie każdego indeksu niezgodnego z2 mod 3
, ponieważ nie są one objęte żadnym podzbiorem).Mamy więc sposób na wybranie
x[0]
zamiast wypróbowania wszystkich możliwości ...... ale zła wiadomość jest taka, że nie oszczędza to na bajtach (124 bajty):
źródło
J
zamiastH
i 2 znaków, jeśli wstawisz ostatni elementPJ
zamiast krojenia.<J_1
.V4J]NVQaJ%_+s>J_2@QN4)I!eJPJB
Pyth,
727673663938 znakówedycja 4: Uświadomiłem sobie, że obliczenia
Q[N]-Q[N+1]+solution[-3]
iQ[-2]-Q[-1]+solution[-3]
ident. Dlatego przeliczam rozwiązanie o 1 i filtruję rozwiązania, gdzie ostatni wpis to 0. Następnie wstawiam ostatni wpis. Na szczęście specjalne przypadki nie wymagają dodatkowego leczenia przy takim podejściu. -27 znakówedycja 3: Stosowanie sztuczek golfowych od postaci FryAmTheEggman: -7
edycja 2: Używając filtru, zmniejszania i mapowania: -3 znak
edycja 1: W mojej pierwszej wersji nic nie wydrukowałem, jeśli nie było rozwiązania. Nie sądzę, że jest to dozwolone, dlatego postać +4.
Oczekuje listy liczb całkowitych jako danych wejściowych
[1,4,2]
i zwraca prawidłowe rozwiązanie,[2,0,1]
jeśli istnieje, w przeciwnym razie pusta lista[]
.Wyjaśnienie:
Niech
Q
będzie lista 5 poziomów iY
lista rozwiązań. Należy uwzględnić następujące równania:Dlatego jeśli używamy dowolny
Y0
iY1
możemy obliczyćY2
,Y3
aY4
w następujący sposób.Niż wszystkie poziomy oprócz ostatniego są równe (ponieważ nie użyliśmy równania
= Q4 + Y3 + Y4
. Aby sprawdzić, czy ten ostatni jest równy innym poziomom, możemy po prostu sprawdzić, czy(Q3 - Q4 + Y2) mod 4 == 0
. Zwróć uwagę, że lewa część będzie wartościąY5
Jeśli obliczę szóstą część rozwiązania, mogę po prostu sprawdzić, czy jest to zero.W moim podejściu po prostu iteruję wszystkie możliwe początki (
[0,0]
, do[3,3]
) i obliczam długość (dane wejściowe) -1 więcej wpisów i filtruję wszystkie rozwiązania, które kończą się na zero.jest to w zasadzie następujące:
następnie filtruję te możliwe rozwiązania pod kątem prawidłowych:
Do tej listy rozwiązań dołączam pustą listę, aby zawierała co najmniej jeden element
i weź pierwsze rozwiązanie
h
, pop ostatni elementp
i wydrukuj goZauważ, że to również działa, jeśli jest tylko jeden blok. W moim podejściu uzyskuję pozycję początkową [0,0] i jej nie przedłużam. Ponieważ ostatni wpis to 0, wypisuje rozwiązanie [0].
Drugi przypadek specjalny (2 bloki) wcale nie jest taki wyjątkowy. Nie jestem pewien, dlaczego wcześniej skomplikowałem sprawę.
źródło
?**lQ]0qhQeQ<lQ3h+f!%-+ePQ@T_3eQ4mu+G]%+&H@G_3-@QH@QhH4UttQd^UT2]Y
ma 66 bajtów. Wydajność została nieco uderzona, ale nadal działa dla mnie największy przypadek testowy w <1s. Pinguj mnie, jeśli chcesz wyjaśnienia niektórych z golfów; w tym komentarzu jest za mało miejsca;) Mam nadzieję, że lubisz korzystać z Pyth: D+<list><int>
ma taki sam efekt jak+<list>]<int>
, więc możesz usunąć pierwszy]
. Również bardzo fajne rozwiązanie.~
? Nie wyglądało na to, kiedy próbowałem~
za
-~<list>]<int>
odpowiadaa<list><int>
.~
is+=
, whilea
is.append()
Ruby,
320313 znakówZdecydowanie można golfa więcej. Nie daje nic dla nierozwiązywalnych łamigłówek.
Wersja bez golfa:
Okej, to było fajne. Oto podstawowy algorytm
{n}
reprezentujący n „dotyku” na liczbie powyżejn
, jak pokazano na jednym z przykładów:Trochę mnie tu utknęło. Jak mogę zamienić
111...1110
ciąg na te same liczby? Porównałem więc moje rozwiązanie i prawidłowe rozwiązanie (uwaga: liczby „dotykowe” wszystkie są o jeden większe niż powinny, ponieważ dane wejściowe są indeksowane 1, podczas gdy dane wyjściowe są indeksowane 0):Zauważyłem, że każda liczba jest o jeden od właściwej
mod 4
, więc oznaczyłem je+
s,-
s i=
s:To działało przez jakiś czas, dopóki nie zauważyłem, że czasem końcowy wynik był
111...11112
lub11...1113
też! Na szczęście wielokrotne stosowanie magicznej formuły, która nie ma sensu, ale prace również je rozwiązały.Więc masz to. Program, który na początku ma sens, ale z czasem staje się coraz bardziej brzydki. Myślę, że to dość typowe rozwiązanie dla golfa kodowego. :)
źródło
exit if (r+=1)>5
na(r+=1)>5&&exit
. Ponadto(code)while cond
składnia jest krótsza niżwhile cond \n code \n end
.Python 2,
294,289,285,281273 bajtówPRÓBNY
Jestem pewien, że można dalej grać w golfa ..
Oto wyniki z przypadków testowych:
Algorytm najpierw upewnia się, że wartości wszystkich bloków oprócz ostatniego bloku są takie same (poprzez iterowanie i dodawanie do „liczeń dotykowych” wszystkich bloków oprócz pierwszych 2). Następnie, jeśli pozwala na to liczba bloków (
(num_of_blocks - 1) % 3 != 1
), wraca i sprawdza, czy wartości pozostałych bloków są zgodne z ostatnim blokiem. Drukuje,x
jeśli nie ma rozwiązania.źródło