Wer wird Ghost gewinnen?


8

Das Ghost-Spiel wird zwischen zwei Spielern gespielt, die abwechselnd in jeder Runde einen Buchstaben sagen. An jedem Punkt müssen die Buchstaben bisher ein gültiges englisches Wort beginnen. Der Verlierer ist der Spieler, der zuerst ein vollständiges Wort vervollständigt. Wenn zum Beispiel die Buchstaben bisher EAGL sind, ist der einzig gültige nächste Buchstabe "E" und der nächste Spieler verliert. (Auch wenn es längere Wörter wie "Adler" gibt.)

Die Herausforderung

Sie müssen ein Programm oder eine Funktion schreiben, um anhand der bisherigen Buchstaben zu bestimmen, wer unter der Annahme von zwei perfekten Spielern gewinnt. Die Eingabe ist eine Zeichenfolge, die den aktuellen Status des Spiels darstellt, und eine Liste von Zeichenfolgen, die das Wörterbuch gültiger Wörter darstellen. Die Ausgabe sollte unterscheiden, ob der nächste Spieler gewinnt oder verliert.

Einzelheiten

  • Der Code muss den Fall behandeln, in dem der aktuelle Status leer ist. Sie können jedoch davon ausgehen, dass kein Wort im Wörterbuch leer ist.
  • Sie können davon ausgehen, dass jede Eingabezeichenfolge nur aus ASCII-Kleinbuchstaben besteht, dh az.
  • Sie können den aktuellen Status annehmen und alle Wörter im Wörterbuch haben jeweils höchstens 80 Zeichen.
  • Das Wörterbuch ist garantiert nicht leer (um den Fall zu vermeiden, dass es keinen gültigen ersten Zug gibt).
  • Sie können davon ausgehen, dass der "aktuelle Status" gültig ist: Es wird notwendigerweise ein Wort geben, das mit dem aktuellen Status beginnt. Außerdem ist der aktuelle Status weder ein vollständiges Wort noch ein Präfix des aktuellen Status ein vollständiges Wort.
  • Das Wörterbuch wird nach den Regeln vorgefiltert, nach denen "englische Wörter" für das Spiel gültig sind. Bei einer Variante, bei der Wörter mit drei oder weniger Buchstaben das Spiel noch nicht beenden, wird das Wörterbuch vorgefiltert vorgefiltert werden, um nur die Wörter von vier oder mehr Buchstaben einzuschließen.
  • Sie können davon ausgehen, dass das Wörterbuch vorsortiert wird.

Beispiele

Angenommen, das Wörterbuch lautet:

abbot
eager
eagle
eaglet
earful
earring

Für die folgenden aktuellen Zustände sollte die Ausgabe dann wie folgt sein:

Current state   Result
=============   ======
                loss
a               win
eag             win
eagl            loss
ear             win
earf            win
earr            loss

Ebenso ist für die Wortliste unter https://raw.githubusercontent.com/dschepler/ghost-word-list/master/wordlist.txt (erstellt auf einem Debian-System unter Verwendung pcregrep '^[a-z]{4,80}$' /usr/share/dict/american-english) hier eine mögliche Sitzung:

Current state   Result
=============   ======
                win
h               loss
ho              win
hoa             loss
hoar            win
hoars           loss

(Und dann schließt der nächste Zug "heiser" ab.)

Wertung

Dies ist : Das kürzeste Programm in Bytes für jede Programmiersprache gewinnt.


Aus der Überprüfungswarteschlange denke ich nicht, dass diese Herausforderung unklar ist. Wenn Sie dies tun, geben Sie bitte an, warum.
mbomb007

Ich habe nicht für den Abschluss gestimmt, aber ich denke, die Frage könnte eine Beschreibung der Ausgabe verwenden. Muss die Ausgabe ein Boolescher Wert sein? Einer von zwei Werten? Einer von vielen Werten, die in zwei Teile geteilt sind?
Jakob

Ich bin mit allem einverstanden, von dem es trivial ist, ein Gewinn / Verlust-Ergebnis abzuleiten. Entweder eine wahrheitsgemäße / falsche Dichotomie (in beliebiger Reihenfolge) oder einer von zwei Werten oder so etwas wie ein positives oder ein negatives ganzzahliges Ergebnis usw.
Daniel Schepler

@ mbomb007 Ich habe als unklar abgestimmt. Ich kann nicht wirklich sagen, was speziell unklar ist, weil ich die Frage nicht verstehe. Ich habe es jetzt fünf Mal gelesen und verstehe die Aufgabe immer noch überhaupt nicht.
Ad-hoc-Garf-Jäger

@WheatWizard Jeder Spieler muss den nächsten Buchstaben so wählen, dass das Teilwort immer noch ein Präfix eines Wortes im Wörterbuch ist. Wenn es keine solchen Möglichkeiten mehr gibt, endet das Spiel mit dem letzten Spieler als Verlierer.
mbomb007

Antworten:


3

JavaScript, 54 Bytes

l=>g=w=>!(w+0)||l.some(t=>t==w||!g(t.match(`^${w}.`)))

Nennen Sie es so: f (wordlist_as_array) (current_word_as_string), es gibt true für win, false für lose zurück.

ziemlich schlechte Leistung T_T, arbeiten nur mit dem kleinen Testfall.


1
Wow, das ist ein genialer Null-Check!
Neil

1

Python 3 , 135 129 84 Bytes

-4 Bytes dank Mr. Xcoder !

-42 Bytes danke an Daniel Schepler !

g=lambda s,l:(s in l)or-min(g(w,l)for w in{w[:len(s)+1]for w in l if w[:len(s)]==s})

Probieren Sie es online aus!

A 1zeigt an, dass der aktuelle Spieler gewinnt, während a -1angibt, dass er verlieren wird.



1
Nicht sicher, aber 131 Bytes ?
Herr Xcoder

Auf dem vollständigen 61135-Wörter-Wörterbuch, das ich bei github und im leeren Zustand gepostet habe, konnte ich es nicht vollständig ausführen (es wurde bereits einige Minuten ausgeführt). Ich kenne den Brauch hier nicht, ob Sie in der Lage sein müssen, alle von mir veröffentlichten Testfälle in angemessener Zeit auszuführen. (Auf dem Sandbox-Post hatte ich anfangs die Anforderung, dass der Code nicht "schrecklich ineffizient" sein sollte, aber Kommentatoren schlugen vor, dies entweder zu löschen oder eine asymptotische Laufzeit anzugeben - und ich befürchtete, "linear in der Größe der Eingabe" zu sagen zu restriktiv.)
Daniel Schepler

1
Hier ist ein Experiment mit der Verwendung eines Zwischensatzes, um die doppelten rekursiven Aufrufe zu eliminieren. Damit ist es zumindest möglich, das gesamte Wörterbuch in wenigen Minuten zu verarbeiten. (Ich habe auch mit einer anderen Vereinfachung experimentiert, so dass das Nettoergebnis eine Abnahme auf 87 Bytes ist.)
Daniel Schepler

@ DanielSchepler Schön! Ich habe auf ähnliche Weise daran gearbeitet, rekursive Aufrufe zu reduzieren, aber Ihre Methode ist viel prägnanter! Es erlaubt mir auch, dies auf a zu reduzieren lambda.
Notjagan

0

PHP, 192 154 100 98 Bytes

function t($w,$d){foreach(preg_grep("#^$w#",$d)as$p)if($p==$w||!t($w.$p[strlen($w)],$d))return 1;}

Funktion kehrt 1für Gewinn, NULLfür Verlust zurück.
Rufen Sie an t(string $word,array $dictionary) oder probieren Sie es online aus .

Nervenzusammenbruch

function t($w,$d)
{
    // loop through matching words
    foreach(preg_grep("#^$w#",$d)as$p)if(
        $p==$w                      // if word is in dictionary (previous player lost)
        ||                          // or
        !t($w.$p[strlen($w)],$d)    // backtracking is falsy (next player loses)
    )
        return 1;                   // then win
    // implicit return NULL
}

0

C ++, 243 Bytes (nicht wettbewerbsfähig)

Zu Ihrer Information, hier ist die Golfversion meiner Referenzimplementierung (als nicht wettbewerbsfähig markiert, da es meine eigene Herausforderung ist). Es wird erwartet, dass die Wortliste im wParameter ein nullterminiertes Array (aus nullterminierten Zeichenfolgen) ist. Es kehrt zurück, 1wenn der nächste Spieler verliert oder 0wenn der nächste Spieler gewinnt.

#define r return
int g(char*s,char**w){struct N{int d=0;N*c[128]{};int l(){if(d)r 0;for(N*p:c)if(p&&p->l())r 0;r 1;}void a(char*s){*s?(c[*s]?:c[*s]=new N)->a(s+1),0:d=1;}N*f(char*s){r*s?c[*s]->f(s+1):this;}}d;for(;*w;d.a(*w++));r d.f(s)->l();}

Probieren Sie es online aus.

Erweiterte und kommentierte Version:

int g(char* s, char** w) {
    /// Node of the prefix tree
    struct N {
        int d = 0;  ///< 1 if the node represents a word in the dictionary
        N* c[128] {};  ///< child nodes, indexed by integer value of character

        // Optional, if you want to eliminate the memory leak from the
        // golfed version.  (Though actually in practice, I would make
        // "c" into std::array<std::unique_ptr<N>, 128> so the default
        // destructor would be sufficient.)
        // ~N() { for (N* p : c) delete p; }

        /// \retval 1 if the next player going from this node will lose
        /// \retval 0 if they will win
        int l() {
            if (d)
                return 0;  // last player lost, so the player who would
                           // have gone next wins
            for (N* p : c)
                if (p && p->l())
                    return 0;  // found a letter to play which forces the
                               // other player to lose, so we win
            return 1;  // didn't find any such letter, we lose
        }

        /// Add word \p s under this node
        void a(char* s) {
            *s ?
                (c[*s] ?: c[*s] = new N) // use existing child node or create new one
                ->a(s+1), 0  // the ,0 just makes the branches of
                             // the ternary compatible
            :
                d = 1;
        }

        /// Find node corresponding to \p s
        N* f(char* s) {
            return *s ?
                c[*s]->f(s+1)
            :
                this;
        }
    } d;  // d is root node of the prefix tree

    // Construct prefix tree
    for (; *w; d.a(*w++))
        ;

    // Find node for input, then run the "loser" method
    return d.f(s)->l();
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.