0

So there was a puzzle:

This equation is incomplete: 1 2 3 4 5 6 7 8 9 = 100. One way to make it accurate is by adding seven plus and minus signs, like so: 1 + 2 + 3 – 4 + 5 + 6 + 78 + 9 = 100. How can you do it using only 3 plus or minus signs?

I'm quite new to Prolog, solved the puzzle, but i wonder how to optimize it

makeInt(S,F,FinInt):-
    getInt(S,F,0,FinInt).

getInt(Start, Finish, Acc, FinInt):-
    0 =< Finish - Start,
    NewAcc is Acc*10 + Start,
    NewStart is Start +1,
    getInt(NewStart, Finish, NewAcc, FinInt).
getInt(Start, Finish, A, A):- 
    0 > Finish - Start.

itCounts(X,Y,Z,Q):-
    member(XLastDigit,[1,2,3,4,5,6]),
    FromY is XLastDigit+1,
    numlist(FromY, 7, ListYLastDigit),
    member(YLastDigit, ListYLastDigit),
    FromZ is YLastDigit+1,
    numlist(FromZ, 8, ListZLastDigit),
    member(ZLastDigit,ListZLastDigit),
    FromQ is ZLastDigit+1, 
    member(YSign,[-1,1]),
    member(ZSign,[-1,1]),
    member(QSign,[-1,1]),
    0 is XLastDigit + YSign*YLastDigit + ZSign*ZLastDigit + QSign*9,
    makeInt(1, XLastDigit, FirstNumber),
    makeInt(FromY, YLastDigit, SecondNumber),
    makeInt(FromZ, ZLastDigit, ThirdNumber),
    makeInt(FromQ, 9, FourthNumber),
    X is FirstNumber,
    Y is YSign*SecondNumber,
    Z is ZSign*ThirdNumber,
    Q is QSign*FourthNumber,
    100 =:= X + Y + Z + Q.
false
  • 10,264
  • 13
  • 101
  • 209
Yegor
  • 1
  • 1

2 Answers2

1

Not sure this stands for an optimization. The code is just shorter:

sum_123456789_eq_100_with_3_sum_or_sub(L) :-
    append([G1,G2,G3,G4], [0'1,0'2,0'3,0'4,0'5,0'6,0'7,0'8,0'9]),
    maplist([X]>>(length(X,N), N>0), [G1,G2,G3,G4]),
    maplist([G,F]>>(member(Op, [0'+,0'-]),F=[Op|G]), [G2,G3,G4], [F2,F3,F4]),
    append([G1,F2,F3,F4], L),
    read_term_from_codes(L, T, []),
    100 is T.
CapelliC
  • 59,646
  • 5
  • 47
  • 90
0

It took me a while, but I got what your code is doing. It's something like this:

itCounts(X,Y,Z,Q) :- % generate X, Y, Z, and Q s.t. X+Y+Z+Q=100, etc.
  generate X as a list of digits
  do the same for Y, Z, and Q
  pick the signs for Y, Z, and Q
  convert all those lists of digits into numbers
  verify that, with the signs, they add to 100.

The inefficiency here is that the testing is all done at the last minute. You can improve the efficiency if you can throw out some possible solutions as soon as you pick one of your numbers, that is, testing earlier.

itCounts(X,Y,Z,Q) :- % generate X, Y, Z, and Q s.t. X+Y+Z+Q=100, etc.
  generate X as a list of digits, and convert it to a number
  if it's so big or small the rest can't possibly bring the sum back to 100, fail
  generate Y as a list of digits, convert to number, and pick it sign
  if it's so big or so small the rest can't possibly bring the sum to 100, fail
  do the same for Z
  do the same for Q

Your function is running pretty fast already, even if I search all possible solutions. It only picks 6 X's; 42 Y's; 224 Z's; and 15 Q's. I don't think optimizing will be worth your while.

But if you really wanted to: I tested this by putting a testing function immediately after selecting an X. It reduced the 6 X's to 3 (all before finding the solution); 42 Y's to 30; 224 Z's to 184; and 15 Q's to 11. I believe we could reduce it further by testing immediately after a Y is picked, to see whether X YSign Y is already so large or small there can be no solution.

In PROLOG programs that are more computationally intensive, putting parts of the 'test' earlier in 'generate and test' algorithms can help a lot.

Topological Sort
  • 2,733
  • 2
  • 27
  • 54