SEND + MORE = MONEY: Difference between revisions
m (→{{header|Free Pascal}}: 41 Words) |
m (→{{header|Free Pascal}}: no more unneeded carry calc) |
||
Line 288: | Line 288: | ||
<syntaxhighlight lang="pascal"> |
<syntaxhighlight lang="pascal"> |
||
program SymbolToDigit; |
program SymbolToDigit; |
||
{$IFDEF FPC}{$MODE DELPHI}{$Optimization ON,All}{$ENDIF} |
|||
{$IFDEF Windows}{$APPTYPE CONSOLE}{$ENDIF} |
|||
uses |
uses |
||
sysutils;// TDatetime |
sysutils;// TDatetime |
||
const |
const |
||
nmax = 9; |
nmax = 9; |
||
maxLen = |
maxLen = 7; |
||
maxIDx = 41; |
|||
type |
type |
||
tFreeDgt = array[0..nmax+1] of Int32; |
tFreeDgt = array[0..nmax+1] of Int32; |
||
tSymbWord = String[maxLen]; |
tSymbWord = String[maxLen]; |
||
tDgtWord = record |
tDgtWord = record |
||
DW_DgtsIdx: array[1..maxLen] of UInt8; |
DW_DgtsIdx: array[1..maxLen] of UInt8; |
||
DW_maxIdx: Uint8; |
DW_maxIdx: Uint8; |
||
end; |
end; |
||
tDgtFront = record |
|||
DW_DgtsIdx: array[1..nmax+1] of UInt8; |
|||
DW_maxIdx: Uint8; |
|||
end; |
|||
tInUse = set of 0..nmax+1; |
|||
const |
const |
||
{ |
|||
// cSumWords : array[0..maxIDx] of tSymbWord =('SEND','MORE','MONEY'); |
|||
maxIDx = 2; |
|||
cSumWords : array[0..maxIDx] of tSymbWord =('SEND','MORE','MONEY'); |
|||
} |
|||
{ |
|||
maxIDx = 4; |
|||
cSumWords : array[0..maxIDx] of tSymbWord =('ABRA','CADABRA','ABRA','CADABRA','HOUDINI'); |
|||
} |
|||
//MANYOTHERS=M2A7N6Y4O1T9H5E0R8S3 |
//MANYOTHERS=M2A7N6Y4O1T9H5E0R8S3 |
||
maxIDx = 41; |
|||
//{ |
|||
cSumWords : array[0..maxIDx] of tSymbWord =( |
cSumWords : array[0..maxIDx] of tSymbWord =( |
||
'SO','MANY','MORE','MEN','SEEM','TO','SAY','THAT', |
'SO','MANY','MORE','MEN','SEEM','TO','SAY','THAT', |
||
Line 313: | Line 329: | ||
'MOON','AS','HE','HAS','AT','THE','OTHER','TEN', |
'MOON','AS','HE','HAS','AT','THE','OTHER','TEN', |
||
'TESTS'); |
'TESTS'); |
||
//} |
|||
var |
var |
||
{$ALIGN 32} |
{$ALIGN 32} |
||
DigitSample |
DigitSample, |
||
DigitSampleSolution : tFreeDgt; |
|||
SymbInUse : array[0..10] of char; |
SymbInUse : array[0..10] of char; |
||
DgtToSymb : array[0..10] of UInt8; |
|||
Words :array[0..maxIDx] of tSymbWord; |
Words :array[0..maxIDx] of tSymbWord; |
||
DgtWords : array[0..maxIDx] of tDgtWord; |
DgtWords : array[0..maxIDx] of tDgtWord; |
||
DgtFrontWords :tDgtFront; |
|||
SymbInUseCount,gblCount : Uint32; |
SymbInUseCount,gblCount : Uint32; |
||
fullStop: boolean; |
fullStop: boolean; |
||
ch : char; |
ch : char; |
||
procedure OneSol(idx:int32;const DS:tFreeDgt); |
|||
var |
|||
i,symbolIdx : Int32; |
|||
begin |
|||
For i := maxlen downto 1 do |
|||
begin |
|||
symbolIdx := DgtWords[idx].DW_DgtsIdx[i]; |
|||
if symbolIdx = 0 then |
|||
write(' ') |
|||
else |
|||
write(DS[symbolIdx]); |
|||
end; |
|||
writeln(cSumWords[idx]:maxLen+2); |
|||
end; |
|||
procedure RevString(var s:tSymbWord); |
procedure RevString(var s:tSymbWord); |
||
Line 342: | Line 374: | ||
//CHR(ORD('A')-1) = '@' is placeholder for no Symbol |
//CHR(ORD('A')-1) = '@' is placeholder for no Symbol |
||
SymbToIdx : array['@'..'Z'] of byte; |
SymbToIdx : array['@'..'Z'] of byte; |
||
FrontSymbols :tInUse; |
|||
i,j : Int32; |
i,j : Int32; |
||
Begin |
Begin |
||
Line 354: | Line 387: | ||
//position of highest symbol |
//position of highest symbol |
||
DgtWords[i].DW_maxIdx := j; |
DgtWords[i].DW_maxIdx := j; |
||
// extend by '@' aka zero |
|||
begin |
|||
inc(j); |
|||
Words[i] := Low(SymbToIdx)+Words[i]; |
|||
end; |
|||
RevString(Words[i]); |
RevString(Words[i]); |
||
setlength(Words[i],maxlen); |
|||
For j := j+1 to maxLen do |
|||
Words[i][j] := Low(SymbToIdx); |
|||
end; |
end; |
||
// find all symbols |
|||
for j := 1 to High(tSymbWord) do |
for j := 1 to High(tSymbWord) do |
||
Begin |
Begin |
||
For i := 0 to |
For i := 0 to maxIdx do |
||
begin |
begin |
||
ch := Words[i][j]; |
ch := Words[i][j]; |
||
Line 376: | Line 407: | ||
end; |
end; |
||
end; |
end; |
||
dec(SymbInUseCount); |
|||
For i := 0 to maxIDx do |
|||
begin |
|||
for j := 1 to maxlen do |
|||
DgtWords[i].DW_DgtsIdx[j]:= SymbToIdx[Words[i][j]]; |
|||
end; |
|||
For i := 1 to SymbInUseCount do |
For i := 1 to SymbInUseCount do |
||
write(SymbInUse[i]); |
write(SymbInUse[i]); |
||
writeln(SymbInUseCount |
writeln(SymbInUseCount:4,' symbols'); |
||
end; |
|||
//get index for every symbol in word |
|||
procedure OneSol(idx:int32); |
|||
For i := 0 to maxIdx do |
|||
var |
|||
with DgtWords[i] do |
|||
i,symbolIdx : Int32; |
|||
for j := 1 to High(tSymbWord) do |
|||
begin |
|||
DW_DgtsIdx[j]:= SymbToIdx[Words[i][j]]; |
|||
For i := maxlen downto 1 do |
|||
//find all first symbols |
|||
symbolIdx := DgtWords[idx].DW_DgtsIdx[i]; |
|||
FrontSymbols := []; |
|||
if symbolIdx = 0 then |
|||
For i := 0 to maxIDx do |
|||
with DgtWords[i] do |
|||
else |
|||
include(FrontSymbols,DW_DgtsIdx[DW_maxIdx]); |
|||
end; |
|||
j := 1; |
|||
writeln(cSumWords[idx]:maxLen+2); |
|||
For i := 0 to nmax+1 do |
|||
if i in FrontSymbols then |
|||
Begin |
|||
DgtFrontWords.DW_DgtsIdx[j] := i; |
|||
inc(j); |
|||
end; |
|||
DgtFrontWords.DW_maxIdx := j-1; |
|||
end; |
end; |
||
Line 405: | Line 437: | ||
var |
var |
||
col,row, |
col,row, |
||
sum |
sum,carry : NativeUInt; |
||
begin |
begin |
||
// |
// check for zero in first symbols of words |
||
with DgtFrontWords do |
|||
For row := maxIdx downto 0 do |
|||
For col := DW_maxIdx downto 1 do |
|||
begin |
|||
if DS[DW_DgtsIdx[DW_maxidx]] = 0 then |
|||
if DS[DW_DgtsIdx[col]] = 0 then |
|||
EXIT(false); |
EXIT(false); |
||
end; |
|||
carry := 0; |
carry := 0; |
||
carrySum := 0; |
|||
For col := 1 to maxLen do |
For col := 1 to maxLen do |
||
Begin |
Begin |
||
sum := |
sum := carry; |
||
carry := 0; |
|||
// add one column |
|||
For row := maxIdx-1 downto 0 do |
For row := maxIdx-1 downto 0 do |
||
Begin |
|||
sum := sum+DS[DgtWords[row].DW_DgtsIdx[col]]; |
sum := sum+DS[DgtWords[row].DW_DgtsIdx[col]]; |
||
if sum > 9 then |
|||
begin |
|||
carry := sum DIV 10; |
|||
carry := sum DIV 10; |
|||
sum := sum - 10 * carry; |
|||
end; |
|||
end; |
|||
//digit of sum |
//digit of sum |
||
if sum <> DS[DgtWords[maxIDx].DW_DgtsIdx[col]] then |
if sum <> DS[DgtWords[maxIDx].DW_DgtsIdx[col]] then |
||
EXIT(false); |
EXIT(false); |
||
end; |
end; |
||
If Carry = 0 then |
|||
DigitSampleSolution := DS; |
|||
EXIT(false); |
|||
For row := 0 to High(DgtWords)do |
|||
OneSol(row); |
|||
EXIT(true); |
EXIT(true); |
||
end; |
end; |
||
Line 445: | Line 474: | ||
i,Col : nativeInt; |
i,Col : nativeInt; |
||
begin |
begin |
||
if fullStop then |
if fullStop then EXIT; |
||
EXIT; |
|||
IF row <= 10 then |
IF row <= 10 then |
||
begin |
begin |
||
Line 468: | Line 496: | ||
end |
end |
||
end; |
end; |
||
var |
var |
||
T1,T0: TDateTime; |
T1,T0: TDateTime; |
||
i : Uint32; |
i,j : Uint32; |
||
begin |
begin |
||
Line 483: | Line 512: | ||
NextPermute(1,DigitSample); |
NextPermute(1,DigitSample); |
||
t1:= time; |
t1:= time; |
||
IF maxIDx < 10 then |
|||
For i := 0 to High(DgtWords)do |
|||
OneSol(i,DigitSampleSolution); |
|||
writeln; |
|||
For i := 1 to SymbInUseCount do |
|||
begin |
|||
j := DigitSampleSolution[i]; |
|||
write(SymbInUse[i],'=',j,' '); |
|||
end; |
|||
writeln; |
writeln; |
||
WriteLn(gblCount,' checks ',FormatDateTime(' NN:SS.ZZZ',T1-t0),' secs'); |
WriteLn(gblCount,' checks ',FormatDateTime(' NN:SS.ZZZ',T1-t0),' secs'); |
||
end.</syntaxhighlight> |
|||
end. |
|||
</syntaxhighlight> |
|||
{{out|@TIO.RUN}} |
{{out|@TIO.RUN}} |
||
<pre> |
<pre> |
||
8 symbols |
DEYNROSM 8 symbols |
||
9567 SEND |
|||
1085 MORE |
|||
10652 MONEY |
10652 MONEY |
||
D=7 E=5 Y=2 N=6 R=8 O=0 S=9 M=1 |
|||
2704147 checks 00:00.090 secs |
|||
2704147 checks 00:00.043 secs |
|||
OYENMTSRAH |
|||
//shorthened 'SO','MANY','MORE','MEN','SEEM','TO','SAY', |
|||
10 symbols |
|||
OYENMTSRAH 10 symbols |
|||
31 SO |
|||
2764 MANY |
|||
2180 MORE |
|||
206 MEN |
|||
3002 SEEM |
|||
91 TO |
|||
374 SAY |
|||
9579 THAT |
|||
9504 THEY |
|||
274 MAY |
|||
3116 SOON |
|||
984 TRY |
|||
91 TO |
|||
3974 STAY |
|||
79 AT |
|||
5120 HOME |
|||
31 SO |
|||
73 AS |
|||
91 TO |
|||
300 SEE |
|||
18 OR |
|||
5078 HEAR |
|||
950 THE |
|||
3720 SAME |
|||
160 ONE |
|||
276 MAN |
|||
984 TRY |
|||
91 TO |
|||
2009 MEET |
|||
950 THE |
|||
9072 TEAM |
|||
16 ON |
|||
950 THE |
|||
2116 MOON |
|||
73 AS |
|||
50 HE |
|||
573 HAS |
|||
79 AT |
|||
950 THE |
|||
19508 OTHER |
|||
906 TEN |
|||
90393 TESTS |
|||
O=1 Y=4 E=0 N=6 M=2 T=9 S=3 R=8 A=7 H=5 |
|||
496179 checks 00:00.061 secs |
|||
496179 checks 00:00.013 secs</pre> |
|||
</pre> |
|||
=={{header|Phix}}== |
=={{header|Phix}}== |
Revision as of 14:22, 13 February 2023
Write a program in your language to solve SEND + MORE = MONEY: A Great Puzzle.
ALGOL 68
This task can be solved without using seven nested loops but then again, it can be solved with them - so why not?.
Uses the observations of the Julia sample (unsuprisingly as this is a translation of the Julia sample).
BEGIN # solve the SEND+MORE=MONEY puzzle - translation of the Julia sample #
INT m = 1;
OP C = ( INT n )CHAR: REPR ( ABS "0" + n ); # convert integer to a digit #
FOR s FROM 8 TO 9 DO
FOR e FROM 0 TO 9 DO
IF e /= m AND e/= s THEN
FOR n FROM 0 TO 9 DO
IF n /= m AND n /= s AND n /= e THEN
FOR d FROM 0 TO 9 DO
IF d /= m AND d /= s AND d /= e AND d /= n THEN
FOR o FROM 0 TO 9 DO
IF o /= m AND o /= s AND o /= e AND o /= n AND o /= d THEN
FOR r FROM 0 TO 9 DO
IF r /= m AND r /= s AND r /= e AND r /= n AND r /= d AND r /= o THEN
FOR y FROM 0 TO 9 DO
IF y /= m AND y /= s AND y /= e AND y /= n AND y /= d AND y /= o AND y /= r THEN
IF ( 1000 * ( s + m ) ) + ( 100 * ( e + o ) ) + ( 10 * ( n + r ) ) + ( d + e )
= ( 10 000 * m ) + ( 1000 * o ) + ( 100 * n ) + ( 10 * e ) + y
THEN
print( ( C s, C e, C n, C d, " + ", C m, C o, C r, C e, " = ", C m, C o, C n, C e, C y
)
)
FI
FI
OD
FI
OD
FI
OD
FI
OD
FI
OD
FI
OD
OD
END
- Output:
9567 + 1085 = 10652
BASIC
Rosetta Code problem: https://rosettacode.org/wiki/SEND_%2B_MORE_%3D_MONEY
by Jjuanhdez, 02/2023
BASIC256
m = 1
for s = 8 to 9
for e = 0 to 9
if e <> m and e <> s then
for n = 0 to 9
if n <> m and n <> s and n <> e then
for d = 0 to 9
if d <> m and d <> s and d <> e and d <> n then
for o = 0 to 9
if o <> m and o <> s and o <> e and o <> n and o <> d then
for r = 0 to 9
if r <> m and r <> s and r <> e and r <> n and r <> d and r <> o then
for y = 0 to 9
if y <> m and y <> s and y <> e and y <> n and y <> d and y <> o then
if ((1000*(s+m)) + (100*(e+o)) + (10*(n+r)) + (d+e)) = ((10000* m) + (1000*o) + (100*n) + (10*e) + y) then
print s;e;n;d; " + "; m;o;r;e; " = "; m;o;n;e;y
end if
end if
next y
end if
next r
end if
next o
end if
next d
end if
next n
end if
next e
next s
- Output:
Same as FreeBASIC entry.
Yabasic
m = 1
for s = 8 to 9
for e = 0 to 9
if e <> m and e <> s then
for n = 0 to 9
if n <> m and n <> s and n <> e then
for d = 0 to 9
if d <> m and d <> s and d <> e and d <> n then
for o = 0 to 9
if o <> m and o <> s and o <> e and o <> n and o <> d then
for r = 0 to 9
if r <> m and r <> s and r <> e and r <> n and r <> d and r <> o then
for y = 0 to 9
if y <> m and y <> s and y <> e and y <> n and y <> d and y <> o then
if ((1000*(s+m)) + (100*(e+o)) + (10*(n+r)) + (d+e)) = ((10000* m) + (1000*o) + (100*n) + (10*e) + y) ? str$(s), str$(e), str$(n), str$(d), " + ", str$(m), str$(o), str$(r), str$(e), " = ", str$(m), str$(o), str$(n), str$(e), str$(y)
fi
next y
fi
next r
fi
next o
fi
next d
fi
next n
fi
next e
next s
end
- Output:
Same as FreeBASIC entry.
FreeBASIC
Dim As Byte m = 1, s, e, n, d, o, r, y
For s = 8 To 9
For e = 0 To 9
If e <> m And e <> s Then
For n = 0 To 9
If n <> m And n <> s And n <> e Then
For d = 0 To 9
If d <> m And d <> s And d <> e And d <> n Then
For o = 0 To 9
If o <> m And o <> s And o <> e And o <> n And o <> d Then
For r = 0 To 9
If r <> m And r <> s And r <> e And r <> n And r <> d And r <> o Then
For y = 0 To 9
If y <> m And y <> s And y <> e And y <> n And y <> d And y <> o Then
If ((1000*(s+m)) + (100*(e+o)) + (10*(n+r)) + (d+e)) = _
((10000* m) + (1000*o) + (100*n) + (10*e) + y) Then
Print s & e & n & d & " + " & _
m & o & r & e & " = " & m & o & n & e & y
End If
End If
Next y
End If
Next r
End If
Next o
End If
Next d
End If
Next n
End If
Next e
Next s
Sleep
- Output:
9567 + 1085 = 10652
Go
package main
import (
"fmt"
"time"
)
func contains(a []int, v int) bool {
for i := 0; i < len(a); i++ {
if a[i] == v {
return true
}
}
return false
}
func main() {
start := time.Now()
var sends [][4]int
var ors [][2]int
m := 1
digits := []int{0, 2, 3, 4, 5, 6, 7, 8, 9}
for s := 8; s <= 9; s++ {
for _, e := range digits {
if e == s {
continue
}
for _, n := range digits {
if n == s || n == e {
continue
}
for _, d := range digits {
if d == s || d == e || d == n {
continue
}
sends = append(sends, [4]int{s, e, n, d})
}
}
}
}
for _, o := range digits {
for _, r := range digits {
if r != o {
ors = append(ors, [2]int{o, r})
}
}
}
fmt.Println("Solution(s):")
for _, send := range sends {
SEND := 1000*send[0] + 100*send[1] + 10*send[2] + send[3]
for _, or := range ors {
send2 := send[:]
or2 := or[:]
if contains(send2, or[0]) || contains(send2, or[1]) {
continue
}
MORE := 1000*m + 100*or[0] + 10*or[1] + send[1]
for _, y := range digits {
if contains(send2, y) || contains(or2, y) {
continue
}
MONEY := 10000*m + 1000*or[0] + 100*send[2] + 10*send[1] + y
if SEND+MORE == MONEY {
fmt.Printf("%d + %d = %d\n", SEND, MORE, MONEY)
}
}
}
}
fmt.Printf("\nTook %s.\n", time.Since(start))
}
- Output:
Solution(s): 9567 + 1085 = 10652 Took 1.149804ms.
Julia
A hoary old task, solved with pencil before electricity was a thing.
Since the M in Money is the result of carry in base 10 of two single digits it is a 1 (we exclude 0 here though that would work, but then MONEY would be spelled ONEY).
In addition, the S plus 1 then needs to result in a carry, so S is 8 or 9, depending on whether there is a carry into that column. Pencil and paper can continue, but from here the computer is likely quicker.
let
m = 1
for s in 8:9
for e in 0:9
e in [m, s] && continue
for n in 0:9
n in [m, s, e] && continue
for d in 0:9
d in [m, s, e, n] && continue
for o in 0:9
o in [m, s, e, n, d] && continue
for r in 0:9
r in [m, s, e, n, d, o] && continue
for y in 0:9
y in [m, s, e, n, d, o] && continue
if 1000s + 100e + 10n + d + 1000m + 100o + 10r + e ==
10000m + 1000o + 100n + 10e + y
println("$s$e$n$d + $m$o$r$e == $m$o$n$e$y")
end
end
end
end
end
end
end
end
end
- Output:
9567 + 1085 == 10652
Pascal
Free Pascal
simple brute force. Permutation stolen by nQueens.
program SymbolToDigit;
{$IFDEF FPC}{$MODE DELPHI}{$Optimization ON,All}{$ENDIF}
{$IFDEF Windows}{$APPTYPE CONSOLE}{$ENDIF}
uses
sysutils;// TDatetime
const
nmax = 9;
maxLen = 7;
type
tFreeDgt = array[0..nmax+1] of Int32;
tSymbWord = String[maxLen];
tDgtWord = record
DW_DgtsIdx: array[1..maxLen] of UInt8;
DW_maxIdx: Uint8;
end;
tDgtFront = record
DW_DgtsIdx: array[1..nmax+1] of UInt8;
DW_maxIdx: Uint8;
end;
tInUse = set of 0..nmax+1;
const
{
maxIDx = 2;
cSumWords : array[0..maxIDx] of tSymbWord =('SEND','MORE','MONEY');
}
{
maxIDx = 4;
cSumWords : array[0..maxIDx] of tSymbWord =('ABRA','CADABRA','ABRA','CADABRA','HOUDINI');
}
//MANYOTHERS=M2A7N6Y4O1T9H5E0R8S3
maxIDx = 41;
cSumWords : array[0..maxIDx] of tSymbWord =(
'SO','MANY','MORE','MEN','SEEM','TO','SAY','THAT',
'THEY','MAY','SOON','TRY','TO','STAY','AT','HOME',
'SO','AS','TO','SEE','OR','HEAR','THE','SAME','ONE',
'MAN','TRY','TO','MEET','THE','TEAM','ON','THE',
'MOON','AS','HE','HAS','AT','THE','OTHER','TEN',
'TESTS');
var
{$ALIGN 32}
DigitSample,
DigitSampleSolution : tFreeDgt;
SymbInUse : array[0..10] of char;
Words :array[0..maxIDx] of tSymbWord;
DgtWords : array[0..maxIDx] of tDgtWord;
DgtFrontWords :tDgtFront;
SymbInUseCount,gblCount : Uint32;
fullStop: boolean;
ch : char;
procedure OneSol(idx:int32;const DS:tFreeDgt);
var
i,symbolIdx : Int32;
begin
For i := maxlen downto 1 do
begin
symbolIdx := DgtWords[idx].DW_DgtsIdx[i];
if symbolIdx = 0 then
write(' ')
else
write(DS[symbolIdx]);
end;
writeln(cSumWords[idx]:maxLen+2);
end;
procedure RevString(var s:tSymbWord);
var
i,j: NativeInt;
begin
i := 1;
j := Length(s);
while j>i do
begin
ch:= s[i];s[i]:= s[j];s[j] := ch;
inc(i);dec(j);
end;
end;
procedure GetSymbols;
var
//CHR(ORD('A')-1) = '@' is placeholder for no Symbol
SymbToIdx : array['@'..'Z'] of byte;
FrontSymbols :tInUse;
i,j : Int32;
Begin
fillchar(SymbToIdx,SizeOf(SymbToIdx),#255);
SymbToIdx['@'] := 0;
SymbInUseCount := 1;//['@'] is always zero
For i := 0 to maxIDx do
begin
Words[i] := cSumWords[i];
j := length(Words[i]);
//position of highest symbol
DgtWords[i].DW_maxIdx := j;
// extend by '@' aka zero
RevString(Words[i]);
setlength(Words[i],maxlen);
For j := j+1 to maxLen do
Words[i][j] := Low(SymbToIdx);
end;
// find all symbols
for j := 1 to High(tSymbWord) do
Begin
For i := 0 to maxIdx do
begin
ch := Words[i][j];
if SymbToIdx[ch] = 255 then
begin
SymbToIdx[ch] := SymbInUseCount;
SymbInUse[SymbInUseCount] := ch;
inc(SymbInUseCount);
end;
end;
end;
dec(SymbInUseCount);
For i := 1 to SymbInUseCount do
write(SymbInUse[i]);
writeln(SymbInUseCount:4,' symbols');
//get index for every symbol in word
For i := 0 to maxIdx do
with DgtWords[i] do
for j := 1 to High(tSymbWord) do
DW_DgtsIdx[j]:= SymbToIdx[Words[i][j]];
//find all first symbols
FrontSymbols := [];
For i := 0 to maxIDx do
with DgtWords[i] do
include(FrontSymbols,DW_DgtsIdx[DW_maxIdx]);
j := 1;
For i := 0 to nmax+1 do
if i in FrontSymbols then
Begin
DgtFrontWords.DW_DgtsIdx[j] := i;
inc(j);
end;
DgtFrontWords.DW_maxIdx := j-1;
end;
function AddWords(const DS:tFreeDgt):boolean;
var
col,row,
sum,carry : NativeUInt;
begin
// check for zero in first symbols of words
with DgtFrontWords do
For col := DW_maxIdx downto 1 do
begin
if DS[DW_DgtsIdx[col]] = 0 then
EXIT(false);
end;
carry := 0;
For col := 1 to maxLen do
Begin
sum := carry;
carry := 0;
// add one column
For row := maxIdx-1 downto 0 do
sum := sum+DS[DgtWords[row].DW_DgtsIdx[col]];
if sum > 9 then
begin
carry := sum DIV 10;
sum := sum - 10 * carry;
end;
//digit of sum
if sum <> DS[DgtWords[maxIDx].DW_DgtsIdx[col]] then
EXIT(false);
end;
If Carry = 0 then
DigitSampleSolution := DS;
EXIT(true);
end;
procedure NextPermute(Row:nativeInt;var DS:tFreeDgt);
var
i,Col : nativeInt;
begin
if fullStop then EXIT;
IF row <= 10 then
begin
NextPermute(Row+1,DS);
For i := row+1 to 10 do
begin
//swap
Col := DS[i];
DS[i] := DS[Row];
DS[Row] := Col;
NextPermute(Row+1,DS);
//Undo swap
DS[Row] := DS[i];
DS[i] := Col;
end
end
else
begin
fullStop := AddWords(DS);
inc(gblCount);
end
end;
var
T1,T0: TDateTime;
i,j : Uint32;
begin
DigitSample[0] := 0;
For i := 0 to nmax do
DigitSample[i+1] := i;
GetSymbols;
t0 := time;
gblCount := 0;
fullStop := false;
NextPermute(1,DigitSample);
t1:= time;
IF maxIDx < 10 then
For i := 0 to High(DgtWords)do
OneSol(i,DigitSampleSolution);
writeln;
For i := 1 to SymbInUseCount do
begin
j := DigitSampleSolution[i];
write(SymbInUse[i],'=',j,' ');
end;
writeln;
WriteLn(gblCount,' checks ',FormatDateTime(' NN:SS.ZZZ',T1-t0),' secs');
end.
- @TIO.RUN:
DEYNROSM 8 symbols 9567 SEND 1085 MORE 10652 MONEY D=7 E=5 Y=2 N=6 R=8 O=0 S=9 M=1 2704147 checks 00:00.043 secs //shorthened 'SO','MANY','MORE','MEN','SEEM','TO','SAY', OYENMTSRAH 10 symbols O=1 Y=4 E=0 N=6 M=2 T=9 S=3 R=8 A=7 H=5 496179 checks 00:00.013 secs
Phix
Mighta gota bit carried away here...
with javascript_semantics sequence answer procedure solve(sequence sums,solve_order,firsts,correct_to, integer l,avail,done=0) done += 1 integer d = solve_order[done] for ad=firsts[done] to 9 do integer m = power(2,ad) if and_bits(avail,m) then answer[d] = ad integer ct = correct_to[done] if ct then integer carry = 0, bOK = true for i=1 to ct do carry += sum(extract(answer,sums[i][1])) if remainder(carry,10)!=answer[sums[i][2]] then bOK = false exit end if carry = floor(carry/10) end for if bOK then if ct=length(sums) then if carry=0 then ?answer end if else solve(sums,solve_order,firsts,correct_to,l,avail-m,done) end if end if else solve(sums,solve_order,firsts,correct_to,l,avail-m,done) end if answer[d] = -1 end if end for end procedure procedure cryptarithm(string s) integer eq = find('=',s) sequence ans = trim(s[eq+1..$]), words = apply(split(s[1..eq-1],'+'),trim), res = join(unique(join(words,"")&ans,"STABLE"),"") integer l = length(res) for i,w in words do words[i] = apply(true,find,{w,{res}}) end for ans = apply(true,find,{ans,{res}}) sequence sums = {}, solve_order = {} for i=1 to length(ans) do sequence set = {} for w in words do if length(w)>=i then integer wi = w[-i] set &= wi if not find(wi,solve_order) then solve_order &= wi end if end if end for integer ai = ans[-i] if not find(ai,solve_order) then solve_order &= ai end if sums = append(sums,{set,ai}) end for assert(length(solve_order)=l) sequence firsts = repeat(0,l), correct_to = repeat(0,l) for f in unique(join(apply(true,extract,{words,{{1}}}),{})&ans[1]) do firsts[find(f,solve_order)] = 1 end for integer mm = 0 for i,fs in apply(sums,flatten) do integer m = max(apply(true,find,{fs,{solve_order}})) mm = max(m,mm) correct_to[mm] = i end for assert(correct_to[$]=length(sums)) answer = repeat(-1,l) printf(1,"%s - %s is ",{s,res}) solve(sums,solve_order,firsts,correct_to,l,0b1_111_111_111) end procedure constant tests = { `SEND+MORE=MONEY`, `TO+GO=OUT`, `SEND + A + TAD + MORE = MONEY`, `ABRA + CADABRA + ABRA + CADABRA = HOUDINI`, `I + GUESS + THE + TRUTH = HURTS`, `THATS + THE + THEORY = ANYWAY`, -- tad slow, 5.8s vs 0.2s for all above: `SO+MANY+MORE+MEN+SEEM+TO+SAY+THAT+ THEY+MAY+SOON+TRY+TO+STAY+AT+HOME+ SO+AS+TO+SEE+OR+HEAR+THE+SAME+ONE+ MAN+TRY+TO+MEET+THE+TEAM+ON+THE+ MOON+AS+HE+HAS+AT+THE+OTHER+TEN =TESTS`} papply(tests,cryptarithm)
- Output:
SEND+MORE=MONEY - SENDMORY is {9,5,6,7,1,0,8,2} TO+GO=OUT - TOGU is {2,1,8,0} SEND + A + TAD + MORE = MONEY - SENDATMORY is {9,2,8,3,7,4,1,0,6,5} ABRA + CADABRA + ABRA + CADABRA = HOUDINI - ABRCDHOUIN is {7,4,5,1,9,3,6,0,8,2} I + GUESS + THE + TRUTH = HURTS - IGUESTHR is {5,2,6,8,1,4,7,9} THATS + THE + THEORY = ANYWAY - THASEORYNW is {8,6,9,7,3,2,4,1,5,0} SO+MANY+MORE+MEN+SEEM+TO+SAY+THAT+ THEY+MAY+SOON+TRY+TO+STAY+AT+HOME+ SO+AS+TO+SEE+OR+HEAR+THE+SAME+ONE+ MAN+TRY+TO+MEET+THE+TEAM+ON+THE+ MOON+AS+HE+HAS+AT+THE+OTHER+TEN =TESTS - SOMANYRETH is {3,1,2,7,6,4,8,0,9,5}
Translation of Raku
Quite a bit slower than the above
enum S, E, N, D, M, O, R, Y function check(sequence p) if p[M]!=0 and sum(sq_mul(extract(p,{S,E,N,D}),{1000,100,10,1}))+ sum(sq_mul(extract(p,{M,O,R,E}),{1000,100,10,1}))= sum(sq_mul(extract(p,{M,O,N,E,Y}),{10000,1000,100,10,1})) then printf(1," %d%d%d%d\n",extract(p,{S,E,N,D})) printf(1," + %d%d%d%d\n",extract(p,{M,O,R,E})) printf(1,"= %d%d%d%d%d\n",extract(p,{M,O,N,E,Y})) return false end if return true -- continue end function {} = permutes(tagset(9,0),check,8)
- Output:
9567 + 1085 = 10652
Raku
Idiomatic
enum <D E M N O R S Y>;
sub find_solution ( ) {
for ('0'..'9').combinations(8) -> @c {
.return with @c.permutations.first: -> @p {
@p[M] !== 0 and
@p[ S,E,N,D].join
+ @p[ M,O,R,E].join
== @p[M,O,N,E,Y].join
}
}
}
my @s = find_solution();
say " {@s[ S,E,N,D].join}";
say " + {@s[ M,O,R,E].join}";
say "== { @s[M,O,N,E,Y].join}";
- Output:
9567 + 1085 == 10652
Fast
Alternately, a version written in 2015 by Carl Mäsak. Not very concise but quite speedy. Applying the observation that M must be 1 and S must be either 8 or 9 gets the runtime under a tenth of a second.
my int $s = 7;
while ++$s <= 9 {
next if $s == 0;
my int $e = -1;
while ++$e <= 9 {
next if $e == $s;
my int $n = -1;
while ++$n <= 9 {
next if $n == $s;
next if $n == $e;
my int $d = -1;
while ++$d <= 9 {
next if $d == $s;
next if $d == $e;
next if $d == $n;
my int $send = $s*1000 + $e*100 + $n*10 + $d;
my int $m = 1;
my int $o = -1;
while ++$o <= 9 {
next if $o == $s;
next if $o == $e;
next if $o == $n;
next if $o == $d;
next if $o == $m;
my int $r = -1;
while ++$r <= 9 {
next if $r == $s;
next if $r == $e;
next if $r == $n;
next if $r == $d;
next if $r == $m;
next if $r == $o;
my int $more = $m*1000 + $o*100 + $r*10 + $e;
my int $y = -1;
while ++$y <= 9 {
next if $y == $s;
next if $y == $e;
next if $y == $n;
next if $y == $d;
next if $y == $m;
next if $y == $o;
next if $y == $r;
my int $money =
$m*10000 + $o*1000 + $n*100 + $e*10 + $y;
next unless $send + $more == $money;
say 'SEND + MORE == MONEY';
say "$send + $more == $money";
}
}
}
}
}
}
}
printf "%.3f elapsed seconds", now - INIT now;
- Output:
SEND + MORE == MONEY 9567 + 1085 == 10652 0.080 elapsed seconds
Ring
// Bert Mariani 2023-02-09 | A Monte Carlo method to solve the encryted message | SEND + MORE = MONEY
t1 = clock() //
See "Start Clock: "+ t1 +nl
counter = 1
aSendory = [["s","-"],["e","-"],["n","-"],["d","-"],["o","-"],["r","-"],["y","-"]]
aRandom = List(10) // 0-9
for j = 1 to 100000000
aRandom = GenRandomUniq() // 5 2 0 8 7 1 6 4 3 9
for i = 1 to 7
if aRandom[1] != 1 // m = 1
aSendory[i][2] = aRandom[1]
del(aRandom,1) // Shorten list, remove value entry picked
else
del(aRandom,1)
i--
ok
next
if (TrySolution(aSendory)) break else counter++ ok // True=1 = Solution Found
next
See "End Clock.: "+ (clock() - t1) +nl
See "Count cycles: "+ counter +nl
Func GenRandomUniq()
throwLimit = 10 // 0-9, Ring does 1-10
aList = 1:throwLimit
aOut = []
while len(aOut) != throwLimit
nSize = len(aList)
if nSize > 0
nIndex = random(nSize) // Random pointer into list
if nIndex = 0 nIndex=1 ok // Ignore 0, Ring Index at 1-10
aOut + (aList[nIndex] -1) // -1 fix value 0-9, Ring +1 Extract list entry content
del(aList,nIndex) // Shorten list, remove value entry picked
else
aOut + aList[1]
aList = []
ok
end
return aOut
Func TrySolution(aTry)
s1 = ( aTry[1][2]) * 1000 // send
e1 = ( aTry[2][2]) * 100
n1 = ( aTry[3][2]) * 10
d1 = ( aTry[4][2]) * 1
nbr1 = s1 + e1 + n1 + d1
m1 = 1 * 1000 // more
o1 = ( aTry[5][2]) * 100
r1 = ( aTry[6][2]) * 10
e1 = ( aTry[2][2]) * 1
nbr2 = m1 + o1 + r1 + e1
m1 = 1 * 10000 // money
o1 = ( aTry[5][2]) * 1000
n1 = ( aTry[3][2]) * 100
e1 = ( aTry[2][2]) * 10
y1 = ( aTry[7][2]) * 1
nbr3 = m1 + o1 +n1 + e1 + y1
nbr4 = nbr1 + nbr2
if (nbr3 = nbr4)
See "Solved: SEND: "+ nbr1 +" MORE: "+ nbr2 +" MONEY: "+ nbr3 +" Check "+ nbr4 +nl
return (nbr3 = nbr4 ) // True
ok
return False
- Output:
// Output // Start Clock: 32 // Solved: SEND: 9567 MORE: 1085 MONEY: 10652 Check 10652 // End Clock.: 3792 // Count cycles: 28316
Ring
t1 = clock() // start
see "works..." + nl + nl
aListSend = []
aListMore = []
for s = 0 to 9
for e1 = 0 to 9
for n = 0 to 9
for d = 0 to 9
bool = s!=e1 and s!=n and s!=d and e1!=n and e1!=d and n!=d
if bool
sendmore = s*1000+e1*100+n*10+d
add(aListSend,sendmore)
add(aListMore,sendmore)
ok
next
next
next
next
for ind1 = len(aListSend) to 1 step -1
for ind2 = 1 to len(aListMore)
strSend = string(aListSend[ind1])
strMore = string(aListMore[ind2])
m = substr(strMore,1,1)
o = substr(strMore,2,1)
r = substr(strMore,3,1)
e2 = substr(strMore,4,1)
bool1 = substr(strSend,m)
bool2 = substr(strSend,o)
bool3 = substr(strSend,r)
if substr(strSend,2,1) = substr(strMore,4,1)
bool4 = 0
else
bool4 = 1
ok
boolSendMore = bool1 + bool2 + bool3 + bool4
if boolSendMore < 1
if substr(strSend,2,1) = substr(strMore,4,1)
for y = 0 to 9
strMoney1 = substr(strMore,1,1) + substr(strMore,2,1) + substr(strSend,3,1)
strMoney2 = substr(strMore,4,1) + string(y)
strMoney = strMoney1 + strMoney2
numMoney = number(strMoney)
numSend = number(strSend)
numMore = number(strMore)
y1 = substr(strMoney,5,1)
ySend = substr(strSend,y1)
yMore = substr(strMore,y1)
yCheck = ySend + yMore
r = substr(strMore,3,1)
rCheck = substr(strSend,r)
if (numSend + numMore = numMoney) and yCheck < 1 and rCheck < 1
see "SEND = "+strSend+" MORE = "+strMore+" MONEY = "+strMoney+nl+nl
exit 3
ok
next
ok
ok
next
next
see "Time: "+ clock() - t1 // end
see "done..." + nl
- Output:
works... SEND = 9567 MORE = 1085 MONEY = 10652 done... Time: 31.9 s
Wren
Clearly M = 1 and S must be 8 or 9. Brute force can be used to solve for the other letters.
var start = System.clock
var sends = []
var ors = []
var m = 1
var digits = (0..9).toList
digits.remove(m)
for (s in 8..9) {
for (e in digits) {
if (e == s) continue
for (n in digits) {
if (n == s || n == e) continue
for (d in digits) {
if (d == s || d == e || d == n) continue
sends.add([s, e, n, d])
}
}
}
}
for (o in digits) {
for (r in digits) {
if (r == o) continue
ors.add([o, r])
}
}
System.print("Solution(s):")
for (send in sends) {
var SEND = 1000 * send[0] + 100 * send[1] + 10 * send[2] + send[3]
for (or in ors) {
if (send.contains(or[0]) || send.contains(or[1])) continue
var MORE = 1000 * m + 100 * or[0] + 10 * or[1] + send[1]
for (y in digits) {
if (send.contains(y) || or.contains(y)) continue
var MONEY = 10000 * m + 1000 * or[0] + 100 * send[2] + 10 * send[1] + y
if (SEND + MORE == MONEY) {
System.print("%(SEND) + %(MORE) = %(MONEY)")
}
}
}
}
System.print("\nTook %(System.clock - start) seconds.")
- Output:
Solution(s): 9567 + 1085 = 10652 Took 0.051735 seconds.
XPL0
include xpllib; \for Print
def M = 1;
int S, E, N, D, O, R, Y;
begin \ Solve the SEND+MORE=MONEY puzzle - Translation of the Algol 68 sample
for S:= 8 to 9 do
for E:= 0 to 9 do
if E # M and E # S then
for N:= 0 to 9 do
if N # M and N # S and N # E then
for D:= 0 to 9 do
if D # M and D # S and D # E and D # N then
for O:= 0 to 9 do
if O # M and O # S and O # E and O # N and O # D then
for R:= 0 to 9 do
if R # M and R # S and R # E and R # N and R # D and R # O then
for Y:= 0 to 9 do
if Y # M and Y # S and Y # E and Y # N and Y # D and Y # O and Y # R then
if 1000*(S+M) + 100*(E+O) + 10*(N+R) + D + E = 10_000*M + 1000*O + 100*N + 10*E + Y then
Print("%d%d%d%d + %d%d%d%d = %d%d%d%d%d\n", S, E, N, D, M, O, R, E, M, O, N, E, Y);
end
- Output:
9567 + 1085 = 10652