Kiedy byłem chłopcem, dzieciaki wędrowały do sklepów komputerowych i grały w Hunt the Wumpus, dopóki nas nie wyrzucili. To była prosta gra, programowalna na domowych komputerach z połowy lat 70. XX wieku, na maszynach tak podstawowych, że zamiast mikroprocesorów wielkości kurcząt, myślę, że niektóre z nich prawdopodobnie miały tam prawdziwe kurczęta.
Wywołajmy minioną epokę, odtwarzając grę na nowoczesnym sprzęcie.
Gracz zaczyna w losowym pokoju na mapie dwudziestościennej (w ten sposób w sumie jest 20 pokoi połączonych ze sobą jak twarze dwudziestościanu, a każdy pokój ma dokładnie trzy wyjścia).
Wumpus rozpoczyna się w losowo wybranym innym pokoju. Wumpus śmierdzi, a jego zapach można wykryć w dowolnym z trzech pomieszczeń sąsiadujących z jego lokalizacją, chociaż kierunek zapachu jest niemożliwy do ustalenia przez gracza. Gra informuje tylko, że „czujesz wumpusa”.
Gracz nosi łuk i nieskończoną liczbę strzał, które może wystrzelić w dowolnym momencie do pokoju przed sobą. Jeśli wumpus jest w tym pokoju, umiera, a gracz wygrywa. Jeśli wumpusa nie było w tym pokoju, jest zaskoczony i porusza się losowo do dowolnego z trzech pokoi połączonych z jego bieżącą lokalizacją.
Jeden losowo wybrany pokój (na pewno nie jest to pokój, w którym gracz się rozpoczyna) zawiera dół bez dna. Jeśli gracz znajduje się w dowolnym pomieszczeniu przylegającym do dołu, odczuwa powiew wiatru, ale nie ma pojęcia, z jakich drzwi pochodzi wiatr. Jeśli wejdzie do pokoju z jamą, umiera, a Wumpus wygrywa. Wumpus nie ma wpływu na jamę.
Jeśli gracz wejdzie do pokoju Wumpusa lub jeśli Wumpus wejdzie do pokoju gracza, Wumpus wygra.
Gracz określa kierunek, w którym patrzy, za pomocą liczby (1 = prawa, 2 = lewa, 3 = wstecz), a następnie akcji (4 = strzał w strzałę, 5 = idź w określonym kierunku).
Dla celów punktacji każdy ciąg gry („Czujesz powiew”, „Czujesz wumpus”, „Twoja strzała niczego nie trafił” itp.) Można uznać za jeden bajt. Nie nadużywaj tego, aby ukryć kod gry w tekście; służy tylko do interakcji z odtwarzaczem.
Poświęć 10% swojego bajtu na wdrożenie megabatów, które zaczynają się w losowym pokoju innym niż gracz (chociaż mogą dzielić pokój z wumpusem i / lub jamą). Jeśli gracz wejdzie do pokoju z nietoperzami, nietoperze przeniosą gracza do innego losowo wybranego pokoju (na pewno nie będzie to pokój z jamą lub wumpusem), zanim odlecą do swojej nowej, losowej lokalizacji. W trzech pokojach sąsiadujących z nietoperzami słychać skrzypienie, ale gracz nie otrzymuje informacji o tym, z którego pomieszczenia pochodzi dźwięk.
Poświęć 35% liczby bajtów na wdrożenie interfejsu graficznego, który pokazuje mapę dwudziestościenną i pewnego rodzaju informację, jaką gracz dotychczas posiadał na temat lokalizacji dołu, wumpusa i nietoperzy (jeśli dotyczy), w stosunku do gracz. Oczywiście, jeśli wumpus się poruszy lub gracz zostanie poruszony przez nietoperze, mapa musi zostać odpowiednio zresetowana.
Najniższa liczba bajtów, po skorygowaniu, wygrywa.
Podstawowy kod źródłowy wersji gry (niekoniecznie zgodny z powyższymi regułami, a w każdym razie całkowicie nie golfowym) można znaleźć na stronie tej stronie i prawdopodobnie w innych.
źródło
Odpowiedzi:
GolfScript, 163
Wynik jest uzyskiwany przez pobranie liczby bajtów (290), dodanie liczby ciągów używanych do interakcji z użytkownikiem (6) i odjęcie łącznej długości tych ciągów (133). Kanały są częścią ciągów i przyczyniają się do zliczania bajtów.
Kamienie milowe
Przeniesiono odpowiedź professorfish z Bash na GolfScript. Wynik: 269
Działał zgodnie z sugestiami Petera Taylora zawartymi w komentarzach. Wynik: 250
Peter Taylor przeredagował cały mój kod i pomógł mi skompresować tabelę wyszukiwania. Wynik: 202
Zastąpiono tabelę wyszukiwania sąsiednich pokoi matematycznym podejściem. Wynik: 182
Refaktoryzowane dane wejściowe, wyjściowe i funkcja wspierająca podejście matematyczne. Wynik: 163
Wielkie „Dziękuję!” Dla Petera Taylora za całą jego pomoc.
Jak to działa
20 pokoi jest reprezentowanych jako wierzchołki dwunastościanu, którym przypisano numery od 0 do 19 w następujący sposób:
Aby znaleźć pokoje przylegające do pokoju N i uporządkować je zgodnie z ruchem wskazówek zegara, musimy wziąć pod uwagę cztery przypadki:
Jeśli N ≡ 0 mod 4 (niebieskie wierzchołki), sąsiedni pokój to 19 - N , N + 2 mod 20 i N - 2 mod 20 .
Jeśli N ≡ 1 mod 4 (zielone wierzchołki), sąsiedni pokój to 19 - N , N - 4 mod 20 i N + 4 mod 20 .
Jeśli N ≡ 2 mod 4 (żółte wierzchołki), sąsiedni pokój to 19 - N , N - 2 mod 20 i N + 2 mod 20 .
Jeśli N ≡ 3 mod 4 (czerwone wierzchołki), sąsiednie pomieszczenie to 19 - N , N + 4 mod 20 i N - 4 mod 20 .
źródło
Q
z19rand 97+
; 2 w@
z97%3*&>
..., kolejny 1 przez inlineQ
jak{19rand 97+}2*:,\:H
, kilka zastępując|
z*
, który jest często najlepszym sposobem, aby zrobićif
.B
nie ma żadnego sensu i myślę, że kilka innych zmiennych można by wyeliminować za pomocą stosu.256base 20base
(i prawdopodobnie również wyeliminować kilka +/- 97). Jedynym minusem jest to, że będzie wymagał znaków niedrukowalnych.You were killed by the wumpus
bez żadnej wzmianki o strzale. Właśnie dlatego dołączałem w nie ładnej wersji.2*2+
=>)2*
REV0 C ++ (Visual Studio w systemie Windows) 405Poniżej znajduje się przegląd gry, pokazujący, że (pod warunkiem, że nie zaczniesz tuż przy ryzyku) z prawidłową grą, zawsze możesz wygrać. Gracz odczuwa powiew wiatru, zawraca i wykonuje pełną pętlę przeciwnie do ruchu wskazówek zegara. Ponieważ zajmuje mu dokładnie 5 ruchów, aby znów poczuć powiew wiatru, zna dziurę po swojej prawej stronie i oddala się jak najdalej. Podobnie, gdy wącha wumpusa, nie wiedząc, czy jest on prawy czy lewy, odwraca się i wykonuje pętlę zgodnie z ruchem wskazówek zegara. Ponowne wyczucie wumpusa zajmuje mu 5 ruchów, więc wie, że jest po lewej stronie i strzela z pewnością.
Gdyby zapętlił w drugą stronę, szybciej znalazłby wumpusa i wiedziałby, że jest w tym samym kierunku, w którym się obraca.
REV1 C (GCC na Cygwin), premia 431-35% = 280,15Dodano nowe linie dla przejrzystości. Zmiany w stosunku do wersji 0 są następujące:
Ogromne podziękowania dla @Dennis za zalecenie kompilatora GCC w emulatorze Cygwin Linux dla systemu Windows. Ten kompilator nie wymaga
include
s w programie rev 0 i pozwala na domyślnyint
typ zmiennych imain.
To jest zmieniająca życie wskazówka golfowa!Dodatkowo uruchomienie w systemie Linux powoduje, że
\f
kursor przesuwa się w dół bez powrotu karetki (w przeciwieństwie do systemu Windows, w którym po prostu wyświetla symbol do wydrukowania). Pozwoliło to na znaczne skrócenie instrukcji printf drukującej tablicęKilka dodatkowych wskazówek od Dennisa w komentarzach i jedna z moich: zmiana stanu podczas sprawdzania, czy strzałka uderzyła w wumpusa:
if(q==w)
>if(q-w)
(..else .. jest odwrócona)Dodanie graficznego wyświetlacza pokazującego informacje, które gracz wie o tym, gdzie pachnie wumpus / czuje się bryza, aby otrzymać 35% premii. (Usunąłem starą wersję tego debugowania, która pokazywała dokładną pozycję wumpusa i dziury. Można to zobaczyć w historii edycji).
REV2 C (GCC na Cygwin), bonus 389-35% = 252,85
Jeszcze raz dziękuję Dennisowi za refaktoryzację mojego kodu:
Stała Char
m[]
zastąpiona literałami (nie wiedziałem, że można indeksować literał.)Ziarno liczb losowych zmienną stosową (zależne od systemu, niektóre systemy losowo przydzielają pamięć jako środek bezpieczeństwa).
Makro z
puts
zastąpionym makrem zprintf
dodatkowym kodem, który należy wykonać, gdy wyświetlany komunikat umieszcza się wewnątrzprintf
argumentów (zaletą tej strony jest to, że printf nie drukuje kilku ostatnich argumentów, jeśli w ciągu formatu nie ma wystarczającej liczby specyfikatorów formatu).if
zastąpione przez||
Obliczanie nowej pozycji gracza / wumpus umieszczonej w nowym makrze.
Wygrywaj / przegrywaj wiadomości umieszczone poza
while
pętlą.if
zastąpiony przez operatora warunkowego.Zastosowanie operatora warunkowego w linii do strzelania strzałą. Jeśli gracz nie trafi, wymaga to zarówno wydrukowania wiadomości, jak i dostosowania pozycji wumpus. Dennis zaproponował kilka sposobów łączenia
printf
i obliczania pozycji wumpusa w jednym wyrażeniu, ale wybrałem jeden z moich własnych.printf
zwraca liczbę wydrukowanych znaków, czyliYour arrow didn't hit anything\n
31 (11111 binarnie.) Tak więc31&Q(w)==Q(w)
.Mój inny wkład w tę edycję polegał na wyeliminowaniu niepotrzebnych nawiasów.
Wydajność
Tutaj gracz już odkrył, gdzie jest Wumpus, ale decyduje się na dokładną eksplorację, aby dowiedzieć się, gdzie dokładnie jest dół. W przeciwieństwie do mojej starej wersji debugowania, która pokazywała, gdzie wumpus i pit były w trakcie gry, pokazuje to tylko pokoje, w których gracz odwiedził i poczuł powiew (1), który wyczuł wumpus (2) lub oba (3). (Jeśli gracz strzela strzałą i chybia, zmienna
a
zawierająca informacje o pozycji wumpus zostaje zresetowana.)REPREZENTACJA ICOSAHEDRON
Uwaga: ta sekcja oparta jest na wersji 1
Moja funkcja gwiazdy! W moim kodzie nie ma wykresu. Aby wyjaśnić, jak to działa, zobacz mapę świata poniżej. Dowolny punkt na dwudziestościanie może być reprezentowany przez szerokość 0–3 i długość 0–4 (lub pojedynczą liczbę
long*4+lat
.) Linia długości oznaczona na mapie przechodzi tylko przez te twarze o długości zero, a linia szerokości przechodzi przez środek twarzy o zerowej szerokości geograficznej.Gracz może być zorientowany na 3 możliwych osiach, reprezentowanych następującymi symbolami: północ-południe
-
północny wschód-południowy zachód\
północny zachód-południowy wschód/
. W każdym pokoju ma dokładnie jedno wyjście na każdej z dostępnych mu osi. Na pokazanym ekranie odtwarzacz wykonuje pełną pętlę zgodnie z ruchem wskazówek zegara. Generalnie łatwo jest zidentyfikować na podstawie oznaczenia gracza, skąd pochodził, a zatem gdzie może się udać.Jedynym przypadkiem, który jest nieco trudny dla niewtajemniczonego oka, jest czwarty. Kiedy zobaczysz nachylenie w jednym z tych biegunowych rzędów, gracz wyszedł z komórki polarnej najbliższej zewnętrznego końca skosu i jest skierowany ogólnie w kierunku równika. Tak więc gracz jest skierowany na południowy wschód, a jego opcje to: 15 (POŁUDNIOWA, komórka po prawej) 25 (północno-wschodnia, komórka powyżej) lub 35 (północno-zachodnia, komórka poniżej).
Zasadniczo odwzorowuję dwudziestościan na siatkę 5x4, z komórkami ponumerowanymi od 19 do 0 w kolejności, w jakiej są drukowane. Ruch wykonuje się przez dodanie lub odjęcie bieżącej pozycji, w zależności od szerokości i kierunku gracza, zgodnie z tabelą poniżej.
Jeśli gracz zejdzie z dolnej (zachodniej) planszy, wraca na górną (wschodnią) stronę i odwrotnie, więc jego pozycja jest przejmowana modulo 20. Zasadniczo ruchy są kodowane do m [] przez dodanie ascii 80 (
P
) do wartości surowej, podając znaki przedstawione poniżej, ale zasadę można dodać dowolną wielokrotność 20 bez wpływu na operację.Dane wejściowe gracza (podzielone przez 10, aby usunąć drugą cyfrę) są dodawane do jego bieżącego kierunku i pobierane modulo 3, aby uzyskać jego nowy kierunek. To działa dobrze w większości przypadków. Jednak jest problem, gdy jest on w pokoju polarnym i zbliża się do bieguna. Podczas składania mapy poniżej będzie jasne, że jeśli opuści pokój skierowany na „północny wschód”, wejdzie na nowy kwadrat skierowany na „południowy wschód”, więc należy dokonać korekty. Odbywa się to w linii
e=(d+i/10)*m[p%4]%3;
przez pomnożenie przezm[p%4]
. Pierwsze cztery wartości m [] są wybrane w taki sposób, że oprócz ich powyższej funkcji mają także charakterystykęm[1]%3==m[2]%3==1
im[0]%3==m[3]%3==2
. Pozostawia to kierunek samemu dla pomieszczeń równikowych i stosuje niezbędną korektę dla pomieszczeń polarnych.Logicznym czasem na dokonanie korekty byłby ruch. Jednak aby zapisać postacie, należy to zrobić przed ruchem. Dlatego niektóre wartości wm [] muszą zostać przetransponowane. Ostatnie 2 znaki są na przykład
LT
zamiast wTL
powyższej tabeli.KOD NIEGOLFOWANY
jest to kod rev 1, który jest mniej zaciemniony niż rev 2.
To będzie działać na GCC / Linux. W komentarzach umieściłem dodatkowy kod potrzebny do uruchomienia go w Visual Studio / Windows. To duża różnica!
ZAGADNIENIA I CIEKAWOSTKI
Wykorzystałem punkt wspomniany przez @professorfish, jeśli wumpus i pit startują w losowych miejscach, nie ma potrzeby, aby gracz zaczynał w losowym miejscu. Gracz zawsze zaczyna od pokoju 19 skierowanego na północ.
Rozumiem, że ponieważ wumpus jest „niewrażliwy na otchłań”, wumpus może rozpocząć lub wejść do pokoju, w którym znajduje się otchłań. Zasadniczo upraszcza to sprawy z wyjątkiem jednego punktu. Nie mam konkretnej zmiennej wskazującej, że gra się skończyła; kończy się, gdy gracz zbiega się z wumpusem lub pitem. Kiedy więc gracz wygrywa, wyświetlam komunikat o zwycięskiej wygranej, ale przesuwam dół do gracza, aby wyjść z pętli! Nie mogę wsadzić gracza do dołu, ponieważ może tam być Wumpus i dostanę wiadomość o Wumpusie, której nie chcę.
Rev0program działał doskonale w studiu wizualnym, ale IDE powiedział „stos uszkodzony wokół zmiennej i” przy wyjściu. To dlatego, scanf próbuje umieścić
int
wchar.
Dennis podano nieprawidłowe zachowanie na swoim komputerze z systemem Linux z tego powodu. W każdym razie jest to naprawione przez użycie poprawnego typu w wersji 1.Linia do wyświetlania planszy w wersji 0 jest niezdarna i wygląda nieco inaczej na innych platformach. W Rev 1 ma rewizję tej linii, która używa znaku \ f formfeed i dlatego nie potrzebuje znaku formatu na początku printf. To sprawia, że jest krótszy, ale \ f nie działa w systemie Windows.
printf(" %c%c%c")
środku% c jest wyświetlany znak do wydrukowania. Ostatni% c to ASCII 0 lub ASCII 10 (\ n, nowa linia ze znakiem powrotu karetki w systemie Windows.) Wygląda na to, że w systemie Windows nie ma znaku, który działałby w konsoli, który przejdzie w dół linii bez podania znaku powrotu karetki. Gdyby tak było, nie potrzebowałbym pierwszej c% (ASCII 0 lub ASCII 9 przed znakiem szerokości geograficznej 1. Zakładki są notorycznie niezdefiniowane w swoim zachowaniu). Wiodące miejsce poprawia formatowanie (umieszcza znaki szerokości 3 i 2 bliżej znaku szerokości 1 .)źródło
scanf_s
zescanf
i tostdio.h
jeśli mogę skompilować jak C ++ Rater niż C), ale to nie dość pracy dla mnie. Na przykład, jeśli pójdę w lewo, a potem w prawo na początku (15 35
), znajdę się w innym pokoju niż ten, w którym zacząłem.i
jest rzeczywiście problemem. Strona człowiek mówi: „ d zestawienia ewentualnie podpisane całkowitą dziesiętną; Następny wskaźnik musi być wskaźnik do int .” Zmiana typu sprawia, że działa dobrze.NULL
się0
iscanf_s
zscanf
, nie trzebaint
wcześniejmain
i można poruszaći
id
poza main (domyślnie oneint
i są inicjowane0
). Ponadto, można określićp=19,h=rand()%p,w=rand()%p
, wymienićm[]
się*m
i powinno być możliwe do zdefiniowania makra dla wszystkich instancjiif(...==...)puts(...);
.GolfScript, 269 znaków
Zauważ, że 163 odjęto od liczby znaków dla zakodowanych ciągów. Jeśli chcesz, aby wynik debugowania wskazywał numery pokojów, dodaj następujący wiersz zaraz po pierwszym wystąpieniu
^
:Przykładowa sesja (z dodatkowym wyjściem debugowania):
źródło
{puts}:|;
, 5 znaków, zastępując jeR
i zaW
pomocą-
i>
(pozwala wyeliminować otaczające spacje) i 9 znaków, upuszczając'> 'print
(nie wydaje się, żeby pytanie to wymagało).JavaScript (ECMAScript 6) -
21971759 -45% = 967,45 znakówPrawie skończyłem grać w golfa ...
Zawiera GUI z mapą Icosahedral i Mega-Bats dla pełnych bonusów.
X
( dół );B
(Mega-Bat);W
(Wumpus); iP
(Ty).W
iP
można klikać tylko w pokojach sąsiadujących z bieżącą lokalizacją.Kod:
źródło
Bash, 365 (pierwsza działająca wersja 726!)
ŁĄCZENIE Z GOLFSCRIPT?
@Dennis w zasadzie zrobił dla mnie całą grę w golfa. Dzięki!
Program zakłada prawidłowe wejście. Prawidłowym wprowadzeniem jest wybrany kierunek (1 dla prawej, 2 dla lewej, 3 dla tyłu), a następnie twoja akcja (4, aby strzelać, 5, aby iść).
Niektóre wyjaśnienia
Zwykle robię duże szczegółowe objaśnienia, ale jest to prawdopodobnie zbyt skomplikowane, żebym się tym przejmował.
Każdy wierzchołek na wykresie dwunastościanu jest kodowany jako litera (a = 1, b = 2, ... t = 20).
Pozycja początkowa gracza wynosi zawsze 20 (i stoją plecami do 18), ponieważ to nie ma znaczenia samo w sobie, liczą się tylko względne pozycje gracza, pit i wumpus.
Zmienna
$p
przechowuje lokalizację gracza.$r
przechowuje poprzednią lokalizację gracza.$w
jest wumpus i$h
(H dla dziury) to dół.Kod
Historia wersji
grep -oE
zmienną. Zapisano 5 znaków.[a-z]{3}
zmienną. Zapisano 3 znaki.echo
zmienną. Zapisano 5 znaków.$m
.grep
i będąc nieco bardziej rozsądnym.C
jako funkcja wyszukiwania wyrażenia regularnego do użycia w instrukcjach if orazE
jako funkcja wypisująca „Zabiłeś wumpusa” i wychodząca.d
i usuwając niepotrzebne nawiasy.Przykładowy przebieg
Wprowadzane jest „In:”, „Out: is output”.
Gracz błąka się trochę, wącha wumpusa i strzela. Tęsknią, a wumpus wchodzi do ich pokoju i je je.
źródło
exit
jest tylko jeden bajt dłuższyg=1
i eliminuje potrzebę testowania niezerowychg
i niektórychelif
instrukcji. 2. Możesz używać((i==35))
zamiast[ $i = 35 ]
i...&&...
zamiastif ... then ... fi
. 3.q(){ L=({a..s});$j ${L[RANDOM%19]};}
in=`$k $w$m<<<$d`;w=${n:RANDOM%2+1:1}
oba oszczędzają kilka bajtów.while :;do
...done
zfor((;;);{
...}
dla oszczędności 3 chard(){ x=npoemfgnshtoksblbtckpdpljqniorelgfhkbqraicadjaghimsmjtqecrdf;s=${x:3*30#$1-30:3};}
pozwoli ci zastąpić definicjes
in
przy pomocyd $p
id $w
. Jeśli ponadto określiću=${s#*$r}$s
(i dostosować definicjel
if
Odpowiednio), nie trzeba będzie$k
i$m
już. Myślę, że oszczędza 83 bajty. Również miejsce wq ()
nie jest wymagane.c(){ [[ $1 =~ $2 ]];}
i zastępując np. drugą do ostatniej liniic $r $b||{ $j You missed;d $w;w=${s:RANDOM%2+1:1};}
.b=$p
zd $p;u=u${s#*$r}$s
linie poread i
zy=${u:i/10:1};C $i 5&&{ p=$y;r=$b;}||{ d $w;C $y $w&&$j You killed the wumpus&&exit;$j You missed;w=${s:RANDOM%2:1};}
i pozbycie sięE()
.GolfScript (
206198)W końcu dogonił wersję tabeli odnośników Dennisa, z której sporo się pożycza. Ciekawą rzeczą w tej wersji jest to, że nie ma tabeli odnośników do układu pokoju.
W 60 o symetrii obrotowej o dwudziestościanu są izomorficzne z grupy przemiennego 5 liter, A_5. Po wypróbowaniu wszystkich podejść do zwięzłego reprezentowania grupy wróciłem do najprostszego: każdy element jest permutacją parzystej parzystości. Grupę można wygenerować z dwóch generatorów na więcej niż jeden sposób: moje podejście wykorzystuje generatory
3
i3 1
. To pozwoli nam na generowanie1 = 3 3 1
,2 = 3 3 1 3 1
i3 = 3
.Zauważ, że kierunek
3
odpowiada elementowi rzędu 2, ponieważ po przejściu przez drzwi za tobą, drzwi te znów są za tobą. Kierunek1
odpowiada elementowi rzędu 5, idąc wokół wierzchołka dwudziestościanu. (Podobnie element2
). A kombinacja3 1
jest rzędu 3, ponieważ krąży wokół pokoi sąsiadujących z pokojem, który zaczyna się za tobą.Szukamy więc permutacji rzędu 2 do reprezentowania kierunku
3
i permutacji rzędu 5 do reprezentowania kierunku1
takiego, który3 1
jest rzędu 3.W A_5 jest 15 permutacji rzędu 2, a dla każdej z nich jest 8 permutacji kandydujących na
1
(a więc na3 1
). Jest oczywistym atrakcją[4 3 2 1 0]
dla3
: odwrócenie tablicę tylko-1%
. Z możliwych możliwych kombinacji permutacji3 1
wybrałem[0 1 3 4 2]
, co dopuszcza dość krótką implementację jako[~@]
.Bez golfa
źródło
10/@3%=
próbuje uzyskać dostęp do czwartego elementu tablicy o długości 3, jeśli dane wejściowe są35
.9/3%@3%=
.9/
zamiast10/
nadal działa, więc dzięki.Wumpus , 384 - 129 (łańcuchy) = 255 bajtów
Wypróbuj online! (Oczywiście TIO nie ma większego sensu, ponieważ nie można tam używać programu interaktywnie, a gdy program skończy się instrukcjami na STDIN, przeczyta
0 0
, co jest równoważne3 4
, więc skończysz strzelanie strzałami, dopóki Wumpus się tam nie przeniesie lub nie zabije.)Uruchamiając to lokalnie, upewnij się, że wysunięcie linii po drugiej liczbie każdego wejścia zostaje opróżnione (ponieważ Wumpus potrzebuje go do ustalenia, że liczba się skończyła). W Powershell muszę jakoś wprowadzić jeszcze jeden znak po wysunięciu wiersza, aby działał (nie ma znaczenia, który znak, ale do testowania użyłem tylko podwójnego wysuwu).
Jest jeszcze dużo miejsca na grę w golfa, ale wypróbowanie zupełnie nowych układów zajmuje trochę czasu. Ostateczny wynik zależy również od rzeczywistych ciągów, których używam, ponieważ w języku 2D ciąg N bajtów kosztuje więcej niż N bajtów kodu źródłowego, ponieważ nakłada znaczne ograniczenia na układ kodu, a ty często trzeba go podzielić na wiele sekcji (co wiąże się z dodatkowymi podwójnymi cudzysłowami). Na końcu, jeśli zredukowałbym każdy ciąg do jednej litery (i -129 do -12), prawdopodobnie zaoszczędziłbym tonę bajtów.
Wyjaśnienie
Najpierw zrzeczenie się odpowiedzialności: pomimo nazwy języka nie zostało ono zaprojektowane tak, aby wdrożenie Hunt the Wumpus było szczególnie łatwe. Zamiast tego po raz pierwszy zaprojektowałem język wokół tematu trójkątów, skończyłem z dwudziestościenną strukturą danych i dlatego nazwałem go Wumpus.
Tak, chociaż Wumpus opiera się głównie na stosie, ma również 20 rejestrów rozmieszczonych wokół powierzchni dwudziestościanu. Oznacza to, że otrzymujemy strukturę danych do reprezentowania mapy za darmo. Jedyne, czego nie możemy zrobić łatwo, to znaleźć określone twarze w dwudziestościanie, więc aby je wyszukać, musimy „rzucać d20”, aż skończymy na szukanej twarzy. (Można to zrobić w sposób deterministyczny, ale zajęłoby to o wiele więcej bajtów.) Wyszukiwanie takich twarzy kończy się prawie na pewno (tj. Z prawdopodobieństwem 1), więc wyszukiwanie trwające wiecznie nie jest problemem w praktyce).
Powyższy kod jest wersją tej pierwszej implementacji w wersji golfowej z rozsądniejszym układem:
Ponieważ gra w golfa polegała głównie na kompresji układu, na razie wyjaśnię tę wersję (dopóki nie dodam żadnych sztuczek golfowych wykraczających poza restrukturyzację kodu).
Zacznijmy od kodu instalacyjnego:
Początkowo wszystkie twarze są ustawione na 0 . Zakodujemy wumpus ustawiając 1-bit odpowiedniej powierzchni, a dół ustawiając 2-bit. W ten sposób oboje mogą znajdować się w tym samym pokoju. Pozycja gracza nie zostanie w ogóle zapisana na dwudziestościanie, zamiast tego zawsze będzie aktywną twarzą (tylko jeden z 20 rejestrów jest aktywny jednocześnie).
Teraz musimy znaleźć losową pustą twarz, aby umieścić gracza.
Następna sekcja sprawdza otoczenie gracza i drukuje odpowiednie ostrzeżenia:
Jest to pętla, przez którą przebiegamy 3 razy. Za każdym razem, gdy patrzymy na prawego sąsiada, drukujemy odpowiednie łańcuchy, jeśli istnieje zagrożenie, a następnie obracamy dwudziestościan o 120 °.
Następna sekcja odczytuje z gracza dwie liczby, a następnie albo przesuwa gracza, albo strzela strzałą. Pierwszy jest trywialny, drugi mniej. Głównym problemem przy strzelaniu do strzały jest przypadek, w którym tęskni. W takim przypadku a) musimy poszukać wumpusa, aby go przenieść, a następnie b) wrócić do pokoju gracza i prawidłowej orientacji dwudziestościanu (tak, aby „powrót” pozostał „z powrotem”). To najdroższa część całego programu.
Punkt wejścia do tej sekcji znajduje
I
się po lewej stronie.Uff, to była trudna część. Teraz musimy tylko sprawdzić, czy gracz umiera, i w przeciwnym razie zacząć od głównej pętli:
Struktura tej sekcji jest zasadniczo identyczna ze strukturą, której użyliśmy podczas sprawdzania otoczenia gracza: sprawdzamy 1-bit bieżącej twarzy (pokój gracza) i jeśli jest ustawiona, drukujemy
The wumpus ate you.
i kończymy program. W przeciwnym razie sprawdzamy 2-bit i po jego ustawieniu drukujemyYou fell into the pit.
i kończymy program. W przeciwnym razie dochodzimy do tego,2.
który przeskakuje z powrotem na początek głównej pętli (na współrzędnych(0, 2)
).źródło
awk - duży
Nie okazało się to tak krótkie, jak się spodziewałem, ale podjąłem nieco inne podejście do wykresu, więc i tak publikuję wersję bez golfa.
Skorzystałem z faktu, że dwudziestościan (wielościenny wielościan) pod rotacjami zachowujący orientację jest izomorficzny w stosunku do naprzemiennej grupy stopnia 5 (permutacje 5-elementowe o parzystej liczbie cykli o parzystej długości). Następnie wybieram dwie permutacje o długości cyklu 5 jako „lewą” i „prawą”, i wybieram jedną permutację o długości cyklu 2 jako „wstecz”. Korzystając z nich, buduję wykres z jednego pokoju, idąc ścieżką hamiltonowską (2xRRRLLLRLRL, używając 3xRB w każdym pokoju, aby uchwycić 3 możliwe kierunki).
źródło