Search code examples
prologclpfdprolog-toplevelcryptarithmetic-puzzle

Cryptarithmetic operation


I was trying to write Prolog code for "SEND MODE MONEY". So far, I got the following:

:- use_module(library(clpfd)).

puzzle([S,E,N,D] + [M,O,R,E] = [M,O,N,E,Y]) :- 
   Vars = [S,E,N,D,M,O,R,Y], 
   Vars ins 0..9, 
   all_different(Vars), 
   S*1000 + E*100 + N*10 + D + M*1000 + O*100 + R*10 + E 
       #= M*10000 + O*1000 + N*100 + E*10 + Y, 
   M #\= 0, 
   S #\= 0,
   label([S,E,N,D,M,O,R,Y]),
   format('~s ~w ~s ~w ~s ~w ~s ~w ~s ~s ~s ~w ~s ~w ~s ~w ~s ~w ~s ~s ~s ~w ~s ~w ~s ~w ~s ~w ~s ~w ~s ~s',
        [ "[", S, ",", E, ",", N, ",", D, "]",
         "+", "[", M, ",", O, ",", R, ",", E, "]",
         "=", "[", M, ",", O, ",", N,  ",", E, ",", Y, "]", ";" ]).

The output is as follows:

?- puzzle([S,E,N,D] + [M,O,R,E] = [M,O,N,E,Y]).

[ 9 , 5 , 6 , 7 ] + [ 1 , 0 , 8 , 5 ] = [ 1 , 0 , 6 , 5 , 2 ] ;
S = 9,
E = 5,
N = 6,
D = 7,
M = 1,
O = 0,
R = 8,
Y = 2.

But I want to print the list at the end not at the beginning how can I do it?

The output I need to get is:

?- puzzle([S,E,N,D] + [M,O,R,E] = [M,O,N,E,Y]).
S = 9,
E = 5,
N = 6,
D = 7,
M = 1,
O = 0,
R = 8,
Y = 2.
[ 9 , 5 , 6 , 7 ] + [ 1 , 0 , 8 , 5 ] = [ 1 , 0 , 6 , 5 , 2 ] ;

Thank you.


Solution

  • If you want formatted output that's different from the answers Prolog provides I'd suggest to cleanly separate the actual relation from the output. So let's remove the last goal from your predicate puzzle/1:

    puzzle([S,E,N,D] + [M,O,R,E] = [M,O,N,E,Y]) :- 
       Vars = [S,E,N,D,M,O,R,Y], 
       Vars ins 0..9, 
       all_different(Vars), 
       S*1000 + E*100 + N*10 + D + M*1000 + O*100 + R*10 + E 
           #= M*10000 + O*1000 + N*100 + E*10 + Y, 
       M #\= 0, 
       S #\= 0,
       label([S,E,N,D,M,O,R,Y]).
    

    Write a predicate that deals with the output. Following your example of desired output that might be something like output the query followed by the variable substitutions, one per line, and finally the input equation with the letters substituted by the numbers that solve the puzzle (that's exactly the last goal from your version of puzzle/1):

    output([S,E,N,D] + [M,O,R,E] = [M,O,N,E,Y]) :-
       format('?- puzzle([S,E,N,D] + [M,O,R,E] = [M,O,N,E,Y]).~n'),
       format('S = ~d,~nE = ~d,~nN = ~d,~nD = ~d,~nM = ~d,~nO = ~d,~nR = ~d,~nY = ~d.~n',[S,E,N,D,M,O,R,Y]),
       format('~s ~w ~s ~w ~s ~w ~s ~w ~s ~s ~s ~w ~s ~w ~s ~w ~s ~w ~s ~s ~s ~w ~s ~w ~s ~w ~s ~w ~s ~w ~s ~s',[ "[", S, ",", E, ",", N, ",", D, "]",  "+", "[", M, ",", O, ",", R, ",", E, "]", "=", "[", M, ",", O, ",", N,  ",", E, ",", Y, "]", ";" ]).
    

    And then you have a calling predicate without arguments so only your desired output is generated:

    puzzleout :-
       puzzle(X),
       output(X).
    

    This way you have a predicate that solves the puzzle and does nothing else:

    ?- puzzle([S,E,N,D] + [M,O,R,E] = [M,O,N,E,Y]).
    S = 9,
    E = 5,
    N = 6,
    D = 7,
    M = 1,
    O = 0,
    R = 8,
    Y = 2 ;
    false.
    

    And you also have a predicate that generates your desired output:

    ?- puzzleout.
    ?- puzzle([S,E,N,D] + [M,O,R,E] = [M,O,N,E,Y]).
    S = 9,
    E = 5,
    N = 6,
    D = 7,
    M = 1,
    O = 0,
    R = 8,
    Y = 2.
    [ 9 , 5 , 6 , 7 ] + [ 1 , 0 , 8 , 5 ] = [ 1 , 0 , 6 , 5 , 2 ] ;
    true ;
    false.
    

    Note that the second line is not a query that you entered but is generated as output by the first goal of output/1.