Created
November 28, 2020 02:30
-
-
Save aaronmauro/b0560d6c7b44f53a75d2903cbe987deb to your computer and use it in GitHub Desktop.
A reimplementation of Raymond Hettinger's alphametic puzzle solver.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
""" | |
This is a reimplementation of Raymond Hettinger's alphametics solver from 2009 | |
on the website Activestate: https://code.activestate.com/recipes/576615-alphametics-solver/. | |
The program works to solve the alphametic puzzle called, Send + More = Money. | |
H.E. Dudeney published the problem in the July 1924 edition of The Strand | |
Magazine. The original problem appears within his articled title "Perplexities." | |
The text for the problem appears under the heading, "708.-VERBAL ARITHMETIC" | |
and reads as follows: ADDITION is an imposition, SEND + MORE = MONEY. | |
SUBTRACTION is as bad; EIGHT - FIVE = FOUR. MULTIPLICATION is vexation TWO * | |
TWO = THREE. DIVISION drives me mad. TWO) SEVEN (TWO / BOB = JOE / OVV / | |
VESN = VESN. In each puzzle every letter respresents a different digit, but | |
a letter does not necessarily stand for the same digit in the case of every | |
puzzle." These problems are typically completed by a focused adult in about | |
30 minutes. Raymond Hettinger's algorithm, then written in Python 2.6, | |
executed in ~14.4 seconds. Now, running Python 3.7.6 this alogrithm takes | |
~11.6 seconds to complete. | |
""" | |
__author__ = "Raymond Hettinger" | |
__editor__ = "Aaron Mauro" | |
__role__ = "researcher" | |
__institution__ = "Brock University" | |
__email__ = "amauro@brocku.ca" | |
__status__ = "prototype/experiment" | |
__version__ = "0.2" | |
from itertools import permutations | |
from re import findall | |
import time | |
def solve(s): | |
''' | |
Find solutions to alphametic equations such as: | |
solve('SEND + MORE == MONEY') | |
9567 + 1085 == 10652 | |
''' | |
print("Problem:",s) | |
words = findall('[A-Za-z]+', s) | |
chars = set(''.join(words)) # characters to be substituted | |
assert len(chars) <= 10 # there are only ten possible digits | |
firsts = set(w[0] for w in words) # first letters of each of word | |
chars = ''.join(firsts) + ''.join(chars - firsts) | |
n = len(firsts) # chars[:n] cannot be assigned zero | |
for perm in permutations('0123456789', len(chars)): | |
if '0' not in perm[:n]: | |
trans = str.maketrans(chars, ''.join(perm)) | |
equation = s.translate(trans) | |
try: | |
if eval(equation): | |
print(f"Solution: {equation}") | |
except ArithmeticError: | |
pass | |
start = time.time() | |
for alphametic in [ | |
'SEND + MORE == MONEY', | |
'VIOLIN * 2 + VIOLA == TRIO + SONATA', | |
'SEND + A + TAD + MORE == MONEY', | |
'ZEROES + ONES == BINARY', | |
'DCLIZ + DLXVI == MCCXXV', | |
'COUPLE + COUPLE == QUARTET', | |
'FISH + N + CHIPS == SUPPER', | |
'SATURN + URANUS + NEPTUNE + PLUTO == PLANETS', | |
'EARTH + AIR + FIRE + WATER == NATURE', | |
('AN + ACCELERATING + INFERENTIAL + ENGINEERING + TALE + ' + | |
'ELITE + GRANT + FEE + ET + CETERA == ARTIFICIAL + INTELLIGENCE'), | |
'TWO * TWO == SQUARE', | |
'HIP * HIP == HURRAY', | |
'PI * R ** 2 == AREA', | |
'NORTH / SOUTH == EAST / WEST', | |
'NAUGHT ** 2 == ZERO ** 3', | |
'I + THINK + IT + BE + THINE == INDEED', | |
'DO + YOU + FEEL == LUCKY', | |
'NOW + WE + KNOW + THE == TRUTH', | |
'SORRY + TO + BE + A + PARTY == POOPER', | |
'SORRY + TO + BUST + YOUR == BUBBLE', | |
'STEEL + BELTED == RADIALS', | |
'ABRA + CADABRA + ABRA + CADABRA == HOUDINI', | |
'I + GUESS + THE + TRUTH == HURTS', | |
'LETS + CUT + TO + THE == CHASE', | |
'THATS + THE + THEORY == ANYWAY', | |
'1/(2*X-Y) == 1', | |
]: | |
solve(alphametic) | |
print(f"{time.time() - start}") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment