SEND + MORE = MONEY, Part 1
July 31, 2012
Our first solution uses a set of nested lists to generate all possible solutions, then tests each, stopping as soon as it finds a valid solution. Non-Scheme programmers can ignore the call-with-current-continuation
at the top, which is the Scheme idiom that creates a return
statement that can interrupt a computation:
(define (send-more-money)
(call-with-current-continuation
(lambda (return)
(do ((s 1 (+ s 1))) ((= s 10))
(do ((e 0 (+ e 1))) ((= e 10))
(do ((n 0 (+ n 1))) ((= n 10))
(do ((d 0 (+ d 1))) ((= d 10))
(do ((m 1 (+ m 1))) ((= m 10))
(do ((o 0 (+ o 1))) ((= o 10))
(do ((r 0 (+ r 1))) ((= r 10))
(do ((y 0 (+ y 1))) ((= y 10))
(when (and (distinct? (list s e n d m o r y))
(= (+ (* 1000 s) (* 100 e) (* 10 n) d
(* 1000 m) (* 100 o) (* 10 r) e)
(+ (* 10000 m) (* 1000 o) (* 100 n) (* 10 e) y)))
(return (list (list s e n d) (list m o r e) (list m o n e y)))))))))))))))
The termination test checks if all digits are distinct using the following function:
(define (distinct? xs)
(cond ((null? xs) #t)
((member (car xs) (cdr xs)) #f)
(else (distinct? (cdr xs)))))
Here’s an example:
> (send-more-money)
((9 5 6 7) (1 0 8 5) (1 0 6 5 2))
The backtracking solution uses John McCarthy’s amb
function, which we have seen previously. The programming is declarative rather than imperative; there is not a single loop or assignment, no control flow anywhere in the function, just a list of possibilities for each variable and a list of requirements that must be satisfied.
(define (send-more-money)
(let ((s (amb 1 2 3 4 5 6 7 8 9))
(e (amb 0 1 2 3 4 5 6 7 8 9))
(n (amb 0 1 2 3 4 5 6 7 8 9))
(d (amb 0 1 2 3 4 5 6 7 8 9))
(m (amb 1 2 3 4 5 6 7 8 9))
(o (amb 0 1 2 3 4 5 6 7 8 9))
(r (amb 0 1 2 3 4 5 6 7 8 9))
(y (amb 0 1 2 3 4 5 6 7 8 9)))
(require (distinct? (list s e n d m o r y)))
(require (= (amb 0 1) m))
(require (= (modulo (+ s m (amb 0 1)) 10) o))
(require (= (modulo (+ e o (amb 0 1)) 10) n))
(require (= (modulo (+ n r (amb 0 1)) 10) e))
(require (= (modulo (+ d e (amb 0 1)) 10) y))
(require (= (+ (* 1000 s) (* 100 e) (* 10 n) d
(* 1000 m) (* 100 o) (* 10 r) e)
(+ (* 10000 m) (* 1000 o) (* 100 n) (* 10 e) y)))
(list (list s e n d) (list m o r e) (list m o n e y))))
The first require
sets up the condition that all variables are distinct. The next five require
s set up the column sums; note the amb
for the carry. The final require
ensures the solution is valid. Here’s an example:
> (send-more-money)
((9 5 6 7) (1 0 8 5) (1 0 6 5 2))
You can see the complete program, including amb
, at http://programmingpraxis.codepad.org/NIkMrLqf. Unfortunately, both versions of the program are very slow, about a quarter of a minute, especially the backtracking version with all of the non-deterministic calls to amb
. We’ll see a much faster version of the program in the next exercise.
[…] today’s Programming Praxis exercise, our goal is to provide two different solutions for the well known SEND […]
My Haskell solution (see http://bonsaicode.wordpress.com/2012/07/31/programming-praxis-send-more-money-part-1/ for a version with comments):
Prolog solution :-
[…] Pages: 1 2 […]
A Python 2.7 solution (with a simple timing utility):
On my machine (i7-2630QM @ 2GHZ, Win7 64bit, Python 2.7.2 32bit) solve1() takes around 95s, solve2() around 5s.
OpenMP used to parallelize the search.
[…] are a few ways that you could brute force the problem (discussed in a previous Programming Praxis article), but where’s the fun in that? I wanted to go ahead and work on the hill climbing version in […]
I solve this problem vith evolver 5.5 in best time of 00:44. Reálly is more easy reolve this problem with this excel excel addin.
I can send this file
//casey cole
//Lamar University
#include
using namespace std;
int main()
{
for( int t = 0; t < 10; t++ )
for( int o = 0; o < 10; o++ )
// put g starting at 1 so != to 0
for( int g = 1; g < 10; g++ )
for( int d = 0; d < 10; d++)
//first if makes sure none of the letter are the same
if (t != o && t != d && t != g && g != o && g != d && d != o)
//second if checks if they are equal
if ((t*100 + o*10 + o) * 4 == g*1000 + o*100 +o*10 +d){
cout << g << o << o << d << " = good\n";
cout << t << o << o << " = too";
}
return 0;
}
Can you provide code to solve any words user prompt in java script?