Zielsetzung
Wenn Sie eine Liste mit drei Passwörtern haben, knacken Sie sie alle. Jedes Mal, wenn Sie raten, erhalten Sie einen Hinweis im Mastermind- Stil, der angibt , wie viele Zeichen mit dem Kennwort übereinstimmen und wie viele sich an der richtigen Position befinden. Ziel ist es, die Gesamtzahl der Vermutungen über alle Testfälle hinweg zu minimieren.
Passphrasen
Aus der Standardwortliste meines Systems habe ich zufällig 10.000 verschiedene Wörter ausgewählt, um das Wörterbuch für diese Herausforderung zu erstellen. Alle Wörter bestehen a-z
nur aus. Dieses Wörterbuch finden Sie hier ( roh ).
Aus diesem Wörterbuch habe ich 1000 Passphrasen generiert, die aus jeweils drei durch Leerzeichen getrennten Wörtern bestehen ( apple jacks fever
zum Beispiel). Einzelne Wörter können in jeder Passphrase ( hungry hungry hippos
) wiederverwendet werden . Die Liste der Passphrasen finden Sie hier ( roh ), eine pro Zeile.
Ihr Programm kann die Wörterbuchdatei verwenden / analysieren, wie Sie möchten. Sie können die Passphrasen nicht analysieren, um sie für diese bestimmte Liste zu optimieren. Ihr Algorithmus sollte bei einer anderen Liste von Phrasen immer noch funktionieren
Vermutung
Um eine Vermutung anzustellen, übermitteln Sie eine Zeichenfolge an einen Prüfer. Es sollte nur Folgendes zurückgeben :
- Die Anzahl der Zeichen in Ihrer Zeichenfolge auch in der Passphrase ( nicht an der richtigen Position)
- Die Anzahl der Zeichen an der richtigen Position
Wenn Ihre Zeichenfolge perfekt übereinstimmt, gibt sie möglicherweise etwas aus, das darauf hinweist (meine wird -1
für den ersten Wert verwendet).
Wenn die Passphrase beispielsweise lautet the big cat
und Sie vermuten tiger baby mauling
, sollte der Checker zurückkehren 7,1
. 7 Zeichen ( ige<space>ba<space>
) befinden sich in beiden Zeichenfolgen, aber an unterschiedlichen Positionen, und 1 ( t
) befindet sich in beiden Zeichenfolgen an derselben Position. Beachten Sie, dass Leerzeichen zählen.
Ich habe eine Beispielfunktion (gelesen: nicht optimiert) in Java geschrieben, kann aber auch eine eigene schreiben, sofern sie nur die erforderlichen Informationen enthält.
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};
}
Wertung
Ihre Punktzahl ist einfach die Anzahl der Vermutungen, die Sie dem Prüfer für alle Testphrasen übermitteln (wobei die endgültige, korrekte Zahl gezählt wird). Die niedrigste Punktzahl gewinnt.
Sie müssen alle Sätze in der Liste knacken . Wenn Ihr Programm auf einem von ihnen fehlschlägt, ist es ungültig.
Ihr Programm muss deterministisch sein. Bei zweimaliger Ausführung mit demselben Satz von Passwörtern sollte dasselbe Ergebnis zurückgegeben werden.
Im Falle eines Unentschieden zum Ersten werde ich die verknüpften Einträge jeweils vier Mal auf meinem Computer ausführen, und die niedrigste durchschnittliche Zeit zum Lösen aller 1000 Fälle gewinnt. Auf meinem Computer wird Ubuntu 14.04 mit einem i7-3770K und 16 GB RAM ausgeführt, falls sich dies auf Ihr Programm auswirkt . Aus diesem Grund und um das Testen zu erleichtern, sollte Ihre Antwort in einer Sprache verfasst sein, die über einen Compiler / Interpreter verfügt, der kostenlos aus dem Internet heruntergeladen werden kann (ohne kostenlose Testversionen) und keine Anmeldung / Registrierung erfordert.
Titel von XKCD angepasst
quelle
9 0
. Dies kann eine Weile dauern: PAntworten:
Scala 9146 (min. 7, max. 15, durchschnittlich 9,15) Zeit: 2000 Sekunden
Wie bei vielen Einträgen beginne ich damit, die Gesamtlänge zu ermitteln, die Leerzeichen zu finden, ein bisschen mehr Informationen zu erhalten, auf die verbleibenden Kandidaten zu reduzieren und dann Sätze zu erraten.
Inspiriert von dem ursprünglichen xkcd-Comic versuchte ich, mein rudimentäres Verständnis der Informationstheorie anzuwenden. Es gibt eine Billion möglicher Phrasen oder knapp 40 Bit Entropie. Ich habe ein Ziel von unter 10 Vermutungen pro Testphrase festgelegt, was bedeutet, dass wir durchschnittlich fast 5 Bits pro Abfrage lernen müssen (da die letzte unbrauchbar ist). Mit jeder Vermutung erhalten wir zwei Zahlen zurück und je größer der potenzielle Bereich dieser Zahlen ist, desto mehr erwarten wir zu lernen.
Um die Logik zu vereinfachen, verwende ich jede Abfrage als zwei separate Fragen, sodass jede Vermutungszeichenfolge aus zwei Teilen besteht, einer linken Seite, die an der Anzahl der korrekten Positionen interessiert ist (schwarze Stifte im Mastermind) und einer rechten Seite, die an der Anzahl der korrekten Zeichen interessiert ist ( Gesamtstifte). Hier ist ein typisches Spiel:
Räume erraten
Jede Leerzeichenvermutung kann höchstens 2 schwarze Stifte zurückgeben. Ich habe versucht, Vermutungen zu erstellen, um 0,1 und 2 Stifte mit den Wahrscheinlichkeiten 1 / 4,1 / 2 bzw. 1/4 zurückzugeben. Ich glaube, dies ist das Beste, was Sie für erwartete 1,5 Bit an Informationen tun können. Ich entschied mich für eine abwechselnde Zeichenfolge für die erste Vermutung, gefolgt von zufällig generierten, obwohl es sich normalerweise lohnt, erst beim zweiten oder dritten Versuch zu erraten, da wir die Wortlängenhäufigkeiten kennen.
Das Lernen des Zeichensatzes zählt
Für die Vermutungen auf der rechten Seite wähle ich zufällige (immer 2 von e / i / a / s) Zeichensätze aus, sodass die erwartete zurückgegebene Zahl die Hälfte der Phrasenlänge beträgt. Eine höhere Varianz bedeutet mehr Informationen und von der Wikipedia-Seite zur Binomialverteilung schätze ich ungefähr 3,5 Bits pro Abfrage (zumindest für die ersten paar, bevor die Informationen überflüssig werden). Sobald der Abstand bekannt ist, verwende ich zufällige Zeichenfolgen der häufigsten Buchstaben auf der linken Seite, die so ausgewählt wurden, dass sie nicht mit der rechten Seite in Konflikt stehen.
Die verbleibenden Kandidaten zusammenführen
Dieses Spiel ist ein Kompromiss zwischen Rechengeschwindigkeit und Abfrageeffizienz, und die Aufzählung der verbleibenden Kandidaten kann ohne strukturierte Informationen wie bestimmte Charaktere sehr lange dauern. Ich habe diesen Teil optimiert, indem ich hauptsächlich Informationen sammle, die nicht mit der Wortreihenfolge übereinstimmen. Dadurch kann ich die Zeichensatzzählungen für jedes einzelne Wort vorab berechnen und mit den Zählungen vergleichen, die ich aus den Abfragen gelernt habe. Ich packe diese Zahlen in eine Long-Ganzzahl und teste mit dem Maschinengleichheitskomparator und dem Addierer alle meine Zeichenzahlen in parralel. Dies war ein großer Gewinn. Ich kann bis zu 9 Zählungen im Long packen, aber ich fand, dass das Sammeln der zusätzlichen Informationen es nicht wert war und entschied mich für 6 bis 7.
Nachdem die verbleibenden Kandidaten bekannt sind, wähle ich den mit dem niedrigsten erwarteten Log der verbleibenden Kandidaten aus, wenn der Satz einigermaßen klein ist. Wenn das Set groß genug ist, um diese Zeit in Anspruch zu nehmen, wähle ich aus einem kleinen Musterset.
Vielen Dank an alle. Das war ein lustiges Spiel und hat mich dazu verleitet, mich auf der Seite anzumelden.
Update: Bereinigter Code zur Vereinfachung und Lesbarkeit mit geringfügigen Änderungen am Algorithmus, was zu einer verbesserten Punktzahl führt.
Ursprüngliche Punktzahl: 9447 (min. 7, max. 13, durchschnittlich 9,45) Zeit: 1876 Sekunden
Neuer Code ist 278 Zeilen von Scala, unten
quelle
C - gesamt: 37171, min: 24, max: 55, Zeit: ungefähr 10 Sekunden
Ich habe mir Rays Idee geliehen , die Länge jedes Wortes durch Erraten mit Leerzeichen zu ermitteln, außer dass ich eine binäre Suche anstelle einer linearen Suche durchführe, was mir viele Vermutungen erspart.
Sobald ich die Länge eines Wortes bestimmt habe, denke ich, dass das erste Wort mit seiner Länge übereinstimmt, und notiere die Anzahl der korrekten Positionen. Dann wähle ich das erste Wort aus der Menge aller Wörter aus, die mit meiner ersten Vermutung die gleiche Anzahl von Positionen haben wie das Mystery-Wort. Für meine dritte Vermutung wähle ich das erste Wort aus der Menge aller Wörter aus, die mit meiner ersten Vermutung die gleiche Anzahl von Positionen wie das Rätselwort und mit der gleichen Anzahl von Positionen wie meine zweite Vermutung mit dem Rätselwort usw. teilen.
Mit dieser Methode kann ich jedes Wort einzeln in etwa 5-10 Raten erraten. Das dritte Wort muss ich natürlich etwas anders machen, weil ich seine Länge nicht kenne, aber die Methode ist ähnlich. Ich verwende eine Datei, die eine Matrix der Anzahl der Positionen enthält, die jedes Wort gemeinsam hat und die ich vorberechnet habe. Der Großteil der Laufzeit fällt beim Laden der vorberechneten Daten an. Sie können alles herunterladen hier .
Es macht auch Spaß zu beobachten, wie sich die Worte zusammenfassen:
quelle
Python 3.4 - Min .: 21, Max .: 29, Gesamt: 25146, Zeit: 20 Min
min: 30, max: 235, gesamt: 41636, zeit: 4 minAktualisieren:
Diese Methode verwendet keine Zufälligkeit, so dass sich die Punktzahl nicht ändert.
Zunächst werden Vermutungen wie die folgenden verwendet, um das erste und zweite Leerzeichen in der Antwort zu finden.
Dann zählt es das Auftreten jedes Buchstabens, indem es errät
aaaaa...
,bbbbb....
... Danach kostet es ungefähr 40 Schritte. Tatsächlich müssen wir nicht alle Buchstaben probieren und können sie in willkürlicher Reihenfolge probieren. In den meisten Fällen reichen etwa 20 Buchstaben aus. Hier wähle ich 21.Jetzt kennt es die Länge des ersten und des zweiten Wortes, sodass es eine Liste von Kandidaten für diese beiden Wörter herausfiltern kann. Normalerweise sind noch etwa 100 Kandidaten übrig.
Dann werden nur das erste und das zweite Wort aufgelistet. Sobald die ersten beiden Wörter aufgelistet sind, können wir alle gültigen dritten Wörter ableiten, da wir wissen, dass es sich um die Anzahl der Zeichen handelt.
Um die Geschwindigkeit zu optimieren
concurrent.futures
, füge ich dem Programm Multiprocessing hinzu. Sie benötigen also Python 3, um es auszuführen, und ich habe es mit Python 3.4 auf meiner Linux-Box getestet. Außerdem müssen Sie installierennumpy
.quelle
Java 13.923 (min: 11, max: 17)
Update: Verbesserter Score (hat den Durchschnitt von <14 / Riss gebrochen!), Neuer Code
Ursprünglicher Beitrag
Ich habe mich entschieden, mich ganz auf die Menge der Vermutungen zu konzentrieren, anstatt auf die Leistung (unter Berücksichtigung der Regeln). Dies hat zu einem sehr langsamen Smart-Programm geführt.
Anstatt die bekannten Programme zu stehlen, habe ich beschlossen, alles von Grund auf neu zu schreiben, aber es stellte sich heraus, dass einige / die meisten Ideen gleich sind.
Algorithmus
So funktioniert meins:
Beispiel raten
Hier ist ein aktuelles Beispiel:
Da sich mein Code nie wirklich auf einzelne Wörter konzentriert und nur Informationen über die gesamte Phrase sammelt, muss er viele dieser Phrasen generieren, wodurch er sehr langsam wird.
Code
Und zum Schluss hier der (hässliche) Code, versuchen Sie nicht einmal, ihn zu verstehen, sorry:
quelle
Java -
18.708 Abfragen; 2,4 Sekunden11.077 Abfragen; 125 min.Min: 8, Max: 13, effektive Abfragen: 10.095
Ich habe viel zu lange damit verbracht. : P
Der Code ist unter http://pastebin.com/7n9a50NM verfügbarRev. 1. verfügbar unter http://pastebin.com/PSXU2bgaRev 2. verfügbar unter http://pastebin.com/gRJjpbbu
Meine zweite Revision. Ich hatte gehofft, die 11K-Barriere zu knacken, um den Preis zu gewinnen, aber mir ist die Zeit ausgegangen, um dieses Biest zu optimieren.
Es arbeitet nach einem völlig anderen Prinzip als die beiden Vorgängerversionen (und benötigt ungefähr 3.500-mal so lange). Das allgemeine Prinzip besteht darin, die Kandidatenliste mit Leerzeichen und geraden / ungeraden Zeichen auf eine überschaubare Größe (normalerweise zwischen 2 und 8 Millionen) zu reduzieren und dann wiederholte Abfragen mit maximaler Unterscheidungskraft durchzuführen (dh deren Ausgabeverteilung die Entropie maximiert hat).
Nicht Geschwindigkeit, sondern Gedächtnis ist die Hauptbeschränkung. Meine Java-VM lässt mich aus unklaren Gründen (wahrscheinlich Windows 7) keinen Heap reservieren, der größer als 1.200 MB ist, und ich habe die Parameter optimiert, um die bestmögliche Lösung zu finden, die dieses Limit nicht ausschöpft. Es ärgert mich, dass eine ordnungsgemäße Ausführung mit den ordnungsgemäßen Parametern 11 KB ohne bedeutende Verlängerung der Ausführungszeit unterbrechen würde. Ich brauche einen neuen Computer. : P
Was mich genauso ärgert, ist, dass 982 der Abfragen in dieser Implementierung nutzlose "Validierungs" -Abfragen sind. Sie haben keinen anderen Zweck, als die Regel zu erfüllen, dass das Orakel irgendwann einen speziellen "you got it" -Wert zurückgeben muss, obwohl in meiner Implementierung die richtige Antwort in 98,2% der Fälle mit Sicherheit vor dieser Abfrage abgeleitet wurde. Die meisten anderen Sub-11K-Einsendungen basieren auf Filtertechniken, die Kandidatenzeichenfolgen als Abfragezeichenfolgen verwenden und daher nicht den gleichen Nachteil erleiden.
Aus diesem Grund sage ich kühn, dass mein Code 10.095 effektive Abfragen ausführt , was bedeutet, dass nur 10.095 Abfragen vorhanden sind , obwohl meine offizielle Anzahl von Abfragen 11.097 beträgt (unter der Voraussetzung, dass der Code konform, spezifikationsgetreu usw. ist) tatsächlich notwendig, um alle Passphrasen mit 100% iger Sicherheit zu bestimmen. Ich bin nicht sicher, ob eine der anderen Implementierungen dazu passt, daher werde ich es als meinen kleinen Sieg ansehen. ;)
quelle
.
."perpetually exhausting pool"
Java - min: 22, max: 41, gesamt: 28353, Zeit: 4 Sekunden
Das Programm errät das Passwort in 3 Schritten:
Es werden auch eine Reihe von "schlechten Zeichen" verarbeitet, die bei der Suche ein Ergebnis von Null zurückgeben, sowie eine Reihe von "guten Zeichen", die an einer anderen Stelle in der Passphrase platziert sind.
Unterhalb eines Beispiels der Werte, die nacheinander zum Erraten gesendet wurden, sehen Sie die 3 Schritte:
Der Code:
quelle
PYTHON 2.7 - 156821 Vermutungen, 0,6 Sekunden
Ich habe mich für Geschwindigkeit entschieden und nicht für die geringste Anzahl von Vermutungen, obwohl ich glaube, dass meine Anzahl von Vermutungen immer noch geringer ist als zum Beispiel ein direkter Wörterbuchangriff. Ich berechne nicht die Anzahl der Buchstaben im Passwort, sondern an der falschen Stelle, da meine Methode es nicht verwendet, aber wenn Sie der Meinung sind, dass dies mir einen unfairen Vorteil verschafft, werde ich es implementieren. Ich beginne einfach mit einer leeren Vermutungszeichenfolge und füge ein einzelnes Zeichensuffix hinzu, das sich über meine Liste von Zeichen erstreckt. Dabei überprüfe ich das Ergebnis von 'check', um festzustellen, ob die Anzahl der richtigen Zeichen der Länge der Vermutung entspricht. Wenn das Passwort zum Beispiel "schlecht" wäre, würde ich Folgendes raten:
a, b
ein
A B C D
Ich habe auch versucht, die Buchstaben nach der Häufigkeit der englischen Buchstaben zu sortieren, was ungefähr 35% der Anzahl der Vermutungen sowie der Zeit erspart hat. Ich habe alle Passwörter in 0,82 Sekunden geknackt. Statistiken werden am Ende gedruckt.
BEARBEITEN: Ein Stray von +1 und -1 aus zwei der while-Schleifen aus früheren Testiterationen wurde entfernt. Außerdem wurden zusätzliche Statistiken für die geringsten und die meisten Schätzungen für ein einzelnes Passwort hinzugefügt.
EDIT2: Nachschlagetabelle für den häufigsten "nächsten" Buchstaben pro Buchstabe hinzugefügt. Erhöhte Geschwindigkeit und verringerte Ratezahl
quelle
C ++ -
1138310989 Übereinstimmungen!Aktualisieren
Speicherlecks wurden behoben und ein weiterer Versuch, die Größe der einzelnen Wörterwörterbücher zu verringern, wurde entfernt. Dauert auf meinem Mac Pro ungefähr 50 Minuten. Der aktualisierte Code ist auf Github.
Ich wechselte zu der Strategie der Wortgruppenübereinstimmung, überarbeitete den Code und aktualisierte ihn auf github https://github.com/snjyjn/mastermind
Mit Phrase Based Matching sind wir auf 11383 Versuche gekommen! Es ist rechenintensiv! Die Codestruktur gefällt mir auch nicht! Und es ist immer noch weit hinter den anderen :-(
So mache ich es:
Fügen Sie parallel 'gestaltete' Testzeichenfolgen hinzu, um weitere Informationen zu der Phrase zu erhalten. Die aktuelle Strategie lautet wie folgt:
ein. Verwenden Sie Zeichen in der Reihenfolge ihrer Häufigkeit im Wörterbuch.
b. Wir kennen die Anzahl der häufigsten bereits
c. 1. Teststring = die nächsten 5 Zeichen. Dies gibt uns die Anzahl dieser Zeichen in der Phrase.
d. Die nächsten 3 Testzeichenfolgen = jeweils die nächsten 5 Zeichen, wobei zusätzlich zu den ersten 1 Zeichen insgesamt 20 Zeichen in 4 Versuchen erfasst werden. Dies gibt uns auch die Anzahl der letzten 5 Zeichen. Sätze mit 0 sind großartig, um die Wörterbuchgröße zu reduzieren!
e. Teilen Sie nun für den vorherigen Test, der die geringste Anzahl ungleich Null aufwies, die Zeichenfolge in 2 auf und verwenden Sie 1 zum Testen. Die resultierende Anzahl gibt auch Auskunft über die andere Aufteilung.
f. Wiederholen Sie nun die Tests mit Zeichen (0-basiert),
Sobald die Leerzeichen identifiziert sind, verwenden Sie die bisherigen Einschränkungen (so viele Tests wie möglich), um die Größe des Wörterbuchs zu verringern. Erstellen Sie außerdem 3 Unterwörterbücher, 1 für jedes Wort.
Nun machen Sie einige Vermutungen für jedes Wort und testen Sie es.
Verwenden Sie diese Ergebnisse, um die einzelnen Wörterbuchgrößen zu reduzieren.
Dekoriere dies auch mit Testzeichen (nach der Länge), um mehr Einschränkungen für die Phrase zu erhalten! Ich habe in der endgültigen Version 3 Vermutungen angestellt - 2 für Wort 1 und 1 für Wort 2
Dies bringt das Wörterbuch auf eine überschaubare Größe. Führen Sie ein produktübergreifendes Verfahren durch, und wenden Sie dabei wie zuvor alle Einschränkungen an, um ein Phrasenwörterbuch zu erstellen.
Lösen Sie das Phrasenwörterbuch durch eine Reihe von Vermutungen - diesmal unter Verwendung von Positions- und Zeichenübereinstimmungsinformationen.
Dieser Ansatz bringt uns zu weniger als 11383 Versuchen:
Vorherigen Post
Ich habe den Code bereinigt und auf https://github.com/snjyjn/mastermind hochgeladen. Dabei habe ich ihn verbessert und noch 1 Idee zum Ausprobieren. Es gibt einen großen Unterschied zu dem, was ich gestern gemacht habe:
Die Statistiken sehen jetzt so aus:
Ursprünglicher Beitrag
Entschuldigung für die "Antwort", aber ich habe gerade ein Konto erstellt und habe nicht genug Ruf, um einen Kommentar hinzuzufügen.
Ich habe ein C ++ - Programm, das ungefähr 6,5 Sekunden dauert, und 24107 Übereinstimmungsversuche. Es sind ungefähr 1400 Zeilen von c ++. Ich bin nicht glücklich über die Codequalität und werde sie bereinigen, bevor ich sie an einem anderen Tag oder so aufstelle. Aber im Interesse der Community und um zur Diskussion beizutragen, mache ich Folgendes:
Lesen Sie das Wörterbuch und erhalten Sie grundlegende Informationen - minimale / maximale Wortlänge, Zeichenhäufigkeit usw.
Zuerst Leerzeichen identifizieren - Dies hat 2 Hälften, die erste ist eine Reihe von Abfragen, die den Leerzeichen weiterhin partitionieren (ähnlich wie bei einem C. Chafouin):
Dies ist nicht genau, da ich die minimale / maximale Wortlänge verwende und die Übereinstimmungszählungen in jeder Phase verwende, aber Sie haben die Idee. Zu diesem Zeitpunkt gibt es noch nicht genügend Informationen, um die beiden Leerzeichen zu erhalten, aber ich habe genug, um sie auf eine kleine Anzahl von Kombinationen zu reduzieren. Aus diesen Kombinationen kann ich einige spezifische Abfragen machen, die es auf 1 Kombination eingrenzen.
Erstes Wort - Holen Sie sich ein Subwörterbuch mit Wörtern der richtigen Länge. Das Subwörterbuch hat seine eigenen Statistiken. Mache ein paar Vermutungen mit den häufigsten Zeichen, damit du eine Anzahl dieser Zeichen im Wort erhältst. Reduzieren Sie das Wörterbuch anhand dieser Informationen erneut. Erstellen Sie ein Schätzwort mit den unterschiedlichsten Zeichen und verwenden Sie dieses. Jede Antwort führt zu einer Reduzierung des Wörterbuchs, bis eine genaue Übereinstimmung vorliegt oder das Wörterbuch die Größe 1 hat.
Zweites Wort - ähnlich dem ersten Wort
Drittes Wort - dies unterscheidet sich am meisten von den anderen 2. Wir haben keine Größeninformationen dafür, aber wir haben alle vorherigen Abfragen (die wir behalten haben). Mit diesen Abfragen können Sie das Wörterbuch verkleinern. Die Logik lautet:
Verwenden Sie das reduzierte Wörterbuch, um eine Vermutung mit den unterschiedlichsten Zeichen anzustellen, und reduzieren Sie das Wörterbuch weiter bis zur Größe 1 (wie in den Wörtern 1 und 2).
Die Statistiken sehen wie folgt aus:
quelle
Los - Insgesamt: 29546
Ähnlich wie bei einigen anderen, mit einigen Optimierungen.
AAAAAAAABBBBBBBBCCCCCCCC...ZZZZZZZZ
Es ist nicht besonders schnell.
quelle
passphases
undallWords
ist undefiniert.Java: 58.233
(Referenzprogramm)
Ein einfacher Bot, den jeder schlagen kann. Für jede Phrase werden die ersten 26 Vermutungen verwendet, um die Anzahl der Zeichen zu bestimmen. Dann werden alle Wörter entfernt, die Buchstaben enthalten, die in der Phrase nicht gefunden wurden.
Dann kommt eine massive O (n 3 ) -Schleife über die verbleibenden Wörter. Zuerst überprüft es jede Kandidatenphrase, um festzustellen, ob es sich um ein Anagramm handelt. In diesem Fall werden die Ergebnisse ignoriert, es sei denn, es ist eine perfekte Übereinstimmung. Ich habe bisher gesehen, dass es zwischen 28-510 Vermutungen für eine bestimmte Phrase verwendet.
Dies ist langsam und hängt ganz davon ab, wie viele Wörter direkt aus den ersten 26 Vermutungen entfernt werden können. Die meiste Zeit verbleiben zwischen 1000-4000 Wörter, um die Schleife zu durchlaufen. Im Moment läuft es ungefähr 14 Stunden lang mit einer Geschwindigkeit von ~ 180s / Phrase. Ich schätze, dass es 50 Stunden dauern wird, bis die Partitur fertig ist. Sie sollten wahrscheinlich etwas schlaueres oder schonenderes tun.
(Update) Endlich war es soweit, mit etwas weniger als 60k Vermutungen.
quelle
Java:
28.340,26.185Min. 15, Max. 35, Zeit 2,5 s
Da mein dummer Bot endlich aufgehört hatte zu laufen, wollte ich etwas schneller einreichen . Es dauert nur ein paar Sekunden, erzielt aber eine gute Punktzahl (nicht ganz gewinnend> <).
Zuerst wird eine große Pad-Zeichenfolge verwendet, um die Gesamtlänge der Phrase zu ermitteln. Dann binäre Suche, um Räume zu finden, ähnlich wie bei anderen. Dabei werden auch die Buchstaben einzeln geprüft (in Pivot-Reihenfolge), sodass Wörter entfernt werden können, die mehr Buchstaben als die gesamte Phrase enthalten.
Sobald es die Wortlängen hat, verwendet es einen binären Verkleinerungsschritt, um die Auswahlmöglichkeiten für die Wortlisten einzugrenzen. Es wählt die größte Liste und einen Buchstaben, der ungefähr aus der Hälfte der Wörter besteht. Es wird ein wortlanger Block dieses Buchstabens erraten, um festzustellen, welche Hälfte wegzuwerfen ist. Außerdem werden die Ergebnisse verwendet, um Wörter in den anderen Listen zu entfernen, die zu viele Buchstaben enthalten.
Sobald eine Liste nur aus Anagrammen besteht, funktioniert dies nicht mehr. An diesem Punkt durchlaufe ich sie einfach, bis nur noch zwei übrig sind (oder eines, wenn die anderen Wörter nicht bekannt sind).
Wenn ich insgesamt vier Wörter habe (zwei bekannte und eines mit zwei Optionen), überspringe ich die Reduktions- und Anagrammprüfungen und rate nur eine der Optionen als vollständige Phrase. Wenn es nicht funktioniert, muss es das andere sein, aber ich spare mir 50% der Zeit.
Hier ist ein Beispiel, das zeigt, wie der erste Ausdruck geknackt wird:
Und natürlich der Code:
quelle
C # - 10649 (min 8, max 14, Durchschnitt: 10,6) Zeit: ~ 12 Stunden
So sieht es aus:
Löser
Es wird ein vorausschauender Löser verwendet. Bevor er eine Vermutung anstellt, schätzt er die Anzahl der vom Mastermind zurückgegebenen eindeutigen Werte unter Berücksichtigung der derzeit möglichen Passphrasen. Die Vermutung, die die Anzahl der eindeutigen Ergebnisse maximiert, wird verwendet.
Für die Raumschätzphase werden nur mögliche Kombinationen von "" und "." Berücksichtigt. Für die Phase des Erraten von Phrasen wird die gesamte Liste der derzeit möglichen Passphrasen erstellt (weshalb sie so langsam ist).
Buchstabe zählt
Die Anzahl der Buchstaben wird mit der Leerstelle berechnet. Die Buchstabensätze wurden durch eine gierige Suche ausgewählt, indem jeweils ein Buchstabe hinzugefügt und zufällige Testphrasen abgetastet wurden, um festzustellen, wie effektiv der Satz ist.
Der Code ist hier: https://github.com/Tyler-Gelvin/MastermindContest
Es wurde keine Schnittstelle angegeben, sodass alle Eingaben fest codiert sind und Unit-Tests die einzige Schnittstelle sind. Der "Haupt" -Test ist SolverFixture.SolveParallelAll.
quelle
Main
Funktion in Ihrem Code nicht finden . Hat es eine?SolverFixture.SolveSerialAll
ist das, was ich verwendet habe, um die Testergebnisse zu erhalten undSolver.Solve
ist der Kern des Programms. Es ist ein Unit-Test-Projekt ohne einen einzigen offiziellen Einstiegspunkt, also ohnemain
Funktion.C # - Gesamt: 1000, Laufzeit: 305 Sekunden, Durchschnitt: 24, Minimum: 14, Maximum: 32
Wow Avg's <15, das ist ziemlich gut. Nun, das kann ich nicht übertreffen, aber ich habe es versucht, also hier ist mein Ansatz. Ich habe es Wort für Wort getrennt und sie dann nacheinander gelöst. Indem ich die Länge der ersten beiden Wörter bestimmte und dann einige strategische Vermutungen anstellte (jedes Mal, wenn ich nach dem zuvor erratenen Wort filterte), konnte ich die Antwort mit einer relativ geringen Anzahl von Vermutungen erhalten. Während der Zeit, in der ich dies entwickelte, war ich in der Lage, die meisten Teile davon zu optimieren, um eine effiziente Vorformung zu erreichen (in Zahlenschätzungen). Der Fehler dabei liegt jedoch in der anfänglichen Entwurfsentscheidung, jeweils ein Wort logisch zu lösen Vermutungen und / oder Vermutungen nicht so effizient wie möglich ausführen, was wiederum bedeutet, dass ich diese nicht gewinne;
Immer noch ein interessantes Design (zumindest denke ich), eine Sache, die mit dem enthaltenen Code zu beachten ist, in bestimmten Fällen kann ich die Antwort bestimmen, ohne jemals eine Vermutung zu machen, die -1 zurückgibt, wenn dies erforderlich ist "ADD GUESS HERE (falls erforderlich)" (und addiere bis zu +1 zu allen meinen Punkten :()
Algorithmus (Mein Sudo-Code-Denken)
Es gibt also zwei Teile, die ersten beiden Wörter und das letzte Wort. Dies mag für niemanden außer mir einen Sinn ergeben, aber ich habe versucht, dem Code genügend Kommentare hinzuzufügen, sodass dies möglicherweise sinnvoller ist:
NextWord (eines der beiden ersten beiden Wörter)
{
var lengthOfPossibleWord = Länge des Wortes bestimmen (In Code siehe: Effizienter Weg, die Länge zu finden)
Listenmöglichkeiten = Alle Wörter dieser Länge (lengthOfPossibleWord)
Rate mal
Möglichkeiten = Möglichkeiten, bei denen (für alle Vermutungen) {Anzahl der Zeichen an derselben Position gleich dem möglichen Wort ist
(Wenn outOfPlace-Zeichen gleich 0 sind), wobei sich alle Zeichen von dem möglichen Wort unterscheiden.}
}
LastWord (Nachdem die ersten beiden gelöst sind)
{
Listenmöglichkeiten = Alle Wörter gefiltert nach der Anzahl der offPosition-Zeichen im zweiten Wort (im Code siehe: helperWords)
Rate mal
möglichkeiten = möglichkeiten wo (für alle Vermutungen) {
Die Anzahl der Zeichen an derselben Position entspricht dem möglichen Wort
Summe der In- und Out-of-Position-Zeichen == mögliches Wort (für alle Vermutungen)
Die Länge ist gleich der Länge des möglichen Wortes (Summe der In- und Out-Position-Zeichen)
(wenn outOfPlace-Zeichen gleich 0 sind), wobei sich alle Zeichen von dem möglichen Wort unterscheiden
}
}
Code
Damit dies funktioniert, müssen Sie die Dateien ppcg_mastermind_dict.txt und ppcg_mastermind_passes.txt in das aktuelle Verzeichnis (oder in den VS im selben Verzeichnis und setzen Sie "Copy to Output Directory" auf true). Ich entschuldige mich wirklich für die Qualität des Codes. Es gibt noch viel zu tun, aber es sollte funktionieren.
quelle
Python - min: 87, max: 108, gesamt: 96063, Zeit: 4s
Dies ist mein zweiter Beitrag. Diese Methode benötigt weniger Zeit, erzielt aber schlechtere Ergebnisse. Und es kann ausgeführt werden mit:
Schritte:
. ....
,.. ...
...Es kostet ungefähr 90 Versuche für jedes Passwort.
quelle
Perl (läuft noch ... ab sofort min / avg / max von 8 / 9,2 / 11, schätze es auf
1500300 Stunden Gesamtlaufzeit)Update: Die anfänglichen Vermutungen wurden geändert, um sie etwas zu beschleunigen. Ein Fehler wurde behoben.
Es wird wahrscheinlich nicht zu Ende sein, bevor dieser Wettbewerb beendet ist, aber ich könnte es auch posten. Es werden nicht einzelne Wortlängen ermittelt, daher muss das gesamte Wörterbuch überprüft werden, was ... einige Zeit in Anspruch nimmt.
Mit den ersten beiden Annahmen wird die Gesamtlänge, die Anzahl von 'e' und die Anzahl der verschiedenen Zeichen bestimmt.
Dann werden alle Kombinationen ausprobiert, die für diese Statistik ausreichen, sowie alle vorherigen Schätzungen.
Diese neue (und letzte) Version hat mp hinzugefügt und läuft derzeit auf einem 24-Kern-System.
quelle
Java 10.026 (in 2,5 Stunden)
Hier ist mein optimierter Code, jetzt mit mehreren Threads, um die Geschwindigkeit zu verbessern:
quelle