(defparameter *n* 0)
(defun calc-counts (total-weight keys &aux results)
(labels ((calc (left-weight keys-count keys)
(incf *n*)
(cond ((= left-weight 0)
(push keys-count results))
((and (> left-weight 0) (consp keys))
(destructuring-bind (key &rest rest-keys) keys
(calc (- left-weight (key-weight key))
(add-key keys-count key)
keys)
(calc left-weight keys-count rest-keys))))))
(calc total-weight (make-counts keys) keys)
results))
(defun make-counts (keys)
(loop :for key :in keys
:collect (cons key 0)))
(defun add-key (counts k)
(loop :for (key . count) :in counts
:collect (cons key (if (eq key k) (1+ count) count))))
(defun get-key-count (counts k)
(cdr (assoc k counts)))
(defun key-weight (k)
(get k :weight))
(defun (setf key-weight) (w k)
(setf (get k :weight) w))
; --------
(defconstant cake&tea-weight 50)
(defconstant apple-weight 65)
(setf (key-weight 'sour) (+ apple-weight (* 3 cake&tea-weight)))
(setf (key-weight 'half-sour) (+ apple-weight (* 2 cake&tea-weight)))
(setf (key-weight 'sweet) (+ apple-weight cake&tea-weight) )
(defparameter *fmt*
"~%Result #~d
Sour apples: ~4d
Half-sour apples: ~4d
Sweet apples: ~4d
Total apples: ~d, cakes: ~d, tea drinks: ~d
")
(defun main ()
(let ((results (calc-counts 1435 '(sour half-sour sweet))))
(loop :for i :upfrom 1
:for result :in results :do
(let* ((sour (get-key-count result 'sour))
(half (get-key-count result 'half-sour))
(sweet (get-key-count result 'sweet))
(apples (+ sour half sweet))
(c&t (+ (* 3 sour) (* 2 half) sweet)))
(format t *fmt* i sour half sweet apples c&t c&t)))
(format t "~%~a cases~%" *n*)))
(main)