

Send more money (in Perl 6) - kamaal
http://strangelyconsistent.org/blog/send-more-money-in-perl6

======
mzl
When solving a combinatorial (optimization) problem, using a suitable
modelling language is always nice. I'm partial to MiniZinc
([http://www.minizinc.org/](http://www.minizinc.org/)) myself, where Send more
money would look like this

    
    
      include "globals.mzn";
    
      var 1..9: S;
      var 0..9: E;
      var 0..9: N;
      var 0..9: D;
      var 1..9: M;
      var 0..9: O;
      var 0..9: R;
      var 0..9: Y;
    
      constraint      1000 * S + 100 * E + 10 * N + D
                    + 1000 * M + 100 * O + 10 * R + E
        = 10000 * M + 1000 * O + 100 * N + 10 * E + Y;
    
      constraint alldifferent([S,E,N,D,M,O,R,Y]);
    
      solve satisfy;
    
      output [ " ",show(S),show(E),show(N),show(D),"\n",
              "+ ",show(M),show(O),show(R),show(E),"\n",
      "= ",show(M),show(O),show(N),show(E),show(Y),"\n"];
    

A couple of nice things to note are the initial domains (defining the non-zero
aspect of S and M), the use of alldifferent to make sure all variables have
unique values, and letting the solving-strategy be determined by the back-end
solver used.

------
Rangi42
A straightforward translation of the first program to Python 3 runs in 11
seconds:

    
    
        digits = set(range(10))
        
        def choose(choices, fn):
            for value in choices:
                fn(value)
        
        def guard(condition, fn):
            if condition:
                fn()
        
        def ten(*digits):
            return int(''.join(map(str, digits)))
        
        choose(digits - {0}, lambda s:
        choose(digits - {s}, lambda e:
        choose(digits - {s, e}, lambda n:
        choose(digits - {s, e, n}, lambda d:
        choose(digits - {0, s, e, n, d}, lambda m:
        choose(digits - {s, e, n, d, m}, lambda o:
        choose(digits - {s, e, n, d, m, o}, lambda r:
        choose(digits - {s, e, n, d, m, o, r}, lambda y:
        (lambda
        send = ten(s, e, n, d),
        more = ten(m, o, r, e),
        money = ten(m, o, n, e, y):
        guard(send + more == money, lambda:
        print("{} + {} = {}".format(send, more, money))
        ))()))))))))

~~~
minikomi
This was quite fun to write in racket:

    
    
        #lang racket
        
        (define (ten digits)
          (apply (compose string->number string-append)
                 (map number->string digits)))
        
        (define (solve)
          (for* ([s                               (range 1 10)]
                 [e (remove s                     (range 0 10))]
                 [n (remove* (list s e)           (range 0 10))]
                 [d (remove* (list s e n)         (range 0 10))]
                 [m (remove* (list 0 s e n d)     (range 0 10))]
                 [o (remove* (list s e n d m)     (range 0 10))]
                 [r (remove* (list s e n d m o)   (range 0 10))]
                 [y (remove* (list s e n d m o r) (range 0 10))]
                 #:when (=   (+ (ten (list s e n d))
                                (ten (list m o r e)))
                              (ten (list m o n e y))))
            (displayln
             (format
              "     S E N D        ~a ~a ~a ~a~n +   M O R E    +   ~a ~a ~a ~a~n------------   ------------~n   M O N E Y      ~a ~a ~a ~a ~a"
              s e n d m o r e m o n e y))))
    

Excuse the ugly format line :)

    
    
        sendmore.rkt﻿> (time (solve))
             S E N D        9 5 6 7
         +   M O R E    +   1 0 8 5
        ------------   ------------
           M O N E Y      1 0 6 5 2
        cpu time: 7124 real time: 7120 gc time: 80

~~~
minikomi
Ah, too late to edit, but using for*/first to terminate the first time it
finds a match is faster still.

------
VeXocide
A solution using the Yices SMT solver which can be found at
[http://yices.csl.sri.com/yices2-documentation.html](http://yices.csl.sri.com/yices2-documentation.html):

    
    
        (define d::int)
        (define e::int)
        (define m::int)
        (define n::int)
        (define o::int)
        (define r::int)
        (define s::int)
        (define y::int)
    
        (assert
           (and
              (and (>= d 0) (<= d 9))
              (and (>= e 0) (<= e 9))
              (and (>= m 0) (<= m 9))
              (and (>= n 0) (<= n 9))
              (and (>= o 0) (<= o 9))
              (and (>= r 0) (<= r 9))
              (and (>= s 0) (<= s 9))
              (and (>= y 0) (<= y 9))
              (and (/= d e) (/= d m) (/= d n) (/= d o) (/= d r) (/= d s) (/= d y))
              (and (/= e m) (/= e n) (/= e o) (/= e r) (/= e s) (/= e y))
              (and (/= m n) (/= m o) (/= m r) (/= m s) (/= m y))
              (and (/= n o) (/= n r) (/= n s) (/= n y))
              (and (/= o r) (/= o s) (/= o y))
              (and (/= r s) (/= r y))
              (/= s y)
              (=
                 (+
                    (+ (* s 1000) (* e 100) (* n 10) d)
                    (+ (* m 1000) (* o 100) (* r 10) e)
                 )
                 (+ (* m 10000) (* o 1000) (* n 100) (* e 10) y)
              )
           )
        )
    
        (check)
        (show-model)
    

which gives

    
    
        sat
        (= m 1)
        (= r 8)
        (= y 2)
        (= o 0)
        (= s 9)
        (= n 6)
        (= d 7)
        (= e 5)
        ./bin/yices money.ys  0.01s user 0.00s system 76% cpu 0.012 total

------
bayonetz
Very nice! Not sure if it will get Perl 6 any better adoption, but still very
nice.

