Cel
Biorąc pod uwagę listę trzech słów, złam je wszystkie. Za każdym razem, gdy zgadniesz, otrzymasz wskazówkę w stylu Mastermind , przedstawiającą, ile znaków pasuje do hasła i ile jest na właściwej pozycji. Celem jest zminimalizowanie całkowitej liczby domysłów we wszystkich przypadkach testowych.
Hasła
Z domyślnej listy słów mojego systemu losowo wybrałem 10 000 różnych słów, aby stworzyć słownik dla tego wyzwania. Wszystkie słowa składają się a-z
tylko z. Słownik ten można znaleźć tutaj ( raw ).
Z tego słownika wygenerowałem 1000 haseł składających się z trzech losowych słów oddzielonych spacjami ( apple jacks fever
na przykład). Poszczególne słowa mogą być ponownie użyte w ramach każdego hasła ( hungry hungry hippos
). Możesz znaleźć listę haseł tutaj ( raw ), z jednym w wierszu.
Twój program może używać / analizować plik słownika w dowolny sposób. Nie można analizować haseł w celu optymalizacji dla tej konkretnej listy. Twój algorytm powinien nadal działać, biorąc pod uwagę inną listę fraz
Zgadywanie
Aby zgadnąć, prześlij ciąg do kontrolera. Powinien zwrócić tylko :
- Liczba znaków w ciągu również w haśle ( nie w prawidłowym położeniu)
- Liczba znaków we właściwej pozycji
Jeśli ciąg znaków jest idealnie dopasowany, może wygenerować coś wskazującego na to (moje używa -1
pierwszej wartości).
Na przykład, jeśli hasło jest the big cat
i wydaje się tiger baby mauling
, że moduł sprawdzający powinien powrócić 7,1
. 7 znaków ( ige<space>ba<space>
) znajduje się w obu ciągach, ale w różnych pozycjach, a 1 ( t
) znajduje się w tej samej pozycji w obu. Zauważ, że spacje się liczą.
Napisałem przykładową funkcję (czytaj: niezoptymalizowaną) w Javie, ale możesz napisać własną, pod warunkiem, że zawiera tylko wymagane informacje.
int[] guess(String in){
int chars=0, positions=0;
String pw = currentPassword; // set elsewhere, contains current pass
for(int i=0;i<in.length()&&i<pw.length();i++){
if(in.charAt(i)==pw.charAt(i))
positions++;
}
if(positions == pw.length() && pw.length()==in.length())
return new int[]{-1,positions};
for(int i=0;i<in.length();i++){
String c = String.valueOf(in.charAt(i));
if(pw.contains(c)){
pw = pw.replaceFirst(c, "");
chars++;
}
}
chars -= positions;
return new int[]{chars,positions};
}
Punktacja
Twój wynik to po prostu liczba zgadnięć, które przesyłasz do kontrolera (licząc ostatni, poprawny) dla wszystkich fraz testowych. Najniższy wynik wygrywa.
Musisz złamać wszystkie frazy na liście. Jeśli twój program zawiedzie na którymkolwiek z nich, jest nieprawidłowy.
Twój program musi być deterministyczny. Jeśli zostanie uruchomiony dwukrotnie na tym samym zestawie haseł, powinien zwrócić ten sam wynik.
W przypadku remisu po raz pierwszy uruchomię powiązane wpisy na komputerze cztery razy, a wygrywa najniższy średni czas na rozwiązanie wszystkich 1000 przypadków. Na moim komputerze działa Ubuntu 14.04 z i7-3770K i 16 GB pamięci RAM, na wypadek, gdyby miało to wpływ na twój program. Z tego powodu oraz w celu ułatwienia testowania twoja odpowiedź powinna być w języku, w którym znajduje się kompilator / tłumacz, który można pobrać bezpłatnie z sieci (bez darmowych wersji próbnych) i nie wymaga rejestracji / rejestracji.
Tytuł dostosowany z XKCD
źródło
9 0
. Może to chwilę potrwać: POdpowiedzi:
Scala 9146 (min. 7, maks. 15, średnio 9,15) czas: 2000 sekund
Podobnie jak wiele wpisów, zaczynam od uzyskania całkowitej długości, a następnie od znalezienia spacji, uzyskania nieco więcej informacji, zredukowania do pozostałych kandydatów, a następnie odgadnięcia fraz.
Zainspirowany oryginalnym komiksem xkcd, próbowałem zastosować moje podstawowe zrozumienie teorii informacji. Istnieje trylion możliwych zwrotów lub nieco mniej niż 40 bitów entropii. Wyznaczam cel poniżej 10 zgadnięć na frazę testową, co oznacza, że musimy nauczyć się średnio prawie 5 bitów na zapytanie (ponieważ ostatni jest bezużyteczny). Przy każdym zgadywaniu otrzymujemy dwie liczby i z grubsza mówiąc, im większy potencjalny zakres tych liczb, tym więcej oczekujemy się nauczyć.
Aby uprościć logikę, używam każdego zapytania jako efektywnie dwóch osobnych pytań, więc każdy ciąg zgadywania składa się z dwóch części, lewej strony zainteresowanej liczbą prawidłowych pozycji (czarne kołki w mastermind) i prawej strony zainteresowanej liczbą poprawnych znaków ( kołki ogółem). Oto typowa gra:
Zgadywanie przestrzeni
Każda próba spacji może zwrócić maksymalnie 2 czarne kołki; Próbowałem skonstruować domysły zwracające 0,1 i 2 kołki o prawdopodobieństwach odpowiednio 1 / 4,1 / 2 i 1/4. Uważam, że jest to najlepsze, co możesz zrobić dla oczekiwanych 1,5 bitów informacji. Postawiłem na naprzemienny ciąg dla pierwszego odgadnięcia, po którym następują losowo generowane, chociaż okazuje się, że zwykle warto po prostu zacząć zgadywać przy drugiej lub trzeciej próbie, ponieważ znamy częstotliwości długości słowa.
Liczy się zestaw znaków do nauki
W przypadku domysłów po prawej stronie wybieram losowe (zawsze 2 z e / i / a / s) zestawy znaków, aby oczekiwana zwrócona liczba była o połowę krótsza. Większa wariancja oznacza więcej informacji, a ze strony wikipedii w rozkładzie dwumianowym szacuję około 3,5 bitu na zapytanie (przynajmniej dla pierwszych kilku, zanim informacje staną się zbędne). Kiedy znane są odstępy, używam losowych ciągów najczęstszych liter po lewej stronie, wybranych tak, aby nie kolidowały z prawą stroną.
Łączenie pozostałych kandydatów
Ta gra stanowi kompromis między szybkością obliczeniową / wydajnością zapytań, a wyliczenie pozostałych kandydatów może zająć naprawdę dużo czasu bez uporządkowanych informacji, takich jak określone postacie. Zoptymalizowałem tę część, zbierając głównie informacje niezmienne w kolejności słów, co pozwala mi wstępnie obliczyć liczbę zestawów znaków dla każdego pojedynczego słowa i porównać je z liczbą uzyskaną z zapytań. Pakuję te liczby do Długiej liczby całkowitej, używając komparatora i sumatora równości maszyn, aby przetestować wszystkie liczby moich postaci w parralelu. To była ogromna wygrana. Mogę spakować do 9 rachunków w Long, ale stwierdziłem, że zbieranie dodatkowych informacji nie było tego warte i ustaliłem na 6 do 7.
Po poznaniu pozostałych kandydatów, jeśli zestaw jest dość mały, wybieram ten z najniższym oczekiwanym logem pozostałych kandydatów. Jeśli zestaw jest wystarczająco duży, aby ten czas był czasochłonny, wybieram z małego zestawu próbek.
Dziękuję wszystkim. To była fajna gra i zachęciła mnie do zarejestrowania się na stronie.
Aktualizacja: Oczyszczony kod dla uproszczenia i czytelności, z drobnymi poprawkami algorytmu, co skutkuje poprawą wyniku.
Oryginalny wynik: 9447 (min. 7, maks. 13, średnio 9,45) czas: 1876 sekund
Nowy kod to 278 linii Scali poniżej
źródło
C - ogółem: 37171, min: 24, maks: 55, czas: około 10 sekund
Pożyczyłem pomysł Raya, aby znaleźć długość każdego słowa, zgadując ze spacjami, tyle że szukam raczej binarnego niż liniowego, co oszczędza mi wielu domysłów.
Gdy określę długość słowa, domyślam się, że pierwsze słowo odpowiada jego długości i zapisuję liczbę poprawnych pozycji. Następnie wybieram pierwsze słowo ze zbioru wszystkich słów, które dzielą tę samą liczbę pozycji z moim pierwszym odgadnięciem jako słowo tajemnicze. Przy trzecim zgadywaniu wybieram pierwsze słowo ze zbioru wszystkich słów, które dzielą tę samą liczbę pozycji z moim pierwszym odgadnięciem jako słowo tajemnicze i taką samą liczbę pozycji jak moje drugie przypuszczenie ze słowem tajemniczym itp.
Korzystając z tej metody, jestem w stanie odgadnąć każde słowo, pojedynczo, w około 5-10 domysłów. Oczywiście trzecie słowo muszę zrobić nieco inaczej, ponieważ nie znam jego długości, ale metoda jest podobna. Korzystam z pliku zawierającego macierz liczby wspólnych pozycji każdego słowa, które wcześniej obliczyłem. Większość czasu wykonywania jest ponoszona podczas ładowania wstępnie obliczonych danych. Możesz pobrać wszystko tutaj .
Przyjemnie jest też oglądać zawężające się słowa:
źródło
Python 3.4 - min: 21, max: 29, łącznie: 25146, czas: 20min
min: 30, max: 235, łącznie: 41636, czas: 4 minAktualizacja:
Ten sposób nie używa losowości, więc wynik się nie zmieni.
Najpierw użyj przypuszczeń takich jak poniżej, aby znaleźć pierwszą i drugą spację w odpowiedzi.
Następnie liczyć występowania każdej litery zgadując
aaaaa...
,bbbbb....
... Po nich będzie kosztować około 40 kroków. W rzeczywistości nie musimy wypróbowywać wszystkich liter i możemy wypróbować je w dowolnej kolejności. W większości przypadków wystarczy około 20 liter. Tutaj wybieram 21.Teraz zna długość pierwszego słowa i drugiego słowa, dzięki czemu może odfiltrować listę kandydatów na te dwa słowa. Zwykle na każdego pozostanie około 100 kandydatów.
Następnie wystarczy wyliczyć pierwsze i drugie słowo. Po wyliczeniu pierwszych dwóch słów możemy wywnioskować wszystkie prawidłowe trzecie słowo, ponieważ wiemy, że liczy się liczba znaków.
Aby zoptymalizować szybkość, używam
concurrent.futures
do dodawania do programu wielu procesów. Potrzebujesz więc Pythona 3, aby go uruchomić, a ja przetestowałem go z Pythonem 3.4 na moim Linux-ie. Musisz także zainstalowaćnumpy
.źródło
Java 13923 (min: 11, maks .: 17)
Aktualizacja: poprawiony wynik (złamał <14 / crack avg!), Nowy kod
Oryginalny post
Postanowiłem całkowicie skoncentrować się na liczbie domysłów zamiast na wydajności (biorąc pod uwagę zasady). Spowodowało to bardzo powolny inteligentny program.
Zamiast kraść ze znanych programów postanowiłem napisać wszystko od zera, ale okazuje się, że niektóre / większość pomysłów jest taka sama.
Algorytm
Oto jak działa mój:
Przykładowe domysły
Oto rzeczywisty przykład:
Ponieważ mój kod nigdy tak naprawdę nie koncentruje się na pojedynczych słowach i gromadzi tylko informacje o pełnej frazie, musi wygenerować wiele z tych fraz, co czyni ją bardzo powolną.
Kod
I wreszcie jest (brzydki) kod, nawet nie próbuj go zrozumieć, przepraszam:
źródło
Java - 18
708 zapytań; 2,4 sekundy 11077 zapytań; 125 min.Min .: 8, Maks .: 13, Skuteczne zapytania: 10 095
Zbyt długo spędziłem nad tym. : P
Kod jest dostępny na stronie http://pastebin.com/7n9a50NMWersja 1. dostępna na stronie http://pastebin.com/PSXU2bgaWersja 2. dostępna na stronie http://pastebin.com/gRJjpbbu
Moja druga wersja. Miałem nadzieję przekroczyć barierę 11 000, aby wygrać nagrodę, ale zabrakło mi czasu na optymalizację tej bestii.
Działa na zupełnie innej zasadzie niż poprzednie dwie wersje (i zajmuje około 3500 razy więcej czasu). Ogólną zasadą jest stosowanie spacji i przesiewania znaków parzystych / nieparzystych w celu zmniejszenia listy kandydatów do możliwego do zarządzania rozmiaru (zwykle między 2-8 milionów), a następnie wykonywanie powtarzających się zapytań z maksymalną mocą dyskryminacji (tj. Których rozkład wyjściowy zmaksymalizował entropię).
Nie ograniczenie, ale pamięć jest głównym ograniczeniem. Moja wirtualna maszyna Java nie pozwala mi zarezerwować sterty większej niż 1200 MB z jakiegoś niejasnego powodu (prawdopodobnie Windows 7), a ja dostroiłem parametry, aby uzyskać najlepsze możliwe rozwiązanie, które nie wyczerpuje tego limitu. Denerwuje mnie, że poprawne uruchomienie z właściwymi parametrami złamałoby 11K bez znaczącego wydłużenia czasu wykonania. Potrzebuję nowego komputera. : P
Najbardziej denerwuje mnie to, że 982 zapytań w tej implementacji to bezużyteczne zapytania „sprawdzania poprawności”. Nie mają innego celu niż spełnienie zasady, że wyrocznia musi w pewnym momencie zwrócić specjalną wartość „masz”, mimo że w mojej implementacji poprawnie wydano prawidłową odpowiedź przed tym zapytaniem w 98,2% przypadków. Większość innych zgłoszeń poniżej 11K opiera się na technikach filtrowania, które wykorzystują ciągi kandydujące jako ciągi zapytania, a zatem nie podlegają takiej samej karze.
Z tego powodu, chociaż moja oficjalna liczba zapytań wynosi 11 077 (brak liderów, pod warunkiem, że ich kod jest zgodny, zgodny ze specyfikacją itp.), Śmiało stwierdzam, że mój kod wykonuje 10 095 efektywnych zapytań, co oznacza, że tylko 10 095 zapytań jest faktycznie konieczne jest określenie wszystkich fraz z 100% pewnością. Nie jestem pewien, czy którakolwiek inna implementacja będzie do tego pasować, dlatego uznam to za moje małe zwycięstwo. ;)
źródło
.
."perpetually exhausting pool"
Java - min: 22, max: 41, łącznie: 28353, czas: 4 sekundy
Program zgaduje hasło w 3 krokach:
Obsługuje również zestaw „złych znaków”, które zwracają zero wyników wyszukiwania, oraz zestaw „dobrych znaków”, które są umieszczane gdzie indziej w haśle.
Poniżej przykład wartości wysyłanych kolejno do zgadywania, możesz zobaczyć 3 kroki:
Kod:
źródło
PYTHON 2.7 - 156821 domysłów, 0,6 sekundy
Poszedłem raczej do szybkości niż do najmniejszej liczby domysłów, chociaż uważam, że moja liczba domysłów jest wciąż niższa niż na przykład byłby zwykły atak słownikowy. Nie obliczam liczby liter w haśle, ale w niewłaściwym miejscu, ponieważ moja metoda go nie używa, ale jeśli uważasz, że daje mi to niesprawiedliwą przewagę, to go wdrożę. Po prostu zaczynam od pustego ciągu zgadywania i dodam do niego przyrostek jednego znaku, który zwiększa się nad moją listą znaków, sprawdzając wynik „sprawdzenia”, aby sprawdzić, czy liczba poprawnych znaków jest równa długości zgadywania. Na przykład, jeśli hasło byłoby „złe”, zgadłbym:
a, b
za
a, b, c, d
Próbowałem też posortować litery według angielskiej częstotliwości, co zmniejszyło liczbę domysłów o 35%, a także o czasie. Złamałem wszystkie hasła w 0,82 sekundy. Statystyki są drukowane na końcu.
EDYCJA: Usunięto zbłąkane +1 i -1 z dwóch pętli while z poprzednich iteracji testowania, dodano także dodatkowe statystyki dla najmniejszej liczby domysłów i większości domysłów dla indywidualnego hasła.
EDYCJA 2: dodano tabelę odnośników dla najczęstszej „następnej” litery na literę. Znacznie większa prędkość i mniejsza liczba zgadnięć
źródło
C ++ -
1138310989 meczów!Aktualizacja
Naprawiono wycieki pamięci i usunięto jeszcze jedną próbę zmniejszenia rozmiarów poszczególnych słowników słów. Moje Mac Pro zajmuje około 50 minut. Zaktualizowany kod znajduje się na github.
Przerzuciłem się na strategię dopasowywania fraz, przerobiłem kod i zaktualizowałem go na github https://github.com/snjyjn/mastermind
Dzięki dopasowaniu opartemu na wyrażeniach ograniczamy się do 11383 prób! Jest drogi pod względem obliczeniowym! Nie podoba mi się również struktura kodu! I wciąż jest daleko w tyle za innymi :-(
Tak to robię:
Równolegle dołącz „spreparowane” ciągi testowe, aby uzyskać więcej informacji na temat frazy. Obecna strategia jest następująca:
za. Używaj znaków w kolejności ich częstotliwości w słowniku.
b. Znamy już liczbę najczęstszych
do. 1. ciąg testowy = kolejne 5 znaków. To daje nam liczbę tych znaków w zdaniu.
re. kolejne 3 ciągi testowe = każde kolejne 5 znaków, obejmujące łącznie 20 znaków w 4 próbach oprócz pierwszego 1 znaku. Daje nam to również liczbę ostatnich 5 znaków. zestawy z liczbą 0 świetnie nadają się do zmniejszenia rozmiaru słownika!
mi. Teraz w poprzednim teście, który miał najmniej niezerową liczbę, podziel ciąg na 2 i użyj 1 do testowania. Wynikowa liczba mówi nam również o innym podziale.
fa. Teraz powtórz testy ze znakami (na podstawie 0),
Po zidentyfikowaniu spacji użyj dotychczasowych ograniczeń (tyle testów, ile można wykonać w tych próbach), aby zmniejszyć rozmiar słownika. Utwórz także 3 słowniki, po 1 dla każdego słowa.
Teraz zrób przypuszczenia dla każdego słowa i przetestuj je.
Użyj tych wyników, aby zmniejszyć poszczególne rozmiary słowników.
Udekoruj to również znakami testowymi (po długości), aby uzyskać więcej ograniczeń dla frazy! Użyłem 3 domysłów w ostatecznej wersji - 2 dla słowa 1 i 1 dla słowa 2
Sprowadza to słownik do rozsądnego rozmiaru. Wykonaj krzyżowy produkt, stosując wszystkie ograniczenia jak poprzednio, aby utworzyć słownik fraz.
Rozwiąż słownik fraz poprzez szereg domysłów - tym razem wykorzystując informacje o położeniu i dopasowaniu znaków.
Takie podejście prowadzi nas do 11383 prób:
Poprzedni post
Wyczyściłem kod i przesłałem go na https://github.com/snjyjn/mastermind W tym czasie ulepszyłem go i nadal mam jeszcze jeden pomysł do wypróbowania. Jest jedna zasadnicza różnica w stosunku do tego, co zrobiłem wczoraj:
Statystyki wyglądają teraz następująco:
Oryginalny post
Przepraszamy za „odpowiedź”, ale właśnie utworzyłem konto i nie mam wystarczającej reputacji, aby dodać komentarz.
Mam program c ++, który zajmuje około 6,5 sekundy i 24107 prób dopasowania. Jest to około 1400 linii c ++. Nie podoba mi się jakość kodu i wyczyszczę go, zanim wprowadzę go w inny dzień. Ale w interesie społeczności i przyczynianiu się do dyskusji robię to:
Przeczytaj słownik, uzyskaj podstawowe informacje na jego temat - minimalna / maksymalna długość słowa, częstotliwość znaków itp.
Najpierw zidentyfikuj spacje - ma 2 połówki, pierwsza to zestaw zapytań, które nadal dzielą przestrzeń (podobnie jak jedna C. Chafouin):
Nie jest to do końca dokładne, ponieważ używam minimalnej / maksymalnej długości słowa i używam liczników dopasowania na każdym etapie, ale masz pomysł. W tym momencie wciąż nie ma wystarczających informacji, aby uzyskać 2 spacje, ale mam dość, aby sprowadzić je do niewielkiej liczby kombinacji. Z tych kombinacji mogę zrobić kilka konkretnych zapytań, które zawęzią go do 1 kombinacji.
Pierwsze słowo - zdobądź subdictionary, który zawiera słowa o odpowiedniej długości. Indeks podrzędny ma własne statystyki. Zrób kilka zgadnięć z najczęstszymi postaciami, aby uzyskać liczbę tych znaków w słowie. Ponownie zmniejsz słownik w oparciu o te informacje. Utwórz słowo „zgadnij”, które ma najróżniejsze znaki i użyj go. Każda odpowiedź powoduje redukcję słownika, dopóki nie znajdziemy dokładnego dopasowania lub słownik będzie miał rozmiar 1.
Drugie słowo - podobne do pierwszego słowa
Trzecie słowo - najbardziej różni się od pozostałych 2. Nie mamy do tego informacji o rozmiarze, ale mamy wszystkie poprzednie zapytania (które zachowaliśmy). Te zapytania pozwalają zmniejszyć słownik. Logika jest następująca:
Użyj skróconego słownika, aby odgadnąć, używając najbardziej różnorodnych znaków, i kontynuuj zmniejszanie słownika do rozmiaru 1 (jak w słowach 1 i 2).
Statystyki wyglądają następująco:
źródło
Idź - ogółem: 29546
Podobne do niektórych, z pewnymi optymalizacjami.
AAAAAAAABBBBBBBBCCCCCCCC...ZZZZZZZZ
To nie jest szczególnie szybkie.
źródło
passphases
iallWords
jest niezdefiniowany.Java: 58,233
(program referencyjny)
Prosty bot dla każdego do pokonania. Używa początkowych 26 odgadnięć dla każdej frazy, aby ustalić liczbę znaków. Następnie eliminuje wszystkie słowa zawierające litery nie znalezione w wyrażeniu.
Potem pojawia się potężna pętla O (n 3 ) nad pozostałymi słowami. Najpierw sprawdza każde zdanie kandydujące, aby zobaczyć, czy jest to anagram. Jeśli tak, zgaduje, ignorując wyniki, chyba że jest to idealne dopasowanie. Do tej pory widziałem, że używa dowolnej liczby wyrażeń od 28 do 510.
Jest to powolne i całkowicie zależy od tego, ile słów można wyeliminować z początkowych 26 domysłów. Przeważnie pozostawia od 1000 do 4000 słów do zapętlenia. Obecnie działa od około 14 godzin w tempie ~ 180s / frazę. Szacuję, że ukończenie zajmie 50 godzin i zaktualizuję wynik w tym czasie. Prawdopodobnie powinieneś zrobić coś mądrzejszego lub bardziej niż to.
(aktualizacja) W końcu się skończyło, z nieco mniej niż 60 000 domysłów.
źródło
Java:
28.34026.185Min. 15, maks. 35, czas 2,5 s
Ponieważ mój głupi bot w końcu skończył działać, chciałem przesłać coś nieco szybciej. Działa w ciągu kilku sekund, ale otrzymuje dobry wynik (niezupełnie wygrywający> <).
Najpierw używa dużego ciągu padu, aby uzyskać całkowitą długość frazy. Następnie wyszukiwanie binarne w celu znalezienia spacji podobnych do innych. Robiąc to, zaczyna również sprawdzać litery pojedynczo (w kolejności przestawnej), aby wyeliminować słowa zawierające więcej dowolnej litery niż całą frazę.
Po uzyskaniu długości słowa wykorzystuje krok binarny, aby zawęzić wybór list słów. Wybiera największą listę i literę składającą się z około połowy słów. Odgaduje długość słowa tego listu, aby określić, którą połowę wyrzucić. Wykorzystuje również wyniki, aby pozbyć się słów z innych list, które mają za dużo litery.
Gdy lista składa się tylko z anagramów, to nie działa. W tym momencie po prostu przechodzę przez nie, aż pozostaną tylko dwa (lub jedno, jeśli pozostałe słowa nie są znane).
Jeśli mam całkowitą liczbę słów cztery (dwa znane i jedno z dwiema opcjami), pomijam sprawdzanie redukcji i anagramów i po prostu odgaduję jedną z opcji jako pełne wyrażenie. Jeśli to nie działa, to musi być drugi, ale oszczędzam przypuszczenie 50% czasu.
Oto przykład pokazujący pękanie pierwszej frazy:
I oczywiście kod:
źródło
C # - 10649 (min. 8, maks. 14, średnio: 10,6) czas: ~ 12 godzin
Tak to wygląda:
Solver
Wykorzystuje przyszłościowy solver. Zanim zgadnie, szacuje liczbę odrębnych wartości zwróconych przez mózg, biorąc pod uwagę aktualnie możliwe hasła. Zgaduje się, że maksymalizuje liczbę wyraźnych wyników.
W fazie zgadywania w przestrzeni bierze się pod uwagę tylko możliwe kombinacje „” i „.”. W fazie zgadywania fraz tworzy całą listę aktualnie możliwych haseł (dlatego jest tak wolny).
List się liczy
Liczby liter są wrzucane wraz ze spacją. Zestawy liter zostały wybrane przez chciwe wyszukiwanie, dodając jedną literę na raz i próbkując losowe frazy testowe, aby zobaczyć, jak skuteczny jest zestaw.
Kod jest tutaj: https://github.com/Tyler-Gelvin/MastermindContest
Nie określono interfejsu, więc wszystkie dane wejściowe są zakodowane na stałe, a testy jednostkowe są jedynym interfejsem. „Główny” test to SolverFixture.SolveParallelAll.
źródło
Main
funkcji w twoim kodzie. Czy to ma?SolverFixture.SolveSerialAll
jest tym, czego użyłem, aby uzyskać wyniki testu opublikowane powyżej iSolver.Solve
jest rdzeniem programu. Jest to projekt testu jednostkowego bez jednego oficjalnego punktu wejścia, więc nie mamain
funkcji.C # - Razem: 1000, Czas działania: 305 sekund, Średnio: 24, Min: 14, Max: 32
Wow Avg <15 to całkiem niezłe, cóż, nie mogę tego przebić, ale zrobiłem sobie dźgnięcie, więc oto moje podejście. Rozbijałem to słowo po słowie, a następnie rozwiązywałem je kolejno. Określając długość pierwszych dwóch słów, a następnie dokonując kilku strategicznych domysłów (za każdym razem filtrując według wcześniej odgadniętego słowa) byłem w stanie uzyskać odpowiedź przy stosunkowo niewielkiej liczbie domysłów. W okresie, w którym to opracowałem, byłem w stanie zoptymalizować większość jego części, aby efektywnie wykonać preformę (w liczbach), ale wina leży w początkowej decyzji projektowej o logicznym rozwiązaniu jednego słowa na raz, co powoduje, że odrzucam części domysły i / lub nie uruchamianie domysłów tak skutecznie, jak to możliwe, co z kolei oznacza, że nie wygrywam tego;
Nadal ciekawy projekt (przynajmniej tak mi się wydaje), jedną rzeczą do odnotowania w dołączonym kodzie, w niektórych przypadkach mogę ustalić odpowiedź bez uruchamiania przypuszczenia, które zwraca -1, jeśli jest to wymagane, po prostu odkomentuj wiersz kodu oznaczony „DODAJ GUESS TUTAJ (jeśli jest wymagany)” (i dodaj +1 do wszystkich moich wyników :()
Algorytm (My Sudo Code Thinking)
Tak naprawdę są dwie części, pierwsze dwa słowa i ostatnie słowo. Może to nie mieć sensu dla nikogo oprócz mnie, ale próbowałem dodać wystarczającą liczbę komentarzy do kodu, więc może to będzie bardziej sensowne:
NextWord (jedno z dwóch pierwszych dwóch słów)
{
var lengthOfPossibleWord = Określ długość słowa (w kodzie patrz: skuteczny sposób na znalezienie długości)
Lista możliwości = Wszystkie słowa o tej długości (lengthOfPossibleWord)
Zgadnij
Możliwości = możliwości gdzie (dla wszystkich przypuszczeń) {Liczba znaków na tej samej pozycji jest równa możliwemu słowu
(jeśli znaki outOfPlace są równe 0), to gdzie wszystkie znaki różnią się od możliwego słowa}
}
LastWord (po rozwiązaniu pierwszych dwóch)
{
Lista możliwości = Wszystkie słowa odfiltrowane według liczby znaków offPosition w drugim słowie (w kodzie patrz: helperWords)
Zgadnij
możliwości = możliwości gdzie (dla wszystkich przypuszczeń) {
Liczba znaków na tej samej pozycji jest równa możliwemu słowu
Suma znaków wejściowych i wyjściowych == możliwe słowo (dla wszystkich odgadnięć)
Długość jest większa niż (suma znaków wejściowych i wyjściowych) możliwego słowa
(jeśli znaki outOfPlace są równe 0), to gdzie wszystkie znaki różnią się od możliwego słowa
}
}
Kod
Uwaga: aby to zadziałało, musisz dołączyć ppcg_mastermind_dict.txt i ppcg_mastermind_passes.txt w katalogu bieżącym (lub w VS w tym samym katalogu i ustawić „Kopiuj do katalogu wyjściowego” na true). Naprawdę przepraszam za jakość kodu, ale wciąż jest wiele do zrobienia, ale powinno działać.
źródło
Python - min: 87, max: 108, ogółem: 96063, czas: 4s
To jest mój drugi post. Ta metoda zużywa mniej czasu, ale gorzej. I można go uruchomić za pomocą:
Kroki:
. ....
,.. ...
...Koszt każdego hasła to około 90 domysłów.
źródło
Perl (wciąż działa ... od teraz min / avg / max 8 / 9,2 / 11, oszacuj na
1500300 godzin całkowitego czasu pracy)Aktualizacja: Zmieniono początkowe domysły, aby nieco przyspieszyć. Naprawiono błąd.
Prawdopodobnie nie skończy się przed tym konkursem, ale równie dobrze mogę to opublikować. Nie określa długości poszczególnych słów, więc musi sprawdzić cały słownik, co ... zajmuje trochę czasu.
Przy pierwszych dwóch zgadywaniach określa całkowitą długość, liczbę „e” i liczbę różnych znaków.
Następnie wypróbowuje wszystkie kombinacje, które wystarczają do tych statystyk, a także wszystkie poprzednie domysły.
Ta ostatnia (i ostatnia) wersja dodała mp i obecnie działa w systemie 24-rdzeniowym.
źródło
Java 10.026 (w 2,5 godziny)
Oto mój zoptymalizowany kod, teraz wielowątkowy, aby poprawić szybkość:
źródło