Questo è un gioco di parole da una serie di carte attività per bambini. Sotto le regole c'è il codice per trovare la migliore tripletta usando / usr / share / dict / words. Ho pensato che fosse un problema di ottimizzazione interessante e mi chiedo se le persone possano trovare miglioramenti.
Regole
- Scegli una lettera da ciascuno dei set seguenti.
- Scegli una parola usando le lettere scelte (e tutte le altre).
- Segna la parola.
- Ogni lettera del set scelto ottiene il numero mostrato con il set (ripetizioni incluse).
AEIOU
contare 0- Tutte le altre lettere sono -2
- Ripeti i passaggi 1-3 sopra (non riutilizzare le lettere nel passaggio 1) altre due volte.
- Il punteggio finale è la somma dei punteggi delle tre parole.
Imposta
(imposta 1 punti 1 punto, imposta 2 punteggi 2 punti, ecc.)
- LTN
- RDS
- GBM
- CHP
- FWV
- YKJ
- QXZ
Codice:
from itertools import permutations
import numpy as np
points = {'LTN' : 1,
'RDS' : 2,
'GBM' : 3,
'CHP' : 4,
'FWV' : 5,
'YKJ' : 6,
'QXZ' : 7}
def tonum(word):
word_array = np.zeros(26, dtype=np.int)
for l in word:
word_array[ord(l) - ord('A')] += 1
return word_array.reshape((26, 1))
def to_score_array(letters):
score_array = np.zeros(26, dtype=np.int) - 2
for v in 'AEIOU':
score_array[ord(v) - ord('A')] = 0
for idx, l in enumerate(letters):
score_array[ord(l) - ord('A')] = idx + 1
return np.matrix(score_array.reshape(1, 26))
def find_best_words():
wlist = [l.strip().upper() for l in open('/usr/share/dict/words') if l[0].lower() == l[0]]
wlist = [l for l in wlist if len(l) > 4]
orig = [l for l in wlist]
for rep in 'AEIOU':
wlist = [l.replace(rep, '') for l in wlist]
wlist = np.hstack([tonum(w) for w in wlist])
best = 0
ct = 0
bestwords = ()
for c1 in ['LTN']:
for c2 in permutations('RDS'):
for c3 in permutations('GBM'):
for c4 in permutations('CHP'):
for c5 in permutations('FWV'):
for c6 in permutations('YJK'):
for c7 in permutations('QZX'):
vals = [to_score_array(''.join(s)) for s in zip(c1, c2, c3, c4, c5, c6, c7)]
ct += 1
print ct, 6**6
scores1 = (vals[0] * wlist).A.flatten()
scores2 = (vals[1] * wlist).A.flatten()
scores3 = (vals[2] * wlist).A.flatten()
m1 = max(scores1)
m2 = max(scores2)
m3 = max(scores3)
if m1 + m2 + m3 > best:
print orig[scores1.argmax()], orig[scores2.argmax()], orig[scores3.argmax()], m1 + m2 + m3
best = m1 + m2 + m3
bestwords = (orig[scores1.argmax()], orig[scores2.argmax()], orig[scores3.argmax()])
return bestwords, best
if __name__ == '__main__':
import timeit
print timeit.timeit('print find_best_words()', 'from __main__ import find_best_words', number=1)
La versione a matrice è quella che mi è venuta in mente dopo averne scritto uno in puro pitone (usando dizionari e segnando ogni parola in modo indipendente), e un altro in modo intorpidito ma usando l'indicizzazione anziché la moltiplicazione con matrice.
La prossima ottimizzazione sarebbe quella di rimuovere completamente le vocali dal punteggio (e usare una ord()
funzione modificata ), ma mi chiedo se ci siano approcci ancora più veloci.
EDIT : aggiunto timeit.timeit code
EDIT : sto aggiungendo un premio, che darò a qualsiasi miglioramento mi piaccia di più (o possibilmente più risposte, ma dovrò accumulare un po 'più di reputazione se è il caso).