Hier ist eine 1,2-MB-ASCII-Textdatei, die den Text von Herman Melvilles Moby-Dick enthält. oder der Wal . Ihre Aufgabe ist es, ein Programm oder eine Funktion (oder eine Klasse usw. - siehe unten) zu schreiben, die diese Datei jeweils zeichenweise erhält und bei jedem Schritt das nächste Zeichen erraten muss.
Das ist eine Code-Herausforderung . Ihre Punktzahl wird sein
2*L + E
Wo L
ist die Größe Ihrer Einreichung in Bytes und E
wie viele Zeichen werden falsch erraten? Die niedrigste Punktzahl gewinnt.
Weitere Angaben
Ihre Einreichung wird ein Programm oder eine Funktion (usw.) sein, die mehrmals aufgerufen oder aufgerufen oder Daten gesendet werden. (1215235-mal um genau zu sein.) Wenn es zum n- ten Mal aufgerufen wird, erhält es das n- te Zeichen von whale.txt
oder whale2.txt
und muss seine Schätzung für das ( n + 1 ) -te Zeichen ausgeben . Die E
Komponente seiner Punktzahl ist die Gesamtzahl der Zeichen, die er falsch erraten hat.
Die meisten Übermittlungen müssen zwischen den Aufrufen einen bestimmten Status speichern, damit sie nachverfolgen können, wie oft sie aufgerufen wurden und wie die vorherigen Eingaben waren. Sie können dies tun, indem Sie in eine externe Datei schreiben, static
oder globale Variablen verwenden, eine Klasse anstelle einer Funktion übergeben, eine Statusmonade verwenden oder was auch immer für Ihre Sprache sonst noch funktioniert. Ihre Einreichung muss den Code enthalten, der zum Initialisieren des Status vor dem ersten Aufruf erforderlich ist.
Ihr Programm sollte deterministisch ablaufen, damit es bei gleicher Eingabe immer die gleichen Vermutungen anstellt (und daher immer die gleiche Punktzahl erhält).
Ihre Antwort muss nicht nur Ihren Beitrag enthalten, sondern auch den Code, den Sie zur Berechnung des E
Teils der Punktzahl verwendet haben. Dies muss nicht in derselben Sprache wie Ihre Einreichung verfasst sein und wird nicht auf die Anzahl der Bytes angerechnet. Sie werden ermutigt, es lesbar zu machen.
In Bezug auf die Schnittstelle zwischen Ihrer Einreichung und diesem Score-Berechnungsprogramm ist alles in Ordnung, solange Ihr Programm immer ein Byte ausgibt, bevor es das nächste Byte an Eingaben erhält. (So können Sie beispielsweise nicht einfach eine Zeichenfolge übergeben, die die gesamte Eingabe enthält, und eine Zeichenfolge zurückerhalten, die die gesamte Ausgabe enthält.)
Sie müssen Ihr Testprogramm ausführen und Ihre Punktzahl berechnen / verifizieren, bevor Sie Ihren Beitrag einreichen. Wenn Ihr Beitrag zu langsam ist, um die Punktzahl zu überprüfen, ist er nicht für den Wettbewerb qualifiziert, auch wenn Sie wissen, wie hoch die Punktzahl im Prinzip sein würde.
Die L
Komponente Ihrer Punktzahl wird nach den üblichen Regeln für Code-Golf-Herausforderungen berechnet. Wenn Ihre Einreichung mehrere Dateien enthält, beachten Sie in diesem Fall die Regeln zur Bewertung und Verzeichnisstruktur . Alle Daten, die Ihr Code verwendet, müssen in Ihrer L
Partitur enthalten sein.
Sie können vorhandene Bibliotheken importieren, aber möglicherweise keine anderen externen Dateien laden, und Ihr Code greift möglicherweise nicht auf whale.txt
oder zuwhale2.txt
Datei auf eine andere Weise als oben beschrieben. Sie dürfen keine vorab trainierten neuronalen Netze oder andere Quellen statistischer Daten laden. (Es ist in Ordnung, neuronale Netze zu verwenden, aber Sie müssen die Gewichtsdaten in Ihre Übermittlung einbeziehen und diese auf Ihre Byteanzahl angerechnet.) Wenn Ihre Sprache oder Bibliotheken aus irgendeinem Grund eine Funktion enthalten, die den gesamten oder einen Teil des Texts von Moby Dick enthält können Sie diese Funktion nicht verwenden. Abgesehen davon können Sie alle anderen eingebauten oder Bibliotheksfunktionen verwenden, die Sie mögen, einschließlich derer, die sich auf Textverarbeitung, Vorhersage oder Komprimierung beziehen, sofern sie Teil Ihrer Sprache oder ihrer Standardbibliotheken sind. Exotischere, speziellere Routinen, die statistische Datenquellen enthalten, müssen Sie selbst implementieren und in Ihre Byteanzahl einbeziehen.
Es ist wahrscheinlich, dass einige Übermittlungen Komponenten enthalten, die selbst durch Code generiert werden. In diesem Fall geben Sie bitte in Ihrer Antwort den Code an, mit dem sie erstellt wurden, und erläutern Sie die Funktionsweise . (Solange dieser Code nicht zum Ausführen Ihrer Übermittlung benötigt wird, wird er nicht in Ihre Byteanzahl aufgenommen.)
Aus historischen Gründen gibt es zwei Versionen der Datei, und Sie können beide in einer Antwort verwenden. In whale2.txt
(oben verlinkt) wird der Text nicht umbrochen, so dass Zeilenumbrüche nur am Ende von Absätzen erscheinen. Im Original wird whale.txt
der Text mit einer Breite von 74 Zeichen umgebrochen, sodass Sie das Ende jeder Zeile sowie den Text vorhersagen müssen. Dies macht die Herausforderung kniffliger und whale2.txt
wird für neue Antworten empfohlen. Beide Dateien haben dieselbe Größe (1215236 Byte).
Zusammenfassend sollten alle Antworten die folgenden Punkte enthalten:
- Ihre Einreichung selbst. (Der Code sowie alle verwendeten Datendateien - dies können Links sein, wenn sie groß sind.)
- Eine Erklärung, wie Ihr Code funktioniert. Bitte erläutern Sie die E / A-Methode sowie die Vorhersage des nächsten Zeichens. Die Erklärung Ihres Algorithmus ist wichtig und gute Erklärungen bringen mir Kopfgeld.
- Der Code, mit dem Sie Ihre Punktzahl bewertet haben. (Wenn dies mit einer vorherigen Antwort identisch ist, können Sie einfach darauf verlinken.)
- Jeglicher Code, den Sie zum Erstellen Ihrer Einreichung verwendet haben, zusammen mit einer Erläuterung dieses Codes. Dies schließt Code ein, den Sie zur Optimierung von Parametern, zum Generieren von Datendateien usw. verwendet haben. (Dies wird nicht für Ihre Byteanzahl gezählt, sollte aber in Ihrer Antwort enthalten sein.)
Bestenliste
Kopfgelder
Von Zeit zu Zeit biete ich Kopfgelder an, um verschiedene Ansätze zu fördern.
Der erste, 50 Punkte, wurde an A. Rex für die beste Antwort seiner Zeit vergeben.
Die zweite, 100 Punkte, wurde ebenfalls an A. Rex für die gleiche Antwort vergeben, weil sie ihre bestehende Antwort mit einer sehr guten Erklärung versehen haben.
Die nächste Prämie, 200 Punkte , wird an beide vergeben
- Eine wettbewerbsfähige Antwort, die eine neue Technik verwendet. (Dies wird auf meiner subjektiven Beurteilung basieren, da es mein Repräsentant ist, der die Belohnung erhält, aber Sie können mir vertrauen, dass ich fair bin. Beachten Sie, dass Ihre Antwort eine ausreichende Erklärung enthalten muss, damit ich verstehe, wie es funktioniert!) Eine solche Antwort ist nicht erforderlich Die Bestnote wird nicht erreicht, sie muss im Vergleich zu den vorhandenen Antworten nur einigermaßen gut abschneiden. Ich bin besonders an Lösungen interessiert, die auf wiederkehrenden neuronalen Netzen basieren, aber ich werde die Prämie für alles vergeben, was sich von den Markov-Modellen, die die aktuellen Top-Scores dominieren, zu unterscheiden scheint.
Oder:
- Jeder andere, der mit einer beliebigen Methode die Bestnote von A. Rex (derzeit 444444) übertrifft.
Sobald die 200-Punkte-Prämie beansprucht wird, werde ich höchstwahrscheinlich eine 400-Punkte-Prämie anbieten und die Anforderungen entsprechend aktualisieren.
quelle
Antworten:
/// , 2 * 1 + 1020874 = 1020876
Druckt ein Leerzeichen.
quelle
Node.js, 2 * 224 + 524279 = 524727
Bitte lesen Sie das Änderungsprotokoll am Ende dieses Beitrags, um die Punktzahl zu aktualisieren.
Eine Funktion, die ein Byte nimmt und zurückgibt.
Es besteht aus einem einfachen PPM-Modell , das die letzten 8 Zeichen betrachtet, um das nächste vorherzusagen.
Wir vertrauen einem Muster der Länge L, wenn wir es mindestens T [L] mal angetroffen haben , wobei T ein Array von willkürlichen Schwellenwerten ist: [1,1,2,1,2,3,5,2] . Außerdem vertrauen wir immer einem Muster, dessen erstes Zeichen übereinstimmt
[A-Z '"(]
.Wir wählen das längste vertrauenswürdige Muster aus und geben die Vorhersage mit der höchsten Punktzahl zurück, die diesem Muster zum Zeitpunkt des Aufrufs zugeordnet ist.
Anmerkungen
Dies ist offensichtlich nicht für die Geschwindigkeit optimiert, aber es läuft in etwa 15 Sekunden auf meinem Laptop.
Wenn wir den Vorgang mehrmals hintereinander wiederholen könnten, ohne das Modell zurückzusetzen, würde die Anzahl der Fehler nach 5 Iterationen auf ~ 268000 konvergieren.
Die aktuelle Erfolgsrate der Vorhersagefunktion beträgt ~ 56,8%. Wie von @immibis in den Kommentaren bemerkt, ist das Ergebnis nicht einmal schwer lesbar, wenn schlechte und richtige Vermutungen miteinander vermischt werden.
Zum Beispiel dieses Snippet gegen Ende des Buches:
wird:
Indem wir falsche Vermutungen durch Unterstriche ersetzen, haben wir eine bessere Vorstellung davon, was die Funktion richtig gemacht hat:
NB : Das obige Beispiel wurde mit einer früheren Version des Codes erstellt, die an der ersten Version der Eingabedatei arbeitete.
Code testen
Änderungsprotokoll
quelle
sidg tlanses,oeth to, shuld hottut tild aoersors Ch, th! Sa, yr! Sheu arinning whales aut ihe e sl he traaty of rrsf tg homn Bho dla tiasot a shab sor ty, af etoors tnd hocket sh bts ait mtubb tiddin tis aeewnrs, dnhost maundy cnd sner aiwt d boelh cheugh -aaieiyns aasiyns taaeiins! th, tla
. Es schafft es manchmal, ein paar vollständige Wörter zu bekommen. Wiewhales
.Perl, 2 · 70525 + 326508 = 467558
Prädiktor
Um dieses Programm auszuführen, benötigen Sie diese Datei hier , die benannt werden muss
B
. (Sie können diesen Dateinamen in der zweiten Instanz desB
obigen Zeichens ändern .) Im Folgenden erfahren Sie, wie Sie diese Datei generieren.Das Programm verwendet eine Kombination von Markov-Modellen im Wesentlichen wie in dieser Antwort von user2699 , jedoch mit einigen kleinen Änderungen. Dies erzeugt eine Verteilung für das nächste Zeichen. Wir verwenden die Informationstheorie, um zu entscheiden, ob ein Fehler akzeptiert oder Speicherplatz für
B
Codierungshinweise benötigt wird (und wenn ja, wie). Wir verwenden eine arithmetische Codierung , um gebrochene Bits aus dem Modell optimal zu speichern.Das Programm ist 582 Bytes lang (einschließlich einer unnötigen letzten Zeile) und die Binärdatei
B
ist 69942 Bytes lang. Nach den Regeln für das Scoring mehrerer Dateien erhalten wir alsoL
582 + 69942 + 1 = 70525.Das Programm benötigt mit ziemlicher Sicherheit eine 64-Bit-Architektur (Little-Endian?). Die Ausführung einer
m5.large
Instanz auf Amazon EC2 dauert ungefähr 2,5 Minuten .Code testen
Das Testgeschirr geht davon aus, dass sich die Einreichung in der Datei befindet
submission.pl
, dies kann jedoch problemlos in der zweiten Zeile geändert werden.Textvergleich
Dieses Beispiel (in einer anderen Antwort ausgewählt ) kommt ziemlich spät im Text vor, daher ist das Modell zu diesem Zeitpunkt ziemlich entwickelt. Denken Sie daran, dass das Modell um 70 Kilobyte an "Hinweisen" erweitert ist, die es beim Erraten der Zeichen direkt unterstützen. es wird nicht einfach von dem kurzen Code-Snippet oben gesteuert.
Hinweise generieren
Das folgende Programm akzeptiert den oben angegebenen genauen Übermittlungscode (bei Standardeingabe) und generiert die oben angegebene genaue
B
Datei (bei Standardausgabe):Die Ausführung dauert ungefähr so lange wie die Übermittlung, da ähnliche Berechnungen durchgeführt werden.
Erläuterung
In diesem Abschnitt werden wir versuchen, die Funktionsweise dieser Lösung so detailliert zu beschreiben, dass Sie sie selbst "zu Hause ausprobieren" können. Die Haupttechnik, die diese Antwort von den anderen unterscheidet, ist ein paar Abschnitte weiter unten als "Zurückspulen" -Mechanismus, aber bevor wir dort ankommen, müssen wir die Grundlagen einrichten.
Modell
Der Grundbestandteil der Lösung ist ein Sprachmodell. Für unsere Zwecke ist ein Modell etwas, das etwas englischen Text benötigt und eine Wahrscheinlichkeitsverteilung für das nächste Zeichen zurückgibt . Wenn wir das Modell verwenden, wird der englische Text ein (korrektes) Präfix von Moby Dick sein. Bitte beachten Sie, dass es sich bei der gewünschten Ausgabe um eine Verteilung handelt und nicht nur um eine Vermutung für das wahrscheinlichste Zeichen.
In unserem Fall verwenden wir im Wesentlichen das Modell in dieser Antwort von user2699 . Wir haben nicht das Modell aus der Antwort mit der höchsten Punktzahl (außer unserer eigenen) von Anders Kaseorg verwendet , da wir nicht in der Lage waren, eine Verteilung zu extrahieren, sondern nur eine einzige bestmögliche Vermutung. Theoretisch berechnet diese Antwort einen gewichteten geometrischen Mittelwert, aber wir haben etwas schlechte Ergebnisse erzielt, wenn wir das zu wörtlich interpretiert haben. Wir haben ein Modell aus einer anderen Antwort "gestohlen", weil unsere "geheime Sauce" nicht das Modell ist, sondern der Gesamtansatz. Wenn jemand ein "besseres" Modell hat, sollte er in der Lage sein, mit dem Rest unserer Techniken bessere Ergebnisse zu erzielen.
Bemerkenswert ist, dass die meisten Komprimierungsmethoden wie Lempel-Ziv auf diese Weise als "Sprachmodell" angesehen werden können, obwohl man möglicherweise ein wenig schielen muss. (Es ist besonders schwierig für etwas, das eine Burrows-Wheeler-Transformation ausführt!) Beachten Sie außerdem, dass das Modell von user2699 eine Modifikation eines Markov-Modells ist. Im Grunde genommen ist nichts anderes für diese Herausforderung oder vielleicht sogar für das Modellieren von Text im Allgemeinen wettbewerbsfähig.
Gesamtarchitektur
Zum besseren Verständnis ist es hilfreich, die Gesamtarchitektur in mehrere Teile zu unterteilen. Aus Sicht der obersten Ebene muss ein wenig Code für die Zustandsverwaltung vorhanden sein. Das ist nicht besonders interessant, aber der Vollständigkeit halber möchten wir betonen, dass das Programm an jedem Punkt, an dem es nach der nächsten Vermutung gefragt wird, ein korrektes Präfix von Moby Dick hat. Wir verwenden unsere früheren falschen Vermutungen in keiner Weise. Aus Gründen der Effizienz kann das Sprachmodell wahrscheinlich seinen Zustand aus den ersten N Zeichen wiederverwenden, um seinen Zustand für die ersten (N + 1) Zeichen zu berechnen, aber im Prinzip kann es jedes Mal, wenn es aufgerufen wird, Dinge von Grund auf neu berechnen.
Lassen Sie uns diesen grundlegenden "Treiber" des Programms beiseite legen und einen Blick in den Teil werfen, der das nächste Zeichen errät. Es ist konzeptionell hilfreich, drei Teile zu trennen: das oben beschriebene Sprachmodell, eine "Hinweis" -Datei und einen "Interpreter". Bei jedem Schritt fragt der Interpreter das Sprachmodell nach einer Verteilung für das nächste Zeichen und liest möglicherweise einige Informationen aus der Hinweisdatei. Dann werden diese Teile zu einer Vermutung kombiniert. Welche Informationen genau in der Hinweisdatei enthalten sind und wie sie verwendet werden, wird später erläutert. Derzeit hilft es jedoch, diese Teile mental voneinander zu trennen. Beachten Sie, dass die Hinweisdatei in Bezug auf die Implementierung buchstäblich eine separate (binäre) Datei ist, es sich jedoch auch um eine Zeichenfolge oder eine im Programm gespeicherte Datei handeln könnte. Als eine Annäherung,
Wenn Sie eine Standardkomprimierungsmethode wie bzip2 wie in dieser Antwort verwenden , entspricht die Datei "hints" der komprimierten Datei. Der "Interpreter" entspricht dem Dekomprimierer, während das "Sprachmodell" ein wenig implizit ist (wie oben erwähnt).
Warum eine Hinweisdatei verwenden?
Lassen Sie uns ein einfaches Beispiel auswählen, um es weiter zu analysieren. Angenommen, der Text besteht aus
N
Zeichen, die lang und durch ein Modell gut angenähert sind, bei dem jedes Zeichen (unabhängig) der BuchstabeE
mit einer Wahrscheinlichkeit von etwas weniger als einer Hälfte,T
ähnlich einer Wahrscheinlichkeit von etwas weniger als einer Hälfte und einerA
Wahrscheinlichkeit von 1/1000 = 0,1% ist. Nehmen wir an, dass keine anderen Zeichen möglich sind. in jedem Fall ist dasA
ziemlich ähnlich wie bei einem zuvor unsichtbaren Charakter aus heiterem Himmel.Wenn wir im L 0 -Regime operieren (wie die meisten, aber nicht alle anderen Antworten auf diese Frage), gibt es keine bessere Strategie für den Dolmetscher als eine von
E
und auszuwählenT
. Im Durchschnitt wird ungefähr die Hälfte der Zeichen korrekt angezeigt. Also E ≈ N / 2 und die Punktzahl score N / 2 auch. Wenn wir jedoch eine Komprimierungsstrategie verwenden, können wir auf etwas mehr als ein Bit pro Zeichen komprimieren. Da L in Bytes gezählt wird, erhalten wir L ≈ N / 8 und erhalten somit ≈ N / 4, doppelt so gut wie die vorherige Strategie.Das Erreichen dieser Rate von etwas mehr als einem Bit pro Zeichen für dieses Modell ist etwas nicht trivial, aber eine Methode ist die arithmetische Codierung.
Arithmetische Codierung
Wie allgemein bekannt ist, ist eine Codierung eine Möglichkeit, einige Daten unter Verwendung von Bits / Bytes darzustellen. Beispielsweise ist ASCII eine 7-Bit- / Zeichen-Codierung von englischem Text und verwandten Zeichen und die Codierung der betreffenden Originaldatei von Moby Dick. Wenn einige Buchstaben häufiger vorkommen als andere, ist eine Codierung mit fester Breite wie ASCII nicht optimal. In einer solchen Situation greifen viele Menschen zur Huffman-Codierung . Dies ist optimal, wenn Sie einen festen (vorwahlfreien) Code mit einer ganzzahligen Anzahl von Bits pro Zeichen wünschen.
Die arithmetische Codierung ist jedoch noch besser. Grob gesagt ist es möglich, "gebrochene" Bits zum Codieren von Informationen zu verwenden. Es gibt viele Anleitungen zur arithmetischen Codierung, die online verfügbar sind. Wir werden die Details hier überspringen (insbesondere die praktische Implementierung, die aus Programmiersicht etwas schwierig sein kann), da andere Ressourcen online verfügbar sind. Wenn sich jemand beschwert, kann dieser Abschnitt möglicherweise weiter ausgearbeitet werden.
Wenn Text tatsächlich von einem bekannten Sprachmodell generiert wurde, bietet die arithmetische Codierung eine im Wesentlichen optimale Codierung von Text aus diesem Modell. In gewissem Sinne löst dies das Komprimierungsproblem für dieses Modell. (In der Praxis besteht das Hauptproblem darin, dass das Modell nicht bekannt ist und einige Modelle besser als andere in der Modellierung von menschlichem Text sind.) Wenn es nicht erlaubt war, Fehler in diesem Wettbewerb zu machen, dann in der Sprache des vorherigen Abschnitts Eine Möglichkeit, eine Lösung für diese Herausforderung zu finden, wäre gewesen, einen arithmetischen Codierer zu verwenden, um eine "Hinweis" -Datei aus dem Sprachmodell zu generieren, und dann einen arithmetischen Decodierer als "Interpreter" zu verwenden.
Bei dieser im Wesentlichen optimalen Codierung werden am Ende -log_2 (p) Bits für ein Zeichen mit der Wahrscheinlichkeit p ausgegeben, und die Gesamtbitrate der Codierung ist die Shannon-Entropie . Dies bedeutet, dass ein Zeichen mit einer Wahrscheinlichkeit in der Nähe von 1/2 ungefähr ein Bit zum Codieren benötigt, während eines mit einer Wahrscheinlichkeit von 1/1000 ungefähr 10 Bit benötigt (da 2 ^ 10 ungefähr 1000 ist).
Die Bewertungsmetrik für diese Herausforderung wurde jedoch gut gewählt, um die Komprimierung als optimale Strategie zu vermeiden. Wir müssen einen Weg finden, Fehler zu machen, um eine kürzere Datei mit Hinweisen zu erhalten. Eine Strategie, die man versuchen könnte, ist beispielsweise eine einfache Verzweigungsstrategie: Wir versuchen im Allgemeinen, arithmetische Codierung zu verwenden, wenn wir können, aber wenn die Wahrscheinlichkeitsverteilung aus dem Modell in irgendeiner Weise "schlecht" ist, raten wir nur das wahrscheinlichste Zeichen und geben " nicht versuchen, es zu codieren.
Warum Fehler machen?
Lassen Sie uns das Beispiel von vorhin analysieren, um zu motivieren, warum wir Fehler "absichtlich" machen möchten. Wenn wir arithmetische Codierung verwenden, um das richtige Zeichen zu codieren, geben wir im Fall von
E
oderT
ungefähr ein Bit aus, im Fall vonA
.Insgesamt ist dies eine ziemlich gute Kodierung, die etwas mehr als ein bisschen pro Zeichen ausgibt, obwohl es drei Möglichkeiten gibt. Im Grunde ist das
A
ziemlich unwahrscheinlich und wir werden die entsprechenden zehn Bits nicht allzu oft ausgeben. Wäre es nicht schön, wenn wir stattdessen einen Fehler machen könntenA
? Immerhin betrachtet die Metrik für das Problem 1 Byte = 8 Bits Länge als äquivalent zu 2 Fehlern; daher sollte man einen Fehler vorziehen, anstatt mehr als 8/2 = 4 Bits für ein Zeichen auszugeben. Mehr als ein Byte für die Speicherung eines Fehlers auszugeben, klingt definitiv suboptimal!Der "Rücklauf" -Mechanismus
In diesem Abschnitt wird der wichtigste clevere Aspekt dieser Lösung beschrieben, mit dem fehlerhafte Vermutungen ohne Kosten für die Länge behoben werden können.
Für das einfache Beispiel, das wir analysiert haben, ist der Rückspulmechanismus besonders einfach. Der Interpreter liest ein Bit aus der Hinweisdatei. Wenn es eine 0 ist, wird es erraten
E
. Wenn es eine 1 ist, wird es erratenT
. Beim nächsten Aufruf wird das richtige Zeichen angezeigt. Wenn die Hinweisdatei gut eingerichtet ist, können wir sicherstellen, dass der Interpreter im Fall einesE
oderT
richtig errät. Aber was ist mitA
? Die Idee des rewind Mechanismus ist einfach nicht codiertA
überhaupt . Genauer gesagt, wenn der Interpreter später erfährt, dass das richtige Zeichen ein warA
, " spult er das Band metaphorisch zurück ": Er gibt das zuvor gelesene Bit zurück. Das gelesene Bit sollE
oder codierenT
, aber jetzt nicht; es wird später verwendet. In diesem einfachen Beispiel, das bedeutet im Wesentlichen , dass es immer das gleiche Zeichen erraten (E
oderT
) , bis sie macht es richtig; dann liest es noch ein bisschen und geht weiter.Die Kodierung für diese Hinweisdatei ist sehr einfach: Verwandeln Sie alle
E
s in 0-Bits undT
s in 1-Bits, während SieA
s vollständig ignorieren . Nach der Analyse am Ende des vorherigen Abschnitts macht dieses Schema einige Fehler, reduziert jedoch die Gesamtpunktzahl, indem keines derA
s codiert wird . Als kleinerer Effekt wird tatsächlich auch die Länge der Hints-Datei gespart, da am Ende genau ein Bit für jedesE
undT
nicht etwas mehr als ein Bit verwendet wird.Ein kleiner Satz
Wie entscheiden wir, wann wir einen Fehler machen? Angenommen, unser Modell gibt uns eine Wahrscheinlichkeitsverteilung P für das nächste Zeichen. Wir werden die möglichen Zeichen in zwei Klassen unterteilen: codiert und nicht codiert . Wenn das richtige Zeichen nicht codiert ist, verwenden wir am Ende den "Zurückspulen" -Mechanismus, um einen Fehler ohne Kosten in der Länge zu akzeptieren. Wenn das richtige Zeichen codiert ist, verwenden wir eine andere Verteilung Q, um es mit arithmetischer Codierung zu codieren.
Aber welche Verteilung Q sollten wir wählen? Es ist nicht schwer zu erkennen, dass die codierten Zeichen alle eine höhere Wahrscheinlichkeit (in P) haben sollten als die nicht codierten Zeichen. Außerdem sollte die Verteilung Q nur die codierten Zeichen enthalten. Schließlich codieren wir nicht die anderen, also sollten wir keine Entropie für sie "ausgeben". Es ist etwas schwieriger zu erkennen, dass die Wahrscheinlichkeitsverteilung Q für die codierten Zeichen proportional zu P sein sollte. Wenn wir diese Beobachtungen zusammenfassen, bedeutet dies, dass wir die wahrscheinlichsten Zeichen, aber möglicherweise nicht die unwahrscheinlichsten Zeichen codieren sollten und dass Q für die codierten Zeichen einfach P-neu skaliert wird.
Es stellt sich außerdem heraus, dass es einen coolen Satz gibt, welchen "Cutoff" man für die Codierungszeichen auswählen sollte: Sie sollten ein Zeichen codieren, solange es mindestens 1 / 5.393 so wahrscheinlich ist wie die anderen codierten Zeichen zusammen. Dies "erklärt" das Auftreten der scheinbar zufälligen Konstante
5.393
am Ende des obigen Programms. Die Zahl 1 / 5.393 ≈ 0.18542 ist die Lösung der Gleichung -p log (16) - p log p + (1 + p) log (1 + p) = 0 .Vielleicht ist es eine vernünftige Idee, diese Prozedur in Code zu schreiben. Dieses Snippet ist in C ++:
Alles zusammen
Der vorherige Abschnitt ist leider ein wenig technisch, aber wenn wir alle anderen Teile zusammenfügen, ist die Struktur wie folgt. Wann immer das Programm aufgefordert wird, das nächste Zeichen nach einem bestimmten korrekten Zeichen vorherzusagen:
Die Codierung der Hinweisdatei funktioniert ähnlich. In diesem Fall weiß das Programm, was das richtige nächste Zeichen ist. Wenn es sich um ein Zeichen handelt, das codiert werden soll, sollte natürlich der arithmetische Encoder verwendet werden. Wenn es sich jedoch um ein nicht codiertes Zeichen handelt, wird der Status des arithmetischen Codierers nicht aktualisiert.
Wenn Sie den informationstheoretischen Hintergrund wie Wahrscheinlichkeitsverteilungen, Entropie, Komprimierung und arithmetische Codierung verstehen, diesen Beitrag aber nicht verstanden haben (außer warum der Satz wahr ist), lassen Sie es uns wissen und wir können versuchen, die Dinge aufzuklären. Danke fürs Lesen!
quelle
B
Datei zu generieren . Wenn ja, können Sie das bitte in Ihre Antwort aufnehmen?Python 3, 2 · 267 + 510193 = 510727
Prädiktor
Dies verwendet eine gewichtete Bayes'sche Kombination der Ordnung 0,…, 16 Markov-Modelle mit Gewichten [1, 6, 12, 30, 65, 99, 87, 117, 118, 89, 95, 118, 96, 184, 126, 219, 126].
Das Ergebnis ist nicht sehr empfindlich in Bezug auf die Auswahl dieser Gewichte, aber ich habe sie optimiert, weil ich denselben Algorithmus für die späte Akzeptanz des Bergsteigens verwenden konnte, den ich in meiner Antwort auf die Frage "Stellen Sie eine Senatsmehrheit zusammen" verwendet habe , bei der es sich um jede mögliche Mutation handelt Nur ein ± 1-Inkrement zu einem einzelnen Gewicht.
Code testen
quelle
b"\0\3\6\r\34'&-20'\22!P\n[\26"
Ist die ASCII-Darstellung der Gewichte, bei der kleine nicht druckbare Werte in Oktal maskiert werden.Python 3 ,
2 × 279 + 592920 = 5934782×250 + 592467 = 5929672×271 + 592084 = 5926262×278 + 592059 = 5926152×285 + 586660 = 5872302×320 + 585161 = 5858012×339 + 585050 = 585728Probieren Sie es online!
Eine Funktion, die globale Variablen verwendet. Lernt, wie es geht, und baut ein Modell auf Wortebene: Was ist der häufigste nächste Charakter, wenn man bedenkt , was in diesem Wort bisher gesehen wurde ? Je mehr Eingaben eingehen, desto besser lernt es gebräuchliche Wörter aus dem Text und desto häufiger wird das Zeichen zum Starten des nächsten Wortes gelernt .
Zum Beispiel:
Am Anfang ist es nicht besonders gut, aber am Ende kommen große Teile der tatsächlichen Wörter heraus. Die Fallback-Option ist ein Leerzeichen und nach einem einzelnen Leerzeichen ein "a", es sei denn, der vorangegangene Buchstabe war "nedtfo", eine Ziffer oder ein Bindestrich oder Apostroph. Außerdem werden Zeilenumbrüche nach 71 Zeichen aggressiv vorhergesagt, oder wenn nach 66 ein Leerzeichen erwartet wurde. Beide wurden nur auf die Daten abgestimmt ("t" ist nach einem Leerzeichen weitaus häufiger, wurde jedoch bereits häufiger vorhergesagt, sodass " a "ist eine bessere Vermutung außerhalb dieser sechs Sonderfälle).
Zu lernen, welche Wortpaare zusammengehören, und die Zuordnung vorzubereiten, erwies sich als nicht lohnenswert.
Es endet mit folgendem Text:
Das entspricht diesem Teil der Eingabe:
Sie können sehen, wo die Eigennamen besonders gut herauskommen, aber die Wortenden stimmen meistens auch. Wenn es "dou" gesehen wird, erwartet es "Zweifel", aber sobald das "l" erscheint, wird es "doubloon".
Wenn Sie es ein zweites Mal mit demselben Modell ausführen, das es gerade erstellt hat, werden sofort weitere 92.000 korrekt angezeigt (51,7% -> 59,3%), aber ab der zweiten Iteration sind es immer knapp 60%.
Der Messcode befindet sich im TIO-Link oder hier ist eine etwas bessere Version:
guess.txt
hat die erratene Ausgabe am Ende.quelle
C ++, Ergebnis: 2 · 132 + 865821 = 866085
Vielen Dank an @Quentin für das Speichern von 217 Bytes!
Eine sehr einfache Lösung, bei der für ein bestimmtes Zeichen nur das Zeichen ausgegeben wird, das am häufigsten nach dem eingegebenen Zeichen erscheint.
Überprüfen Sie die Punktzahl mit:
Bearbeiten: Mit erhalten Sie
whale2.txt
eine bessere Punktzahl.quelle
L
, um eine Reihe von Zeichen zu speichern :)Python, 2 · 516 + 521122 = 522154
Algorithmus:
Bei einer weiteren Python-Übermittlung berechnet dieser Algorithmus den wahrscheinlichsten nächsten Buchstaben, wobei Sequenzen der Länge 1, ..., l betrachtet werden. Die Summe der Wahrscheinlichkeiten wird verwendet, und es gibt einige Tricks, um bessere Ergebnisse zu erzielen.
Ergebnisse:
Meistens Kauderwelsch, obwohl man sieht, dass es gelegentlich auftaucht, wie zum Beispiel "Father Mapple".
Testcode:
Ziemlich einfach, gibt einige Textbeispiele an verschiedenen Stellen aus. Verwendet whale2.txt, da dadurch zusätzliche Logik zum Berechnen von Zeilenumbrüchen vermieden wird.
quelle
C (gcc) ,
6797876528928476 Bytes,679619652740 falsche VermutungenProbieren Sie es online!
Update: ~ 27000 Punkte bei aktualisierter Datei, 16 Punkte (8 Bytes) bei besserer Golffunktion.
Erläuterung
Dies funktioniert so, dass der Code beim Durchlaufen des Texts das letzte Zeichen speichert, das eine bestimmte 4-stellige Sequenz beendet hat, und diesen Wert zurückgibt. Ähnlich wie Arnauld oben, aber abhängig von der Wahrscheinlichkeit, dass zwei vorgegebene 4-Zeichen-Sequenzen auf die gleiche Weise enden.
Entgolft:
quelle
sh + bzip2, 2 * 364106 = 728212
2 * 381249 + 0 = 762498gefolgt von der bzip2-komprimierten whale2.txt mit dem ersten fehlenden Byte
Ignoriert seine Eingabe; gibt die richtige Antwort aus. Dies liefert eine Basislinie an einem Ende; daniero liefert am anderen ende eine grundlinie.
Builder-Skript:
E / A-Testkabelbaum (tcc; erste Zeile für gcc abschneiden). Dieses Testkabel kann von jedermann auf einer geeigneten Plattform verwendet werden, die ein vollständiges Programm einreicht, das Lese- / Schreib-E / A erwartet. Es werden Byte-für-Byte-E / A verwendet, um Betrug zu vermeiden. Das untergeordnete Programm muss die Ausgabe nach jedem Byte leeren, um ein Blockieren zu vermeiden.
quelle
but may not load any other external files, and your code may not access the whale.txt file in any way other than described above.
Klausel?nth
Zeit aufgerufen wird, erhält es das n-te Zeichen vonwhale.txt
oderwhale2.txt
und muss seine Vermutung für das ausgeben(n+1)th
Charakter." - Wie wird diese Anforderung erfüllt? Der Code zeigt beiwhale.txt
jeder Ausführung den gesamten Text an .Python 3 , 879766
Probieren Sie es online!
... Die
///
Antwort, die ein Leerzeichen ausgibt, erhält 10 Upvotes, während mein Code nur 3 bekommen kann ...Erläuterung:
Für jeden Charakter hat das Programm:
frequency[prev][char]
frequency[char]
die haben die Gesamtpunktzahl
Da es keine Möglichkeit gibt, eine große Datei zu TIO hochzuladen (außer Dennis zu fragen), wird im Beispiel, das über den TIO-Link ausgeführt wird, nur das Programm für einen kleinen Teil des Texts ausgeführt.
Im Vergleich zur älteren Antwort hat diese 362 falschere Zeichen, aber der Code ist um 255 Bytes kürzer. Der Multiplikator bewirkt, dass mein Beitrag eine niedrigere Punktzahl aufweist.
quelle
C #, 378 × 2 + 569279 = 570035
Bei diesem Ansatz wird eine Nachschlagetabelle verwendet, um das häufigste Zeichen nach einer bestimmten Zeichenfolge zu ermitteln. Die Schlüssel der Nachschlagetabelle haben maximal 4 Zeichen, daher aktualisiert die Funktion zuerst die Nachschlagetabelle mit dem aktuellen Zeichen und prüft dann nur, welches Zeichen nach den 4 vorhergehenden Zeichen, einschließlich des aktuellen Zeichens, am wahrscheinlichsten ist . Wenn diese 4 Zeichen nicht in der Nachschlagetabelle gefunden werden, wird ein Leerzeichen gedruckt.
Diese Version verwendet die
whale2.txt
Datei, da sie die Anzahl der erfolgreichen Vermutungen erheblich verbessert.Der folgende Code wird zum Testen der Klasse verwendet:
Der Code läuft in knapp 2 Sekunden. Nur zur Veranschaulichung: Dies erhalte ich, wenn ich die Größe der Schlüssel der Nachschlagetabelle ändere (einschließlich der Ergebnisse eines zweiten Durchlaufs ohne Zurücksetzen des Modells):
Es wäre interessant zu wissen, warum eine Schlüsselgröße von 4 Zeichen die beste Wahl für diesen Algorithmus ist.
Textvergleich
Original:
Neu erstellt:
Vermutungen:
Änderungsprotokoll
whale2.txt
und damit die Optimierung entfernt.quelle
Java 7, 1995 Zeichen, (1995 * 2 + 525158) 529148
Java ist zum Kotzen für kleine Programmgrößen. Wie auch immer, ich habe mehrere äußerst komplexe und knifflige Ansätze ausprobiert, die überraschend schlechte Ergebnisse hervorgebracht haben. Anschließend bin ich zurückgegangen und habe nur einen einfachen Ansatz gewählt, der zu einer geringeren Programmgröße und besseren Ergebnissen geführt hat.
Dieser Ansatz ist eigentlich sehr einfach. Die vorherigen x Zeichen (zusätzlich zu allen Teilzeichenfolgen dieser Zeichen) werden blind in eine Hash-Tabelle eingespeist, die dem aktuellen Zeichen zugeordnet ist. Anschließend wird verfolgt, welche Muster das aktuelle Zeichen am genauesten vorhersagen. Wenn Muster, die bestimmten Zeichen vorangehen, mehrmals vorkommen, können sie das Zeichen erfolgreich vorhersagen. Längeren Zeichenfolgen wird Vorrang eingeräumt, und es wird demjenigen Zeichen Vorrang eingeräumt, das am häufigsten auf eine bestimmte Zeichenfolge folgt. Dieser Algorithmus kennt weder die Art des Dokuments noch die englische Sprache.
Ich entschied mich dafür, 9 Zeichen zu verwenden und zu versuchen, möglichst ganze Wörter innerhalb der vorherigen 9 Zeichen zu finden. Wenn Sie nicht versuchen, die Wörter in den Zeichenfolgen abzugleichen, beträgt die optimale Länge 6 Zeichen, was zu mehreren tausend falschen Vorhersagen führt.
Eine interessante Beobachtung war, dass die Verwendung von 20 Zeichen beim ersten Mal zu schlechten Vorhersagen führte, bei nachfolgenden Durchgängen jedoch eine Genauigkeit von 99,9 Prozent. Der Algorithmus war im Grunde in der Lage, das Buch in überlappenden 20-Byte-Blöcken zu speichern, und dies war deutlich genug, um es zu ermöglichen, das gesamte Buch zeichenweise abzurufen.
quelle
Python 3,
2 × 497 + 619608 = 6206022 × 496 + 619608 = 620600Ich habe es unabhängig versucht, aber am Ende war es eine minderwertige Version von Michael Homers Antwort. Ich hoffe das macht meine Antwort nicht komplett obsolet.
Dadurch wird im Laufe der Zeit ein Wörterbuch mit Wörtern erstellt (grob definiert als Zeichenfolgen, die mit
oder abgeschlossen sind
\n
, wobei die Groß- und Kleinschreibung beachtet wird und Satzzeichen enthalten sind). Anschließend durchsucht es das Wörterbuch nach Wörtern, die mit dem beginnen, was es bisher über das aktuelle Wort wusste, sortiert die resultierende Liste nach der Häufigkeit des Auftretens (langsam) und errät, dass das nächste Zeichen das nächste Zeichen im häufigsten übereinstimmenden Wort ist. Wenn wir bereits das häufigste passende Wort haben oder es kein passendes Wort mehr gibt, wird es zurückgegeben.
Es baut auch ein ekelhaft ineffizientes Wörterbuch von Wortpaaren auf. Wenn Sie auf eine Wortgrenze stoßen, wird vermutet, dass das nächste Zeichen der erste Buchstabe des zweiten Wortes im häufigsten übereinstimmenden Wortpaar ist oder
t
keine Übereinstimmung vorliegt. Es ist jedoch nicht sehr klug. NachMoby
errät das Programm richtig , dass das nächste ZeichenD
, aber dann vergisst sie alles über den Kontext und in der Regel endet den Wal „Moby Duck“ Aufruf (weil das Wort „Dutch“ scheint in der ersten Hälfte des Textes häufiger zu sein ). Es wäre einfach, dies zu beheben, indem man Wortpaare gegenüber einzelnen Wörtern priorisiert, aber ich gehe davon aus, dass der Gewinn marginal ist (da er normalerweise ab dem dritten Zeichen korrekt ist und die Wortpaare überhaupt nicht hilfreich sind).Ich könnte dies tunen, um es besser mit dem bereitgestellten Text abzustimmen, aber ich denke nicht, dass das manuelle Tunen des Algorithmus basierend auf Vorkenntnissen der Eingabe wirklich im Geiste des Spiels liegt. und das hätte ich wahrscheinlich auch nicht tun sollen), das habe ich vermieden. Ich habe die bekannte Zeilenlänge der Eingabedatei ignoriert und stattdessen
\n
nach jeweils 13 Leerzeichen eingefügt - dies ist mit ziemlicher Sicherheit eine sehr schlechte Übereinstimmung. Die Hauptabsicht bestand darin, die Zeilenlänge angemessen zu halten, anstatt der Eingabe zu entsprechen.Der Code ist nicht gerade schnell (~ 2 Stunden auf meinem Computer), aber insgesamt stimmt ungefähr die Hälfte der Zeichen (49%). Ich erwarte, dass die Punktzahl geringfügig besser wäre, wenn sie weiterlaufen würde
whale2.txt
, aber das habe ich nicht getan.Der Start der Ausgabe sieht folgendermaßen aus:
aber am Ende sieht es ein bisschen mehr nach ... etwas aus. Meine Lieblingspassage vom Ende des Buches,
kommt als raus
Das hätte The Wrath of Khan viel verwirrender gemacht. Und "einsam" → "prickelnd" ist eine besonders befriedigende Substitution.
Bearbeiten: Speichert ein Byte durch Löschen eines nicht benötigten Speicherplatzes
Wertung
Dies führt das Programm für den Text von Moby Dick aus und gibt den "vorhergesagten" Text an stdout aus und missbraucht stderr, um die Partitur zu schreiben. Ich würde empfehlen, die Ausgabe in eine Datei umzuleiten.
quelle
lambda i:i[1]
billiger als der Umgang mitoperator
?C ++, 2 · 62829 + 318786 = 444444
Um dieses Programm auszuführen, benötigen Sie diese Datei hier , die benannt werden muss
C
.Das Programm verwendet dieselbe Kombination von Markov-Modellen wie in unserer vorherigen Antwort . Nach wie vor ist diese Kombination im Wesentlichen das Modell aus dieser Antwort von user2699 , jedoch mit ein paar kleinen Änderungen.
Da in dieser Antwort genau dasselbe Modell wie zuvor verwendet wird, ist die Verbesserung ein besserer informationstheoretischer Mechanismus als der zuvor beschriebene "Rückspul" -Mechanismus. Dies ermöglicht es, weniger Fehler zu machen und gleichzeitig eine kleinere kombinierte Länge zu haben. Das Programm selbst spielt nicht viel Golf, weil es nicht den Hauptbeitrag zur Punktzahl leistet.
Das Programm ist 2167 Bytes lang (einschließlich aller Registerkarten für Vertiefung und vielen anderen unnötiger Zeichen, aber vor dem Testcode) und die Binär - Datei
C
ist 60661 Bytes lang, so dass nach den Regeln für mehrere Dateien Scoring , wir punktenL
als 2.167 + 60661 + 1 = 62829.Die Ausführung des Programms auf einer
m5.4xlarge
Instanz unter Amazon EC2 dauert ungefähr 8 Minuten und beansprucht etwas mehr als 16 GB Speicher. (Diese übermäßige Speichernutzung ist nicht erforderlich - wir haben sie auch nicht optimiert.)quelle
Python 3, 526640
274 Bytes, 526092 Fehler (mit
whale2.txt
). Dies ist definitiv noch verbesserungsfähig, hat aber das Stadium "Gut genug, um zu posten" erreicht.Die Idee ist, die Häufigkeiten aller Läufe von 2, 3, 4, ..., 10 Zeichen zu speichern. Für jede dieser Längen L prüfen wir, ob die neuesten L-1-Zeichen mit einem gespeicherten Muster übereinstimmen; in diesem Fall ist unsere Schätzung g L das häufigste nächste Zeichen nach diesem Muster. Auf diese Weise sammeln wir bis zu neun Vermutungen. Um zu entscheiden, welche Schätzung verwendet werden soll, gewichten wir die Frequenz jedes Musters durch seine Länge mit der 8. Potenz. Die Schätzung mit der größten Summe gewichteter Frequenzen wird ausgewählt. Wenn es keine übereinstimmenden Muster gibt, schätzen wir den Raum.
(Die maximale Musterlänge und der Gewichtungs-Exponent wurden durch Ausprobieren ausgewählt, um die wenigsten falschen Schätzungen zu erhalten.)
Hier ist meine ungolfed work-in-progress-Version:
Und das Testgeschirr:
Hier ist ein Beispiel für die Ausgabe am Anfang des Textes. Schon beginnen wir die Fähigkeit zu sehen , gemeinsame Worte zu beenden nach ihrem ersten Brief zu sehen (
in
,to
,and
,by
, auch anscheinendschool
).Gegen Ende gibt es immer noch viele Fehler, aber auch viele sehr gute Sequenzen (
shmage seashawks
zum Beispiel).Es ist interessant, sich einige der Fehler anzusehen und zu erraten, welches Wort der Algorithmus "erwartet" hat. Zum Beispiel, nachdem
sail
das Programm beide Maleo
vorausgesagt hatsailor
, nehme ich an. Oder wieder, nachdem, a
es erwartet hat -n
möglicherweise wegen des häufigen Auftretens von, and
.Änderungsprotokoll:
quelle
Python 2, Punktzahl: 2 * (407 + 56574) + 562262 = 676224
Sucht nach Wörtern, die mit den vorherigen Zeichen übereinstimmen, aus einer Liste
allerim Text verwendeten Wörter, sortiert nach der Anzahl ihrer Vorkommen.Code:
Daten: https://www.dropbox.com/s/etmzi6i26lso8xj/d?dl=0
Testsuite:
Bearbeiten: Mit erhalten Sie
whale2.txt
eine bessere Punktzahl.quelle
C ++ (GCC), 725 × 2 + 527076 = 528526
Noch eine Präfix-Häufigkeitseinreichung. Laufen Sie weiter
whale2.txt
und erzielen Sie eine ähnliche (etwas schlechtere) Punktzahl als andere.Dieser findet gierig die längste Zeichenfolge, die mit einem Suffix der Historie beginnt, und wenn es mehrere Kandidaten gibt, Tiebreak mit kürzeren Zeichenfolgen.
Zum Beispiel: Wenn die letzten 7 Zeichen sind
abcdefgh
, und die Zeichenfolgeabcdefghi
undabcdefghj
erscheinen mit der größten Häufigkeit in allen Saiten der Formabcdefgh*
, wird der Ausgang entwederi
oderj
, Tie - Break mit kürzeren Suffixe (bcdefgh
,cdefgh
, ...).Aus unbekannten Gründen haben mehr als 7 und mein Computer nicht genug RAM, um es auszuführen. Selbst mit 7 muss ich alle Webbrowser schließen, um es auszuführen.
Testcode:
Ungolfed:
Beispielausgabe:
Dieser ist fast am Ende des Textes. Die meisten lange Wörter sind ziemlich genau vorhergesagt (
intervals
,pivot-hole
,distance
)Großbuchstaben scheinen nicht gut zu sein.
quelle
Python 2, 756837
Verwendet etwas, das Markov-Ketten sein könnte?
quelle
zlib.decompress('...')
auswertet auf{'G?':' ', 'G;':' ','G"':' ',.......}
unda
ist ein Wörterbuch , das von 2 Zeichen 1 Zeichen abbildet. Grundsätzlich 2-stellige Variante der Antwort von Steadybox .xxd
,hexdump
,uuencode
, Oder ähnlichHaskell, (1904 + 1621 + 208548 + 25646) * 2 + 371705 = 847143
Beispiel:
Verwendet drei vorberechnete Hilfsdateien:
seqwords
enthält die 236 häufigsten Wörter.wordsseq
enthält eine LZMA-komprimierte Sequenz dieser Wörter und für alle Wörter, die nicht zu den 236 häufigsten gehören, die Länge.dicttries
enthält für jede Wortlänge einen Entscheidungsbaum, der alle verbleibenden Wörter enthält. Aus diesen Versuchen werden Einträge ausgewählt, während wir gehen.Auf diese Weise erzielen wir eine signifikant niedrigere Fehlerrate als alle anderen verlustbehafteten Schemata. Leider ist die
wordsseq
Datei immer noch zu groß, um wettbewerbsfähig zu sein.Hier ist eine fertige Version, die die Dateien erstellt und die Analyse durchführt:
quelle
C ++ (WIP), 1923 × 2 + 1017344 = 1021190
Gegenwärtig handelt es sich bei dieser Lösung um eine WIP-Lösung, die nicht in die Gewinnzone gelangt. Auch wenn man bedenkt, dass die tatsächliche Codegröße kaum Einfluss auf die Punktzahl hat, dachte ich, ich sende meine Antwort zuerst, bevor ich mit der Mikrooptimierung beginne.
(Vollständiger Code hier verfügbar: https://github.com/BrainStone/MobyDickRNG - Beinhaltet die vollständige Programm- und Samensuche)
Diese Lösung basiert auf einem RNG. Zuerst analysiere ich den Text. Ich erstelle eine Karte, die das Vorkommen von zwei aufeinanderfolgenden Zeichen zählt. Dann erstelle ich eine Verbreitungskarte. Dies erfolgt alles statisch, sollte also in Übereinstimmung mit den Regeln erfolgen.
Während ich dann versuche, den Text auszudrucken, suche ich nach einem zufälligen Zeichen der möglichen. Während dies normalerweise zu schlechteren Ergebnissen führt als nur zur Ausgabe des häufigsten folgenden Buchstabens, könnte es wahrscheinlich Göttersamen geben, die bessere Ergebnisse liefern. Deshalb ist der Samen hart codiert. Ich bin gerade auf der Suche nach dem besten Samen. Und ich werde diese Antwort aktualisieren, sobald ich bessere Samen finde. Also bleibt auf dem Laufenden!
Wenn jemand selbst nach Saatgut suchen oder andere RNGs verwenden möchte, kann er das Repo nach Belieben teilen.
Methode zur Berechnung der Punktzahl: https://github.com/BrainStone/MobyDickRNG/blob/master/src/search.cpp#L15
Beachten Sie, dass die Gesamtpunktzahl im Moment die schlechteste ist, jedoch die Fehleranzahl bei der Ausgabe von Leerzeichen übertrifft. Und die Chancen stehen gut, dass die Punktzahl sinkt, wenn mehr Samen geprüft werden.
Änderungsprotokoll
Überprüfte Samen: 0-50000. Bewertung: 2305 * 2 + 1017754 = 1022364
Überprüfte Samen: 0-80000. Ergebnis: 1920 * 2 + 1017754 = 1021594 (-770)
Überprüfte Startwerte: 0-32000000. Bewertung: 1923 * 2 + 1017344 = 1021190 (-404)
quelle
Ruby, 1164418 (autsch)
Ich wollte nur sehen, wie gut ich es kann, ohne andere Antworten zu überprüfen.
Ich bin nicht sicher, ob dies zulässig ist, da es ein Literal enthält, das ich durch Analyse der Datei generiert habe, aber auch wenn es nicht so war, besteht nicht die Gefahr, dass jemand geschlagen wird.
Wie ich generiert habe
x
Zuerst habe ich
a.txt
mit folgendem generiert :Dann habe ich generiert
a.csv
:Dann habe ich es
x
mit dem folgenden Ruby-Skript analysiert :Wie ich getroffen habe
quelle
Python 3 , (146 * 2 + 879757) 880049 Bytes
Probieren Sie es online!
Ziemlich übersichtliche Häufigkeitstabelle. Jede Position in der Zeichenfolge entspricht dem ASCII-Code des aktuellen Zeichens (minus 10 = 0x0a = '\ n', das niedrigste Zeichen in der Datei), und das Zeichen an jedem Index ist das häufigste nächste Zeichen. Vorausgesetzt, ich habe die Frequenzen richtig berechnet ...
Getestet mit dem Code von user202729's Test
quelle
def f(c):return(" ">c)*c or"t ... e"[ord(c)-32]
?[Python 3] (644449 * 2 + 0) 1288898 Punkte
Perfekte Genauigkeit in nur 644449 Bytes
Der vollständige Code kann nicht in eine Antwort passen, daher habe ich ihn hier eingefügt und das große Binärzeichenfolgenliteral im Antworttext durch b '###' ersetzt.
Dies wird mit dem folgenden Code generiert, wobei "modified.py" die generierte Datei und "cheatsheet.txt" die Datei whale2.txt ist, die mit dem zweiten Zeichen beginnt.
Der Code kann ausgeführt werden, indem am Ende von "modified.py" Folgendes hinzugefügt wird. "whale2.txt" muss sich im selben Verzeichnis wie "modified.py" befinden, und die Ausgabe wird in "out.txt" geschrieben.
Diese Antwort greift nicht direkt auf whale.txt oder whale2.txt zu. Dabei werden vorhandene Standardkomprimierungsbibliotheken verwendet, die in den Regeln ausdrücklich zulässig sind.
quelle