diff options
| author | Alexandre Jesus <adbjesus@gmail.com> | 2024-01-24 22:50:49 +0000 | 
|---|---|---|
| committer | Alexandre Jesus <adbjesus@gmail.com> | 2024-01-24 22:50:49 +0000 | 
| commit | 79b7509103cfc358b2689bfe133b123be2baec2f (patch) | |
| tree | 948853616069e1dd2fd222c1591a008bd28d4e7c | |
| parent | 9b5111f033f908a694592a724190c736005cd0f3 (diff) | |
| download | aoc2023-79b7509103cfc358b2689bfe133b123be2baec2f.tar.gz aoc2023-79b7509103cfc358b2689bfe133b123be2baec2f.zip | |
| -rw-r--r-- | day19.lisp | 94 | 
1 files changed, 40 insertions, 54 deletions
| @@ -1,7 +1,5 @@  (defstruct problem workflows parts) -(defstruct part x m a s) -  (defstruct rule var op value res)  (defun read-rule (string) @@ -34,17 +32,12 @@      ht))  (defun read-part (string) -  (let* ((x 0) (m 0) (a 0) (s 0)) -    (loop for i = 0 then (1+ j) -          as j = (position #\= string :start i) -          while j -          do (let ((num (parse-integer string :start (1+ j) :junk-allowed t)) -                   (chr (aref string (1- j)))) -               (cond ((equal chr #\x) (setf x num)) -                     ((equal chr #\m) (setf m num)) -                     ((equal chr #\a) (setf a num)) -                     ((equal chr #\s) (setf s num))))) -    (make-part :x x :m m :a a :s s))) +  (loop for i = 0 then (1+ j) +        as j = (position #\= string :start i) +        while j +        collect (let ((num (parse-integer string :start (1+ j) :junk-allowed t)) +                      (chr (aref string (1- j)))) +                  (cons chr num))))  (defun read-parts (stream)    (loop for line = (read-line stream nil) @@ -55,30 +48,26 @@    (with-open-file (stream filespec)      (make-problem :workflows (read-workflows stream) :parts (read-parts stream)))) -(defun part-accepted-p (part workflows) -  (labels ((f (rules) -             (loop for rule in rules -                   as rvar = (rule-var rule) -                   as rop = (rule-op rule) -                   as rvalue = (rule-value rule) -                   as rres = (rule-res rule) -                   if (let ((pvalue (cond ((equal rvar #\x) (part-x part)) -                                          ((equal rvar #\m) (part-m part)) -                                          ((equal rvar #\a) (part-a part)) -                                          ((equal rvar #\s) (part-s part))))) -                        (or (not rvar) -                            (and (equal rop #\<) (< pvalue rvalue)) -                            (and (equal rop #\>) (> pvalue rvalue)))) -                     return (cond ((equalp rres "A") t) -                                  ((equalp rres "R") nil) -                                  (t (f (gethash rres workflows))))))) -    (f (gethash "in" workflows)))) +(defun part-accepted-p (part workflows &optional (entry "in")) +  (let ((rules (gethash entry workflows))) +    (loop for rule in rules +          as rvar = (rule-var rule) +          as rop = (rule-op rule) +          as rvalue = (rule-value rule) +          as rres = (rule-res rule) +          as pvalue = (assoc rvar part) +          if (or (not rvar) +                 (and (equal rop #\<) (< (cdr pvalue) rvalue)) +                 (and (equal rop #\>) (> (cdr pvalue) rvalue))) +            return (cond ((equalp rres "A") t) +                         ((equalp rres "R") nil) +                         (t (part-accepted-p part workflows rres))))))  (defun solve1 (filespec)    (let ((problem (read-problem filespec)))      (loop for p in (problem-parts problem)            if (part-accepted-p p (problem-workflows problem)) -            sum (+ (part-x p) (part-m p) (part-a p) (part-s p))))) +            sum (reduce #'+ (mapcar #'cdr p)))))  (defun range-size (range)    (assert (<= (car range) (cdr range))) @@ -98,9 +87,8 @@     (subrange (1- value) #\> range)     (subrange (1+ value) #\< range))) -(defun range-combinations (workflows rulename x m a s) -  (cond ((equalp rulename "A") -         (* (range-size x) (range-size m) (range-size a) (range-size s))) +(defun range-combinations (workflows rulename ranges) +  (cond ((equalp rulename "A") (reduce #'* (mapcar #'range-size (mapcar #'cdr ranges))))          ((equalp rulename "R") 0)          (t (let ((rules (gethash rulename workflows)))               (loop for rule in rules @@ -108,33 +96,31 @@                     as rop = (rule-op rule)                     as rvalue = (rule-value rule)                     as rres = (rule-res rule) -                   as range = (cond -                                ((equal rvar #\x) x) -                                ((equal rvar #\m) m) -                                ((equal rvar #\a) a) -                                ((equal rvar #\s) s)) +                   as range = (cdr (assoc rvar ranges))                     as sub = (when rvalue (subrange rvalue rop range))                     if sub  -                     sum (range-combinations -                          workflows -                          rres -                          (if (equal rvar #\x) sub x) -                          (if (equal rvar #\m) sub m) -                          (if (equal rvar #\a) sub a) -                          (if (equal rvar #\s) sub s)) +                     sum (range-combinations workflows rres +                                             (mapcar +                                              (lambda (range) +                                                (if (equal rvar (car range)) +                                                    (cons rvar sub) +                                                    range)) +                                              ranges))                     if (not rvar) -                     sum (range-combinations workflows rres x m a s) +                     sum (range-combinations workflows rres ranges)                     ;; update subrange -                   do (cond -                        ((equal rvar #\x) (setf x (inv-subrange rvalue rop range))) -                        ((equal rvar #\m) (setf m (inv-subrange rvalue rop range))) -                        ((equal rvar #\a) (setf a (inv-subrange rvalue rop range))) -                        ((equal rvar #\s) (setf s (inv-subrange rvalue rop range))))))))) +                   do (when rvar +                        (setf ranges (copy-tree ranges)) +                        (setf (cdr (assoc rvar ranges)) (inv-subrange rvalue rop range))))))))  (defun solve2 (filespec)    (let* ((problem (read-problem filespec))           (workflows (problem-workflows problem))) -    (range-combinations workflows "in" '(1 . 4000) '(1 . 4000) '(1 . 4000) '(1 . 4000)))) +    (range-combinations workflows "in" +                        '((#\x . (1 . 4000)) +                          (#\m . (1 . 4000)) +                          (#\a . (1 . 4000)) +                          (#\s . (1 . 4000))))))  (print (solve1 "data/19/example.txt")) ;; 19114  (print (solve1 "data/19/input.txt"))   ;; 495298 | 
