誰がゴーストを勝ちますか?


8

ゴーストのゲームは、各ターンで交互に手紙を言う2人のプレイヤーの間で行われます。各時点で、これまでの文字は有効な英語の単語で始まる必要があります。敗者は、最初に完全な単語を完成させるプレーヤーです。したがって、たとえば、これまでの文字がEAGLの場合、有効な次の文字は "E"だけなので、次のプレイヤーは負けます。(「イーグルト」のような長い言葉があっても)

チャレンジ

あなたは、これまでの手紙を踏まえて、2人の完璧なプレーヤーを想定して勝者を決定するプログラムまたは関数を作成することになります。入力は、ゲームの現在の状態を表す文字列と、有効な単語の辞書を表す文字列のリストです。出力では、次に行くプレーヤーが勝つか負けるかを区別する必要があります。

細部

  • コードは、現在の状態が空の場合を処理する必要があります。ただし、辞書のどの単語も空ではないと想定できます。
  • 各入力文字列は小文字のASCII文字、つまりazのみで構成されていると想定できます。
  • 現在の状態を想定し、辞書内のすべての単語の最大文字数はそれぞれ80文字です。
  • 辞書は空でないことが保証されています(有効な最初の移動がない場合を回避するため)。
  • 「現在の状態」が有効であると想定することができます。現在の状態で始まる単語が必ずあるはずです。また、現在の状態がフルワードになることも、現在の状態のプレフィックスがフルワードになることもありません。
  • 辞書は、「英単語」がゲームで有効であると見なされるルールに従って事前にフィルターされます。たとえば、3文字以下の単語でゲームがまだ終了しないバリアントの場合、辞書は4文字以上の単語のみが含まれるように事前にフィルタリングする。
  • 辞書は事前に分類されていると想定できます。

辞書が次のとおりだとします。

abbot
eager
eagle
eaglet
earful
earring

次の現在の状態の場合、出力は次のようになります。

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

同様に、https://raw.githubusercontent.com/dschepler/ghost-word-list/master/wordlist.txt(Debianシステムでを使用して作成pcregrep '^[a-z]{4,80}$' /usr/share/dict/american-english)の単語リストの場合、可能なセッションは次のとおりです。

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

(そして、次の移動は「かすれた」を完了します。)

得点

これはです。各プログラミング言語のバイト単位の最短プログラムが優先されます。


レビューキューから、この課題は不明確だとは思いません。もしそうなら、理由を投稿してください。
mbomb007

締めくくる投票はしませんでしたが、質問には出力の説明を使用できると思います。出力はブール値でなければなりませんか?2つの値のうちの1つ?2つに分割された多くの値の1つですか?
ヤコブ

勝敗結果を導き出すのが簡単なことなら何でも大丈夫です。真偽の二分法(どちらかの順序)、または2つの値のいずれか、または正の整数と負の整数の結果などのようなもの
Daniel Schepler

@ mbomb007私は不明確なものとして投票しました。質問が分からないので、具体的に何がわかりにくいのかは言えません。私はこれを5回読みましたが、それでもタスクをまったく理解していません。
アドホックガーフハンター2017

@WheatWizard各プレーヤーは、部分的な単語が辞書内の単語のプレフィックスであるように、次の文字を選択する必要があります。そのような選択肢がなくなった場合、ゲームは最後に敗者になったプレイヤーで終了します。
mbomb007 2017

回答:


3

JavaScript、54バイト

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

次のように呼び出します:f(wordlist_as_array)(current_word_as_string)、勝つ場合はtrue、負ける場合はfalseを返します。

非常に悪いパフォーマンスT_T、小さなテストケースでのみ動作します。


1
うわー、それは独創的なnullチェックです!
ニール

1

Pythonの3135の 129 84バイト

Xcoder氏のおかげで-4バイト!

-Daniel Scheplerのおかげで-42バイト!

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})

オンラインでお試しください!

A 1は現在のプレーヤーが勝つ-1ことを示し、a は負けることを示します。



1
わかりませんが、131バイトですか?
Xcoder氏2017

私がgithubに投稿した空の状態の完全な61135語辞書では、完全に実行することができませんでした(すでに数分実行されています)。私が投稿したすべてのテストケースを妥当な時間内に実行できるようにする必要があるかどうかについて、ここでの習慣はわかりません。(サンドボックスの投稿では、最初はコードが「非常に非効率的」ではないという要件がありましたが、コメンターはそれを削除するか、漸近的な実行時間を指定することを提案しました-そして、「入力のサイズが線形」は制限が多すぎます。)
Daniel Schepler 2017

1
これは、中間セットを使用して重複する再帰呼び出しを排除する実験です。これにより、少なくとも数分で完全な辞書を処理できます。(別の簡略化も実験していたため、最終的には87バイトに減少します。)
Daniel Schepler 2017

@DanielScheplerいいね!私は再帰呼び出しを減らすために同様の方法で作業していましたが、あなたの方法ははるかに簡潔です!また、これをに減らすこともできますlambda
notjagan

0

PHP、192154100 98バイト

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

関数は1勝つために、負けるために戻りますNULL
電話をかけるt(string $word,array $dictionary)、オンラインで試してください

壊す

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バイト(非競合)

参考までに、これが私のリファレンス実装のゴルフ版です(私自身の挑戦なので、非競合としてマークされています)。これは、wパラメーター内の単語リストが(nullで終了する文字列の)nullで終了する配列であると想定しています。1次のプレイヤーが負けた0場合、または次のプレイヤーが勝った場合に戻ります。

#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();}

オンラインでお試しください。

展開してコメントしたバージョン:

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();
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.