Генератор криптарифмов
- import re, itertools
- import codecs
- from collections import defaultdict
- from copy import copy
- def pattern(st):
- d={}
- rv=[]
- for l in st:
- if not(l in d):
- d[l]=len(d)
- rv.append(d[l])
- return tuple(rv)
- def substitutions_generator(st):
- words = re.split('[-*+]',st)
- letters = list(set(''.join(words)))
- first_letters = set([w[0] for w in words])
- for comb in itertools.combinations(range(10),len(letters)):
- d = dict(zip(letters,comb))
- if not any(d[k] == 0 for k in first_letters):
- yield d
- def eval_substitution(st,substitution):
- reverse_substitution = {}
- for k in substitution:
- reverse_substitution[str(substitution[k])] = k
- st = st.replace(k,str(substitution[k]))
- result = str(eval(st))
- tojd = st + "=" + result
- forbidden = set([]) #цифры, которые нельзя заменять буквами из substitution
- for k in reverse_substitution:
- if not(k in result):
- forbidden.add(reverse_substitution[k])
- else:
- result = result.replace(k,reverse_substitution[k])
- return result,tojd,forbidden
- def gen_indexes(path, limit = None):
- freq_dict = {}
- pattern_index = defaultdict(set)
- letters_order_index = defaultdict(set)
- words_list=[]
- letters_existance_index = defaultdict(set)
- for i,l in enumerate(codecs.open(path,"r","utf-8-sig")):
- if limit and i>limit:break
- w,n=l.split()
- words_list.append(w)
- index = len(words_list)-1
- freq_dict[index]=int(n)
- pattern_index[pattern(w)].add(index)
- for k in list(enumerate(w)):
- letters_order_index[k].add(index)
- for l in w:
- letters_existance_index[l].add(index)
- return words_list, pattern_index, letters_order_index, letters_existance_index, freq_dict
- def generate_cryptarithm(st, indexes):
- words_list, pattern_index, letters_order_index, letters_existance_index, freq_dict = indexes
- d=defaultdict(list)
- for sub in substitutions_generator(st):
- res,tojd,forbidden = eval_substitution(st,sub)
- cur_indexes=copy(pattern_index.get(pattern(res),set([])))
- if not cur_indexes:
- continue
- for lk in list(enumerate(res)):
- if not(lk[1] in '0123456789'):
- cur_indexes&=letters_order_index.get(lk,set([]))
- for l in forbidden:
- cur_indexes-=letters_existance_index[l]
- if cur_indexes:
- for w in cur_indexes:
- d[w].append((sub,tojd))
- for k in sorted(d.keys(), key = lambda x:freq_dict[x], reverse = True):
- if len(d[k]) ==1:
- tojd=d[k][0][1]
- print "%s=%s,%s"%(st,words_list[k],tojd)
Для того, чтобы пользоваться этим модулем можно импортировать из него две функции — gen_indexes и generate_cryptarithm.
Сгенерируем достойный ответ на send+more=money:
# -*- coding: utf-8 -*-
from cryptarithm import generate_cryptarithm,gen_indexes
indexes = gen_indexes("wiki_freq.txt", 400000)
l1=[u'пошли',u'пришли',u'вышли',u'отправь']
l2=[u'еще',u'больше',u'мне',u'много', u'срочно']
for w1 in l1:
for w2 in l2:
generate_cryptarithm(w1+u'+'+w2,indexes)
generate_cryptarithm(w1+u'*'+w2,indexes)
generate_cryptarithm(w1+u'-'+w2,indexes)
Сгенерируем достойный ответ на send+more=money:
# -*- coding: utf-8 -*-
from cryptarithm import generate_cryptarithm,gen_indexes
indexes = gen_indexes("wiki_freq.txt", 400000)
l1=[u'пошли',u'пришли',u'вышли',u'отправь']
l2=[u'еще',u'больше',u'мне',u'много', u'срочно']
for w1 in l1:
for w2 in l2:
generate_cryptarithm(w1+u'+'+w2,indexes)
generate_cryptarithm(w1+u'*'+w2,indexes)
generate_cryptarithm(w1+u'-'+w2,indexes)