1. Giriş
İşte bu soruna sistematik olarak yaklaşmanın bir yolu: Adam asmayı iyi oynayan bir algoritmanız varsa, o zaman her kelimenin zorluğunu programınızın o kelimeyi tahmin ederseniz alacağı yanlış tahminlerin sayısı olarak kabul edebilirsiniz.
2. Cellat stratejisi bir yana
Diğer bazı cevaplarda ve yorumlarda örtük bir fikir var, çözücü için en uygun stratejinin kararlarını İngilizce'deki harflerin sıklığına veya bazı derlemedeki kelimelerin sıklığına dayandırmak olacaktır. Bu baştan çıkarıcı bir fikir, ancak tam olarak doğru değil. Çözücü , ayarlayıcı tarafından seçilen kelimelerin dağılımını doğru bir şekilde modellerse en iyisini yapar ve bir insan belirleyici, kelimeleri nadirliklerine veya sık kullanılan harflerden kaçınmalarına göre seçebilir. Her ne kadar Örneğin, Eİngilizce olarak en sık kullanılan mektup, ayarlayıcı hep kelimelerinden seçerse JUGFUL, RHYTHM, SYZYGY, ve ZYTHUMdaha sonra mükemmel bir çözücüdür tahmin ederek başlamaz E!
Ayarlayıcıyı modellemeye yönelik en iyi yaklaşım bağlama bağlıdır, ancak sanırım bir tür Bayesçi tümevarımsal çıkarım, çözücünün aynı ayarlayıcıya veya bir grup benzer kurucuya karşı birçok oyun oynadığı bir bağlamda iyi sonuç verecektir.
3. Adam asmaca algoritması
Burada oldukça iyi (ama mükemmel olmaktan uzak) bir çözücüyü özetleyeceğim. Ayarlayıcıyı, sabit bir sözlükten tek tip olarak kelimeleri seçecek şekilde modeller. Bu bir var açgözlü algoritma : Her aşamada öyle özlüyor, tahmin içermeyen sözcük sayısını en aza indirir mektubu tahmin eder. Örneğin, şimdiye kadar hiçbir tahmin yapılmadıysa ve olası sözcükler DEED, DEADve DAREo zaman:
- eğer tahmin ederseniz
Dya da Eözledim yok;
- tahmin ederseniz
A, bir eksik var ( DEED);
- tahmin ederseniz
R, iki eksik ( DEEDve DEAD) vardır;
- başka bir harf tahmin ederseniz, üç eksik var.
Yani ya Dya Ebu durumda iyi bir tahmindir.
( Adam asmada doğru tahminlerin ücretsiz olduğuna işaret ettiği için yorumlarda bulunan Albay Panic'e teşekkürler - bunu ilk denememde tamamen unuttum!)
4. Uygulama
İşte bu algoritmanın Python'da bir uygulaması:
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. Örnek sonuçlar
Bu stratejiyi kullanarak bir koleksiyondaki her kelimeyi tahmin etmenin zorluğunu değerlendirmek mümkündür. Burada sistem sözlüğümdeki altı harfli kelimeleri ele alıyorum:
>>> 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))
Bu sözlükte tahmin edilmesi en kolay sözcükler (çözücünün bunları tahmin etmesi için gereken tahmin dizisiyle birlikte) aşağıdaki gibidir:
>>> 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')]
ve en zor kelimeler bunlar:
>>> 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')]
Bunların zor olmasının nedeni, tahmin ettikten sonra -UZZLEhala yedi olasılığın kalmasıdır:
>>> ' '.join(sorted(w for w in six_letter_words if w.endswith('uzzle')))
'buzzle guzzle muzzle nuzzle puzzle tuzzle wuzzle'
6. Kelime listesi seçimi
Elbette çocuklarınız için kelime listeleri hazırlarken, bilgisayarınızın sistem sözlüğüyle başlamazsınız, muhtemelen bileceklerini düşündüğünüz kelimelerin bir listesiyle başlarsınız. Örneğin, Vikisözlük'ün çeşitli İngilizce derlemelerde en sık kullanılan kelimelerin listelerine bakabilirsiniz .
Örneğin, 2006 yılı itibariyle Project Gutenberg'deki en yaygın 10.000 kelimede yer alan 1.700 altı harfli kelime arasında en zor on tanesi şunlar:
[(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 tarafından yazılan Forsyte Saga'da bir karakterdir ; kelime listesi küçük harfe dönüştürüldü, bu yüzden özel isimleri hızlıca kaldırmam mümkün değildi.)
f(w) = (# unique letters) * (7 - # vowels) * (sum of the positions of unique letters in a list, ordered by frequency). Oradan, işlevin aralığını üç bölüme ayırabilir ve bunlara zorluklarınız diyebilirsiniz.