From 8919471dd82b9cf92610f62008dee3d64a003f12 Mon Sep 17 00:00:00 2001 From: Mark Pilgrim Date: Sun, 29 Mar 2009 18:09:43 -0500 Subject: [PATCH] code for Advanced Iterators chapter --- examples/alphametics.py | 57 +++++++++++++++++++++++++++++++++++++ examples/alphameticstest.py | 57 +++++++++++++++++++++++++++++++++++++ notes.txt | 8 ++++++ 3 files changed, 122 insertions(+) create mode 100644 examples/alphametics.py create mode 100644 examples/alphameticstest.py diff --git a/examples/alphametics.py b/examples/alphametics.py new file mode 100644 index 0000000..80dbf1b --- /dev/null +++ b/examples/alphametics.py @@ -0,0 +1,57 @@ +import re +import itertools + +def solve(puzzle): + '''Find solutions to alphametic equations. + + >>> solve('SEND + MORE == MONEY') + 9567 + 1085 == 10652 + + ''' + words = re.findall('[A-Z]+', puzzle) + unique_characters = set(''.join(words)) + assert len(unique_characters) <= 10 + first_letters = set(word[0] for word in words) + n = len(first_letters) + sorted_characters = ''.join(first_letters) + \ + ''.join(unique_characters - first_letters) + characters = tuple(map(ord, sorted_characters)) + digits = tuple(map(ord, '0123456789')) + zero = digits[0] + for guess in itertools.permutations(digits, len(characters)): + if zero not in guess[:n]: + equation = puzzle.translate(dict(zip(characters, guess))) + if eval(equation): + return equation + +if __name__ == '__main__': + import sys + for puzzle in sys.argv[1:]: + print(puzzle) + for solution in solve(puzzle): + print(solution) + +# Copyright (c) 2009, Raymond Hettinger, All rights reserved. +# Ported to Python 3 and modified by Mark Pilgrim +# original: http://code.activestate.com/recipes/576615/ +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. diff --git a/examples/alphameticstest.py b/examples/alphameticstest.py new file mode 100644 index 0000000..7f66dca --- /dev/null +++ b/examples/alphameticstest.py @@ -0,0 +1,57 @@ +from alphametics import solve +import unittest + +class KnownValues(unittest.TestCase): + def test_out(self): + """TO + GO == OUT""" + self.assertEqual(solve("TO + GO == OUT"), "21 + 81 == 102") + + def test_too(self): + """I + DID == TOO""" + self.assertEqual(solve("I + DID == TOO"), "9 + 191 == 200") + + def test_mom(self): + """AS + A == MOM""" + self.assertEqual(solve("AS + A == MOM"), "92 + 9 == 101") + + def test_best(self): + """HES + THE == BEST""" + self.assertEqual(solve("HES + THE == BEST"), "426 + 842 == 1268") + + def test_late(self): + """NO + NO + TOO == LATE""" + self.assertEqual(solve("NO + NO + TOO == LATE"), "74 + 74 + 944 == 1092") + + def test_onze(self): + """UN + UN + NEUF == ONZE""" + self.assertEqual(solve("UN + UN + NEUF == ONZE"), "81 + 81 + 1987 == 2149") + + def test_deux(self): + """UN + DEUX + DEUX + DEUX + DEUX == NEUF""" + self.assertEqual(solve("UN + DEUX + DEUX + DEUX + DEUX == NEUF"), "25 + 1326 + 1326 + 1326 + 1326 == 5329") + +if __name__ == "__main__": + unittest.main() + +# Copyright (c) 2009, Mark Pilgrim, All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. diff --git a/notes.txt b/notes.txt index 7d75fa1..2295e8b 100644 --- a/notes.txt +++ b/notes.txt @@ -1,3 +1,11 @@ +Python 3.1: + OrderedDict + "".format() auto-numbered format specifiers + unittest: assertRaises context block (?) + importlib + (possibly) yield from + (possibly) IP address library + http://www.alanwood.net/unicode/general_punctuation.html http://www.alanwood.net/unicode/arrows.html http://www.alanwood.net/unicode/miscellaneous_technical.html