The "finding the digits problem" is this:
Find unique decimal digits A, B, C such that
CCC
+ BBB
+ AAA
= CAAB
To solve it using recursion in Common Lisp, I've written this code:
(defun find! ()
(found? 0 ;; initially point to the number 1
'(1 2 3) ;; initial list
'() ;; initially no numbers found
3 ;; numbers list width is 3
) )
(defun found? (index lst occupied width)
(if (< index (1- width))
(do ( (j 1 (1+ j) ) )
( (> j 9) lst)
(unless (some (lambda (x) (= x j)) occupied)
(setf (nth index lst) j)
(push j occupied)
(if (found? (1+ index) lst occupied width) ;; recursion happens here
lst
(setf occupied (remove j occupied)))))
(do ( (j 1 (1+ j) ) )
( (> j 9) lst)
(unless (some (lambda (x) (= x j)) occupied)
(setf (nth index lst) j)
(let ((lefthnd (* 111 (reduce #'+ lst)))
(rghthnd (reduce #'+
(mapcar
(lambda (x y) (* x y))
'(1000 100 10 1)
(list (third lst) (first lst)
(first lst) (second lst))))))
(if (= lefthnd rghthnd)
lst
'nil))))))
The delivered result (lst) is (9 9 9)
The expected result (lst) is (9 8 1) meaning A=9, B=8, C=1 so that the equation CCC + BBB + AAA = CAAB holds i.e.
111 ; CCC
+ 888 ; BBB
+ 999 ; AAA
= 1998 ; CAAB
Which parts of the code should I change so that it gives the expected result? Can someone fix the code? Note that using recursion is a must. Only one line of recursion is enough i.e. like the line where the ;; recursion happens here comment is.
What is the minimal edit to fix this code?
The minimal edit needed to make your code work is the following three small changes (marked with
;;;; NBin the comments):pushofjintooccupied:If you change the
return-fromline to print the result instead of returning it, you will get all of them printed.If you want to get them all in a list instead of being printed, you can surgically append each of the results to some list defined in some outer scope (or
consonto the front and reverse it when it's all done, if you prefer).Or in general, you can change this code to accept a callback and call it with each result, when it is found, and let this callback to do whatever it does with it -- print it, append it to an external list, whatever.
Remarks: your code follows a general recursive-backtracking approach, creating three nested loops structure through recursion. The actual result is calculated -- and put into
lstby surgical manipulation -- at the deepest level of recursion, corresponding to the innermost loop ofjfrom1to9(while avoiding the duplicates).There's lots of inconsequential code here. For instance, the
ifin(if (found? ...) lst)isn't needed at all and can be just replaced with(found? ...). I would also prefer different names --occupiedshould really be namedused,lstshould beres(for "result"),indexis canonically named justi,widthis justn, etc. etc. (naming is important)... But you did request the smallest change.This code calculates the result
lstgradually, as a side effect on the way in to the innermost level of the nested loops, where it is finally fully set up.Thus this code follows e.g. an example of Peter Norvig's PAIP Prolog interpreter, which follows the same paradigm. In pseudocode:
Here's your code re-structured, renamed, and streamlined:
This is now closely resembling the C++ code you once had in your question, where the working function (here,
f) also received just one argument, indicating the depth level of the nested loop -- corresponding to the index of the digit being tried, -- and the rest of the variables were in an outer scope (there, global; here, the auxiliary variables in the containing functionfind2).By the way, you aren't trying any
0s for some reason.