絞首刑難易度の単語を「簡単」、「中」、または「難しい」に分類するアルゴリズム


114

指定された難易度に一致する単語をゲームが選択できるように、絞首刑執行人ゲームの単語の「難易度」を決定するための適切なアルゴリズムは何ですか?

難易度は、必要な推測の数、文字の相対的な使用頻度(たとえば、珍しい文字が多い単語は推測が難しい場合がある)、および場合によっては単語の長さに関連しているように思われます。

単語がプレーヤーの語彙に含まれている可能性や、単語の頻度だけに基づく推測戦略から、既知の一致する単語。

私の今の試みはルビーの下にあります。分類を改善する方法について何か提案はありますか?

def classify_word(w)
  n = w.chars.to_a.uniq.length # Num. unique chars in w
  if n < 5 and w.length > 4
    return WordDifficulty::Easy
  end
  if n > w.length / 2
    return WordDifficulty::Hard
  else
    return WordDifficulty::Medium
  end
end

私は子供たちに遊んでもらいたい絞首刑執行人ゲームを書いています。私はかなり古すぎて「宿題」をしようとしないので、質問が非常に多くの反対票を受け取っているのかもしれません...単語は、多数のあいまいな単語を含む大きな単語データベースからランダムに抽出され、難易度によってフィルタリングされています言葉のために決定した。


12
なぜ反対票?これはまともな質問です。のような難易度の関数を作成しますf(w) = (# unique letters) * (7 - # vowels) * (sum of the positions of unique letters in a list, ordered by frequency)。そこから、関数の範囲を3つのセグメントに分割し、それらを難易度と呼ぶことができます。
Blender 2013

2
これについてウェブ検索を行うことをお勧めします。おそらく、単語の複雑さを計算/報告することを意図したアルゴリズムまたは辞書があるでしょう。私は長いテキストがあることを知っています。
Hot Licks 2013

3
関連:youtube.com/watch?v=bBLm9P - ph6U(QI XL-ハングマンで推測するのが最も難しい言葉)
クラウスヨルゲンセン2013

5
何をするにせよ、必ずEXTINCTIONSPECTROPHOTOPOLERISCOPEOCCULOGRAVOGYROKYNETOMETERを含めるようにしてください。
Hot Licks 2013

2
Rubyに慣れていないユーザーのために、メソッドの最初の行が何をするか説明したいと思うかもしれません。n = w.chars.to_a.uniq.lengthユニークな文字の数を数えますか?
T Nguyen

回答:


91

1.はじめに

この問題に体系的に取り組む方法を次に示します。絞首刑に上手く機能するアルゴリズムがある場合、各単語の難易度を、その単語を推測する場合にプログラムがとる誤った推測の数とすることができます。

2.絞首刑戦略は別として

他のいくつかの回答とコメントには暗示的である考えがあります。ソルバーの最適な戦略は、英語での文字の頻度、またはコーパスでの単語の頻度に基づいて決定することです。これは魅惑的なアイデアですが、正しくありません。ソルバーは、セッターによって選択された単語の分布を正確にモデル化し、人間のセッターが希少性や頻繁に使用される文字の回避に基づいて単語を選択している場合に最適です。が、例えば、E英語で最も頻繁に使用される文字である、セッターは常に言葉から選択した場合はJUGFULRHYTHMSYZYGY、およびZYTHUM、その後、完璧なソルバーは推測して起動しませんE

セッターをモデル化するための最良のアプローチはコンテキストに依存しますが、ある種のベイズ帰納推論は、ソルバーが同じセッターまたは同様のセッターのグループに対して多くのゲームをプレイするコンテキストでうまく機能すると思います。

3.絞首刑アルゴリズム

ここでは、かなり良い(しかし完璧とはほど遠い)ソルバーの概要を説明します。固定辞書から一律に単語を選択するセッターをモデル化します。これは貪欲なアルゴリズムです。各段階で、ミスの数を最小限にする文字、つまり、推測を含まない単語を推測します。例えば、全くの推測では、これまで行われていない、と可能な単語がある場合DEEDDEADそしてDAREその後、:

  • Dまたはを推測した場合E、ミスはありません。
  • 推測するとA、1つのミス(DEED);
  • 推測するとR、2つのミスがあります(DEEDおよびDEAD);
  • 他の文字を推測すると、3つのミスがあります。

したがって、この状況ではどちらDEが適切な推測です。

(ハングマンでは正しい推測が自由であることを指摘してくれたコメントのパニック大佐に感謝します。最初の試みでこれを完全に忘れていました!)

4.実装

Pythonでのこのアルゴリズムの実装は次のとおりです。

from collections import defaultdict
from string import ascii_lowercase

def partition(guess, words):
    """Apply the single letter 'guess' to the sequence 'words' and return
    a dictionary mapping the pattern of occurrences of 'guess' in a
    word to the list of words with that pattern.

    >>> words = 'deed even eyes mews peep star'.split()
    >>> sorted(list(partition('e', words).items()))
    [(0, ['star']), (2, ['mews']), (5, ['even', 'eyes']), (6, ['deed', 'peep'])]

    """
    result = defaultdict(list)
    for word in words:
        key = sum(1 << i for i, letter in enumerate(word) if letter == guess)
        result[key].append(word)
    return result

def guess_cost(guess, words):
    """Return the cost of a guess, namely the number of words that don't
    contain the guess.

    >>> words = 'deed even eyes mews peep star'.split()
    >>> guess_cost('e', words)
    1
    >>> guess_cost('s', words)
    3

    """
    return sum(guess not in word for word in words)

def word_guesses(words, wrong = 0, letters = ''):
    """Given the collection 'words' that match all letters guessed so far,
    generate tuples (wrong, nguesses, word, guesses) where
    'word' is the word that was guessed;
    'guesses' is the sequence of letters guessed;
    'wrong' is the number of these guesses that were wrong;
    'nguesses' is len(guesses).

    >>> words = 'deed even eyes heel mere peep star'.split()
    >>> from pprint import pprint
    >>> pprint(sorted(word_guesses(words)))
    [(0, 1, 'mere', 'e'),
     (0, 2, 'deed', 'ed'),
     (0, 2, 'even', 'en'),
     (1, 1, 'star', 'e'),
     (1, 2, 'eyes', 'en'),
     (1, 3, 'heel', 'edh'),
     (2, 3, 'peep', 'edh')]

    """
    if len(words) == 1:
        yield wrong, len(letters), words[0], letters
        return
    best_guess = min((g for g in ascii_lowercase if g not in letters),
                     key = lambda g:guess_cost(g, words))
    best_partition = partition(best_guess, words)
    letters += best_guess
    for pattern, words in best_partition.items():
        for guess in word_guesses(words, wrong + (pattern == 0), letters):
            yield guess

5.結果の例

この戦略を使用すると、コレクション内の各単語を推測する難しさを評価できます。ここで、システム辞書の6文字の単語について考えます。

>>> words = [w.strip() for w in open('/usr/share/dict/words') if w.lower() == w]
>>> six_letter_words = set(w for w in words if len(w) == 6)
>>> len(six_letter_words)
15066
>>> results = sorted(word_guesses(six_letter_words))

この辞書で推測する最も簡単な単語は、(ソルバーが推測するために必要な一連の推測と合わせて)次のとおりです。

>>> from pprint import pprint
>>> pprint(results[:10])
[(0, 1, 'eelery', 'e'),
 (0, 2, 'coneen', 'en'),
 (0, 2, 'earlet', 'er'),
 (0, 2, 'earner', 'er'),
 (0, 2, 'edgrew', 'er'),
 (0, 2, 'eerily', 'el'),
 (0, 2, 'egence', 'eg'),
 (0, 2, 'eleven', 'el'),
 (0, 2, 'enaena', 'en'),
 (0, 2, 'ennead', 'en')]

そして最も難しい言葉はこれらです:

>>> pprint(results[-10:])
[(12, 16, 'buzzer', 'eraoiutlnsmdbcfg'),
 (12, 16, 'cuffer', 'eraoiutlnsmdbpgc'),
 (12, 16, 'jugger', 'eraoiutlnsmdbpgh'),
 (12, 16, 'pugger', 'eraoiutlnsmdbpcf'),
 (12, 16, 'suddle', 'eaioulbrdcfghmnp'),
 (12, 16, 'yucker', 'eraoiutlnsmdbpgc'),
 (12, 16, 'zipper', 'eraoinltsdgcbpjk'),
 (12, 17, 'tuzzle', 'eaioulbrdcgszmnpt'),
 (13, 16, 'wuzzer', 'eraoiutlnsmdbpgc'),
 (13, 17, 'wuzzle', 'eaioulbrdcgszmnpt')]

これらが難しい理由は-UZZLE、を推測した後でも、7つの可能性が残っているためです。

>>> ' '.join(sorted(w for w in six_letter_words if w.endswith('uzzle')))
'buzzle guzzle muzzle nuzzle puzzle tuzzle wuzzle'

6.単語リストの選択

もちろん、子供用の単語リストを作成するときは、コンピューターのシステム辞書から始めるのではなく、子供が知っていると思われる単語のリストから始めます。たとえば、さまざまな英語のコーパスで最も頻繁に使用される単語のウィクショナリー一覧をご覧ください。

たとえば、2006年現在のProject Gutenbergの最も一般的な10,000の単語のうち1,700の6文字の単語のうち、最も難しい10の単語は次のとおりです。

[(6, 10, 'losing', 'eaoignvwch'),
 (6, 10, 'monkey', 'erdstaoync'),
 (6, 10, 'pulled', 'erdaioupfh'),
 (6, 10, 'slaves', 'erdsacthkl'),
 (6, 10, 'supper', 'eriaoubsfm'),
 (6, 11, 'hunter', 'eriaoubshng'),
 (6, 11, 'nought', 'eaoiustghbf'),
 (6, 11, 'wounds', 'eaoiusdnhpr'),
 (6, 11, 'wright', 'eaoithglrbf'),
 (7, 10, 'soames', 'erdsacthkl')]

(Soames Forsyteは、John GalsworthyによるForsyte Sagaのキャラクターです。ワードリストは小文字に変換されているため、適切な名前をすばやく削除することはできませんでした。)


1
頻繁に使用される単語リストをお見逃しなく。invokeit.wordpress.com/frequency-word-listsは英語とスウェーデン語を持っているので、両方あると便利です。
grrussel 2013

1
私が期待するbingleよりも難しい定格が定められているsingletingle- bingleあまり一般的な単語である bあまり一般的ではない手紙である
BlueRaja -ダニーPflughoeft

5
クールなアルゴリズム(そして、コードを書く前に英語で説明してくれてありがとう!)しかし、私はあなたが間違った推測の数を最小限に抑えるように努めるべきだと思います。したがって、辞書が[bat、bet、hat、hot、yum]だった場合、(B、A、Hではなく)Tを推測します。私が正しいなら、それは私に何の費用もかかりません。私が間違っていると、「ヤム」だけが残ります。
大佐パニック

8
これは本当にクールなアルゴリズムですが、人間のプレイヤーが行う可能性が高い戦略を反映していないと思います。すべての単語を知る代わりに、人間は最も一般的な単語を(確率的に)認識し、そうでなければ十分性を認識しようとします。接頭辞(ion、ingなど)および一般的な文字を推測するだけの失敗(母音で始まり、t / r / s / n / etcを実行)。これをどのようにコーディングするかわからないが、それについて考える必要がある:)
Patashu 2013

2
素晴らしい分析。@Patashuが指摘するように、これをさらに改善するための次のステップは、一般的な単語の辞書を取るだけでなく、単語の完全な辞書を取るが、共通性についての注釈を付け、単純にヒューリスティックに単語の共通性を検討することです。手紙の配布の難しさ。しかし、それはオプションの改善のためだけです-これは現状ではすでに優れたソリューションです。
ベン・リー

21

本当に簡単な方法は、単語の母音の欠如、一意の文字の数、および各文字の共通性に基づいてスコアを計算することです。

letters = 'etaoinshrdlcumwfgypbvkjxqz'
vowels = set('aeiou')

def difficulty(word):
    unique = set(word)
    positions = sum(letters.index(c) for c in word)

    return len(word) * len(unique) * (7 - len(unique & vowels)) * positions

words = ['the', 'potato', 'school', 'egypt', 'floccinaucinihilipilification']

for word in words:
    print difficulty(word), word

そして出力:

432 the
3360 potato
7200 school
7800 egypt
194271 floccinaucinihilipilification

次に、次のように単語にスコアを付けます。

        score < 2000   # Easy
 2000 < score < 10000  # Medium
10000 < score          # Hard

こんにちは、ブレンダーです。マジックナンバー7の意味を教えてください。なぜ6または50ではないのですか?別の番号を入力するとどうなりますか?
Pavan

@パヴァン:本当に何もない。すべての単語のスコアが同じ量だけシフトアップされます。
Blender

ええ、私はオンラインのpythonエグゼキューターで遊んでいたときにシフトに気づきました。私は何かに気づきました、そしてそれは私が忌まわしいものと比較して幻想的なもののようなものを入力するとき、幻想的なものはより正確に綴られた単語であるため、忌まわしさは幻想的なものよりも低い値を持つでしょう、したがって単語ゲームの低い難易度レベルで現れるはずです。これにより、難しさは主観的であることがわかりましたが、どの単語を他の単語の上に重ねるのが最も難しいかを概説するために、ある種の研究を行う必要があると思いました。そのような研究plsを私に指摘してもらえますか?
Pavan

あるいは、最初の試行で単語のスペルを間違えた人のパーセンテージで単語のコレクションを見つけるのが難しいので、少なくともそのような研究が呼び出されるでしょう-これは私が今求めていることです。
Pavan

9

モンテカルロ法を使用して、単語の難易度を推定できます。

  • ランダムな文字を毎回推測し、ターゲット言語での文字の頻度で重み付けしてゲームをシミュレートし、ランダム化されたプレーヤーが解に到達するまでにかかった推測の数を数えます。それぞれの推測は文字を排除するため、このプロセスは有限であり、1から26までの数値を返します。
  • このプロセスを繰り返します2*N。ここで、Nは単語内の一意の文字の数です。
  • 2*N実行結果を平均してスコアを計算し、
  • 複雑さのレベルを決定します。10未満のスコアは簡単な単語を示し、16を超えるスコアは難しい単語を示します。他はすべて中程度です。

2
間違った推測だけを数えるべきだと思います。正しい推測にペナルティはありません。
大佐パニック

なぜその数の繰り返しですか?この戦略(ほとんどのランダム化された戦略と同様)は、短い単語の方が分散が大きいと思います。
大佐パニック

@ColonelPanic個別の文字の数を自然に回答に組み込むため、推測の総数をカウントする方が良いと思います。あなたは短い単語の差異が高いほど正しいかもしれません。おそらく、リピートの数を固定する必要があります。しかし、2Nは大丈夫だと思います。
dasblinkenlight 2013

4

同じトピックに関する以前の同様の議論: 英語の単語の難易度を決定する

リンク先の答えが好きです^。キッズハングマンゲームの場合は、スクラブルのようなアプローチを適用します。

各文字にポイント値を割り当てて、文字を合計します。


1
これは、簡単なレベルで珍しい単語やあいまいな単語を回避することと相まって、今のところ進むべき道のようです。私が言及しなかった複雑さは、単語が巨大な辞書から選択されていることです。その大部分は、定義によってほとんど使用されない単語でなければなりません:-)
grrussel

ポイント値が機能し、文字の頻度が使用される可能性があります。ただし、一般的に使用される単語の中には、実際には奇妙に高いポイント値を持つものもあります。
Nuclearman 2013

3

しばらく前に私は明白なアルゴリズムを使用して絞首刑執行人ソルバーを書きました:可能なすべての単語の初期辞書が与えられたら、各ターンで、辞書に残っているほとんどの単語に出現する文字を選択し、次に一致しない単語を削除します(応答)辞書から。

アルゴリズムはこれほど簡単ではありません。辞書にある同じ数の単語の中に複数の文字が含まれていることが多いためです。この場合、文字の選択によって、単語に必要な推測の数に大きな違いが生じます。その文字の配置に関する結果の情報(実際に単語にある場合)がシステムに関する最大の情報(最大の情報エントロピーを持つ文字)を提供する最大値を選択します。たとえば、残りの2つの単語が「百科事典」と「百科事典」の場合、文字「c」はe、n、y、l、o、p、e、d、iと同じ確率で表示されます(つまり、単語に含まれることが保証されています)が、ゼロ以外の情報エントロピーがあるため、最初に「c」について質問する必要があります。

ソース(C ++、GPL)はこちら

これらすべての結果は、単語のリストであり、それぞれに必要な推測の数が含まれています。難易度 .txt(630KB)。このアルゴリズムが見つけるのが最も難しい単語は「意志」です(14回の推測が失敗)。iとdouble lはかなりすばやく推測されますが、オプションには、bill、dill、fill、gill、hill、kill、mill、pill、rill、till、willが含まれ、それ以降は、各文字を推測することしかできません。順番。多少直観に反して、長い単語ははるかに迅速に推測されます(選択できるものはありません)。

もちろん、絞首刑執行人の人間のゲームでは、心理学(および語彙の幅)は、このアルゴリズムが説明するよりもはるかに大きな役割を果たす...


3

早くやれよ!言葉に対して絞首刑執行人を果たしています。打ち負かすのにいくつの失効(すなわち、間違った推測)を数える。

プレイするには戦略が必要です。これが人間的(戦略的)な戦略です。辞書から、これまで明らかにしていない単語をすべて削除します。残っている単語の中で最も頻度の高い文字を推測してください。

戦略がランダム化されている場合は、メジャーを予想される失効数として定義し、それを経験的に見積もることができます。


数年前に書いた絞首刑執行人ボットからのもう1つの確定的戦略。推測が正しくない場合に残っている単語の数を最小限にする文字を推測します(つまり、最悪の場合を最適化します)。今日、私はこの戦略が機械的すぎるのが嫌いです。私は上記の戦略を好みます。


はは、私は同じことを提案するつもりだった。しかし、深刻なバージョン:いくつかの単純な戦略を使用して推測する単純なボットを作成し、それを辞書の単語に対して何度も実行します。
Tikhon Jelvis 2013

はい、それは私が意味したことです!
大佐パニック

2

もちろん、最初に、一意の文字のリストを生成します。次に、頻度で並べ替えます(英語または任意の言語- これにはリストがあります)。頻度の低い文字ほど難易度が高くなります。

次に、スコアを組み合わせるか、乗算するか、他のスキームを使用するかを決定する必要があります。


(実際には、頻度で並べ替える必要はないかもしれませんが、頻度のスコアを累積するだけです。並べ替えは、より多くの情報を提供するかもしれません-それがあなたのために何かをするように見えるかどうか確認するのに価値があります。)
Hot Licks

そして、どういうわけか文字のコンボを考慮したいかもしれません-つまり、Qがある場合、ほぼ確実にUがあり、UはQをはるかに可能にします。したがって、例えば、周波数POVから、QUを単一の文字と見なすことは理にかなっています。
Hot Licks 2013

1

非常に複雑なアルゴリズムを構築するように私たちに要求しているので、あなたは反対票を投じています。

3つの配列(easy、medium、hard)を作成して、それぞれに100語程度の単語を入れてみませんか?約20分かかります。

彼らが数百のゲームを焼き尽くすずっと前に、あなたの子供が首を絞める男に退屈することを約束します...:D


3
それはする必要はありませんように複雑。たとえば、Blenderのコメントを見てみましょう。あなたの答えは核心的な質問を実際に扱っておらず、特に有用ではありません。
Tikhon Jelvis 2013

4
「なぜ3つの配列(easy、medium、hard)を作成し、それぞれに100語程度の単語を入力しないのですか?」:「問題がすでに解決されていると仮定して問題を解決する」方法とも呼ばれます。
Pascal Cuoq 2013

批判を受けました、ありがとう...私は学問の観点から、あなたは完全に正しいと思います。私の答えは何も解決しません。しかし、実用的な観点から、つまり、子供のための絞首刑執行人ゲームを構築する最も簡単な方法から、私の答えはそれを安価かつ迅速に解決します。
BBagi 2013

1
@PascalCuoqまたは、これは「人間がアルゴリズムよりも適切なリストを選択することを好むと想定して問題を解決する」ためのアプローチであると言えるでしょう。質問者が子供向けのゲームを望んでいるとすれば、「帽子、猫、太陽」は簡単なリストにあり、「木琴、ノート、学校」は難しいリストにあるほうがよいでしょう。平均して。
ダレンクック2013年

1
@PascalCuoq複雑な問題を回避することで問題が回避できる場合は、簡単な解決策を使用しても問題はありません。楽しみのために複雑なアルゴリズムを構築することにも問題はありませんが、簡単な解決策は少なくとも言及に値します。
David

1

まあ、潜在的には多くのことが関与する可能性があります:

  1. みんなが言ったように、個々の手紙の頻度。
  2. 単語の長さは間違いなく数えられるべきですが、直線的な方法ではありません。長い単語はランダムな推測を文字に当てることができますが、短い単語は取得が難しい場合があります。
  3. また、単語自体も考慮する必要があります。「バイパータイト」はSOの人々にとっては単語かもしれませんが、技術者以外の人々にとってはそうではないかもしれません。

実際、いくつかの戦略を共進化させようとすることもできます。そのうちの半分は単語の価値を決定するためのもので、残りの半分はゲームに勝つためのものです。後者のグループはスコアを最大化しようとしますが、最初のグループはスコアを最小化しようとします。しばらくするとパターンができる可能性があり、単語の価値を決定するための半分はいくつかのベンチマークを与える可能性があります。


単語の使用頻度が良い点です。ユニークな文字を頻度でスコアリングすることに基づいた私の最初の試みは、「共融」と主張され、「簡単な」言葉でした。Google ngrams storage.googleapis.com/books/ngrams/books/datasetsv2.htmlは、今日一般的に使用されている単語の識別に役立つようです。
grrussel 2013

1

単語のリストから始めて、それぞれについてGoogle検索を起動します。ヒット数は、用語の難易度の(粗い)プロキシとして機能します。

洗練されたバージョンでは、類義語に基づいた同義関係によって単語をグループ化し、Google検索の結果を数えることで、カテゴリの最も難しい単語を特定します。

n-グラムの概念をさらに一歩進めると、単語の難しさは、散文中のその音節の頻度によって評価できます。もちろん、音節の統計の質に依存します。おそらく、語彙素と関数の単語(決定詞、接続詞など)を区別し、単語の音節の数で正規化する必要があります(Overkill like i Write ...のように感じます)。


0

ユーザーに応じて学習して変化するアルゴリズムを構築するのが好きです。最初に、リストを作成するように提案されたアルゴリズムを実装できます。その後、より多くの人がゲームをプレイするにつれて、推測の数に応じて各単語に重みを割り当てます(これも継続的に追跡および計算されます) )。これにより、複雑で人気のある単語に難しい評価が付けられても、よく知られているという問題が回避されます。


0

E = 1、D = 2、V = 4、X = 8などのスクラブルポイントで単語の各文字の値を計算します。それらを合計し、文字数で割って平均文字値を取得し、それを使用して単語をスコアリングします。大きな辞書の各単語の平均を計算し、四分位数間の区切り点を決定します。下位の四分位の単語を「簡単」、中央の2つの四分位の単語を「中」、上位の四分位の単語を「ハード」と呼びます。

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