Celem tego wyzwania jest napisanie programu potrafiącego odgadnąć słowo w jak najmniejszej liczbie prób. Opiera się na koncepcji programu telewizyjnego Lingo ( http://en.wikipedia.org/wiki/Lingo_(US_game_show) ).
Zasady
Biorąc pod uwagę długość słowa przekazaną jako pierwszy argument w wierszu poleceń, program odtwarzający podejmuje pięć prób odgadnięcia słowa, pisząc zgadnięcie na standardowym wyjściu, a następnie pojedynczy \n
znak.
Po odgadnięciu program na swoim standardowym wejściu otrzymuje ciąg znaków, po którym następuje pojedynczy \n
znak.
Ciąg ma taką samą długość jak słowo do odgadnięcia i składa się z sekwencji następujących znaków:
X
: co oznacza, że danej litery nie ma w słowie do odgadnięcia?
: co oznacza, że dana litera jest obecna w słowie do odgadnięcia, ale w innym miejscuO
: co oznacza, że list w tej lokalizacji został poprawnie odgadnięty
Na przykład, jeśli słowo do odgadnięcia jest dents
, a program wysyła słowo dozes
, otrzyma OXX?O
bo d
i s
są prawidłowe, e
jest niesłuszna, a o
i z
nie są obecne.
Bądź ostrożny, jeśli litera występuje więcej razy w zgadywaniu niż w słowie do zgadnięcia, nie będzie oznaczona jako ?
i O
więcej razy niż liczba wystąpień litery w słowie do zgadnięcia. Na przykład, jeśli słowo do zgadnięcia to cozies
i program wysyła tosses
, otrzyma, XOXXOO
ponieważ jest tylko jedno s
do zlokalizowania.
Słowa są wybierane z angielskiej listy słów. Jeśli słowo wysłane przez program nie jest prawidłowym słowem o prawidłowej długości, próba jest uważana za automatyczną awarię i X
zwracane są tylko te.
Program odtwarzacza powinien zakładać, że plik o nazwie wordlist.txt
i zawierający jedno słowo w wierszu znajduje się w bieżącym katalogu roboczym i można go odczytać w razie potrzeby.
Odgadnięcia powinny składać się wyłącznie z małych liter alfabetu ( [a-z]
).
Program nie może wykonywać żadnych innych operacji sieciowych lub związanych z plikami.
Gra kończy się, gdy O
zostanie zwrócony ciąg złożony z samego ciągu lub gdy program wykona 5 prób i nie będzie w stanie odgadnąć słowa.
Punktacja
Wynik gry jest określony przez podaną formułę:
score = 100 * (6 - number_of_attempts)
Więc jeśli słowo jest poprawnie odgadnięte przy pierwszej próbie, daje się 500 punktów. Ostatnia próba jest warta 100 punktów.
Brak odgadnięcia słowa daje zero punktów.
Jama
Programy odtwarzające będą oceniane przez próbę odgadnięcia 100 losowych słów dla każdego słowa o długości od 4 do 13 znaków włącznie.
Losowe wybieranie słów będzie dokonywane z wyprzedzeniem, więc wszystkie wpisy będą musiały odgadnąć te same słowa.
Zwycięski program i zaakceptowana odpowiedź będą tymi, które osiągną najwyższy wynik.
Programy będą uruchamiane na maszynie wirtualnej Ubuntu, przy użyciu kodu pod adresem https://github.com/noirotm/lingo . Implementacje w dowolnym języku są akceptowane, o ile dostarczone są uzasadnione instrukcje ich kompilacji i / lub uruchomienia.
Podaję kilka implementacji testowych w Rubim w repozytorium git, nie krępuj się czerpać z nich inspiracji.
To pytanie będzie okresowo aktualizowane o rankingi opublikowanych odpowiedzi, aby umożliwić pretendentom poprawę swoich wpisów.
Oficjalna ocena końcowa odbędzie się 1 lipca .
Aktualizacja
Wpisy mogą teraz zakładać obecność wordlistN.txt
plików, aby przyspieszyć czytanie listy słów dla bieżącej długości słowa dla N od 4 do 13 włącznie.
Na przykład istnieje wordlist4.txt
plik zawierający wszystkie czteroliterowe słowa i wordlist10.txt
zawierający wszystkie dziesięć liter i tak dalej.
Wyniki pierwszej rundy
Na dzień 01.01.2014 r. Przesłano trzy wpisy, z następującymi wynikami:
4 5 6 7 8 9 10 11 12 13 Total
./chinese-perl-goth.pl 8100 12400 15700 19100 22100 25800 27900 30600 31300 33600 226600
java Lingo 10600 14600 19500 22200 25500 28100 29000 31600 32700 33500 247300
./edc65 10900 15800 22300 24300 27200 29600 31300 33900 33400 33900 262600
** Rankings **
1: ./edc65 (262600)
2: java Lingo (247300)
3: ./chinese-perl-goth.pl (226600)
Wszystkie wpisy były wykonywane konsekwentnie, z wyraźnym zwycięzcą, będąc wpisem C ++ @ edc65.
Wszyscy zawodnicy są niesamowici. Do tej pory nie byłem w stanie nawet pokonać @ chinese-perl-goth.
Jeśli zostanie przesłanych więcej zgłoszeń, odbędzie się kolejna ocena. Bieżące wpisy można również poprawić, jeśli czujesz, że możesz to zrobić lepiej.
źródło
Odpowiedzi:
C ++ 267700 punktów
Przenoszenie ze starego silnika MasterMind.
Różnice w stosunku do MasterMind:
Podstawową ideą jest wybranie słowa, które minimalizuje przestrzeń rozwiązania. Algorytm jest naprawdę powolny przy pierwszym zgadywaniu (mam na myśli „dni”), ale najlepsze pierwsze zgadywanie zależy tylko od słowa len, więc jest zakodowane na stałe w źródle. Inne domysły są wykonywane w ciągu kilku sekund.
Kod
(Kompilacja z g ++ -O3)
Moje wyniki
Ocena z żargonem, 100 rund:
Razem 265'100
Wyniki samooceny
Oto moje średnie punkty, zdobyte na całej liście słów. Nie do końca niezawodne, ponieważ niektóre szczegóły algorytmu zmieniły się podczas testów.
Według tych liczb mój średni wynik powinien być blisko 257'800
WYNIK PIT
W końcu zainstalowałem Ruby, więc teraz mam „oficjalny” wynik:
źródło
Java, 249700 punktów (w moim teście pokonuje chińskiego Perla Gotha)
Zaktualizowana lista rankingowa:
Oto stara lista rankingowa wykorzystująca
pit.rb
:W porównaniu do @chineseperlgoth przegrywam krótszymi słowami (<6 znaków), ale wygrywam dłuższymi słowami (> = 6 znaków).Pomysł jest podobny do @chineseperlgoth, po prostu moim głównym pomysłem jest znalezienie zgadywania (może to być dowolne słowo o tej samej długości, niekoniecznie jedna z pozostałych możliwości), co daje najwięcej informacji do następnego zgadnięcia.
Obecnie nadal gram z formułą, ale dla powyższej tabeli wyników wybieram słowo, które da minimum:Najnowsza wersja wykorzystuje inną ocenę, aby znaleźć następne najlepsze zgadywanie, co maksymalizuje liczbę „pojedynczych możliwości” po bieżącym zgadywaniu. Odbywa się to poprzez wypróbowanie wszystkich słów w przyciętej liście słów (w celu zaoszczędzenia czasu) wszystkich możliwych kandydatów i sprawdzenie, które przypuszczenie jest bardziej prawdopodobne, aby uzyskać „pojedynczą możliwość” (to znaczy, po tym przypuszczeniu będzie tylko jedna możliwa odpowiedź) dla następne przypuszczenie.
Na przykład ten przebieg:
Z pierwszych trzech domysłów, mamy już gdzieś „* oo * s” z „n” i wciąż musimy wymyślić jeszcze jedną literę. Piękno tego algorytmu polega na tym, że zamiast zgadywać słowa podobne do tej formy, odgaduje słowo, które w ogóle nie ma związku z poprzednimi domysłami, próbując podać więcej liter, miejmy nadzieję, że ujawni brakującą literę. W tym przypadku zdarza się również, że poprawnie przyjmuje pozycję brakującego „b” i kończy się poprawnym odgadnięciem „dobrodziejstw”.
Oto kod:
źródło
Perl
Nadal jest miejsce na ulepszenia, ale przynajmniej wyprzedza przykładowych graczy :)
Zakłada dostęp do zapisu do bieżącego katalogu w celu buforowania list słów (w celu przyspieszenia jego działania); utworzy
wordlist.lenN.stor
pliki za pomocąStorable
. Jeśli jest to problem, usuńread_cached_wordlist
i zmień kod, aby użyć justread_wordlist
.Wyjaśnienie
Najpierw buduję histogram częstotliwości liter we wszystkich słowach w bieżącej liście słów (
build_histogram
). Następnie muszę wybrać moje następne przypuszczenie - co się dziejefind_best_word
. Algorytm oceniania po prostu dodaje razem wartości histogramu, pomijając już widoczne litery. To daje mi słowo zawierające najczęstsze litery na liście słów. Jeśli z danym wynikiem jest więcej niż jedno słowo, wybieram jedno losowo. Po znalezieniu słowa wysyłam je do silnika gry, czytam odpowiedź, a następnie próbuję zrobić z nią coś pożytecznego :)Utrzymuję zestaw warunków, czyli liter, które mogą wystąpić na danym stanowisku w słowie. Na początku jest to po prostu proste
(['a'..'z'] x $len)
, ale jest aktualizowane na podstawie wskazówek podanych w odpowiedzi (patrzupdate_conds
). Następnie buduję wyrażenie regularne na podstawie tych warunków i filtruję przez niego listę słów.Podczas testów dowiedziałem się wtedy, że wspomniane filtrowanie nie radzi sobie
?
zbyt dobrze, stąd drugi filtr (filter_wordlist_by_reply
). Wykorzystuje to fakt, że litera oznaczona jako?
występuje w słowie na innym miejscu i odpowiednio filtruje listę słów.Kroki te powtarza się dla każdej iteracji głównej pętli, chyba że rozwiązanie zostanie znalezione (lub nie można już czytać ze standardowego wejścia, co oznacza błąd).
Kod
źródło