130 lines
3.2 KiB
Common Lisp
130 lines
3.2 KiB
Common Lisp
(defpackage :aoc/2024/07
|
|
(:use :cl :aoc :alexandria :trivia)
|
|
(:export
|
|
#:sample-data
|
|
#:sample-data2
|
|
#:part1
|
|
#:part2
|
|
#:parse-line
|
|
#:make-equation
|
|
#:equation-result
|
|
#:equation-operands
|
|
#:mul-branch
|
|
#:plus-branch
|
|
#:plus-branch
|
|
#:solvedp
|
|
#:valid-equation
|
|
#:concat-branch
|
|
))
|
|
|
|
(in-package :aoc/2024/07)
|
|
|
|
|
|
|
|
|
|
(defstruct equation result operands)
|
|
|
|
|
|
(defun parse-line (line)
|
|
"return an equation with the result and the operands in reverse order as in the text"
|
|
(let ((ns (mapcar #'parse-integer (ppcre:split ":? " line))))
|
|
(make-equation :result (first ns) :operands (reverse (cdr ns)))))
|
|
|
|
|
|
(defun parse-input (lines)
|
|
(mapcar #'parse-line lines))
|
|
|
|
(defparameter input-text (test-input 2024 7))
|
|
(defparameter input-data (parse-input input-text))
|
|
|
|
(defparameter sample-text (aoc:split-lines "190: 10 19
|
|
3267: 81 40 27
|
|
83: 17 5
|
|
156: 15 6
|
|
7290: 6 8 6 15
|
|
161011: 16 10 13
|
|
192: 17 8 14
|
|
21037: 9 7 18 13
|
|
292: 11 6 16 20"))
|
|
(defparameter sample-data
|
|
(parse-input sample-text))
|
|
|
|
|
|
(defun mul-branch (equation)
|
|
"returns simplified equation after applying the * operator or nil if not possible"
|
|
(let ((r (equation-result equation))
|
|
(os (equation-operands equation)))
|
|
(and (zerop (mod r (first os)))
|
|
(make-equation :result (/ r (first os)) :operands (cdr os)))))
|
|
|
|
(defun plus-branch (equation)
|
|
"returns simplified equation after applying the + operator or nil if not possible"
|
|
(let ((r (equation-result equation))
|
|
(os (equation-operands equation)))
|
|
(and (>= r(first os))
|
|
(make-equation :result (- r (first os)) :operands (cdr os)))))
|
|
|
|
(defun solvedp (equation)
|
|
"returns true if equation has been solved"
|
|
(let ((r (equation-result equation))
|
|
(os (equation-operands equation)))
|
|
(and
|
|
(= (length os) 1)
|
|
(= r (first os)))))
|
|
|
|
(defun valid-equation (equation)
|
|
"recursively determine if the equation is valid"
|
|
(if (equation-operands equation)
|
|
(let ((mb (mul-branch equation))
|
|
(pb (plus-branch equation)))
|
|
(or
|
|
(solvedp equation)
|
|
(and mb (valid-equation mb))
|
|
(and pb (valid-equation pb))))
|
|
nil))
|
|
|
|
(defun sum-valid-eqs (eqs)
|
|
(loop
|
|
for eq in eqs
|
|
if (valid-equation eq)
|
|
sum (equation-result eq)))
|
|
|
|
(defun part1 (data)
|
|
(format nil "~A" (sum-valid-eqs data)))
|
|
|
|
(defun wrapping-power-of-10 (x)
|
|
(expt 10 (ceiling (log (1+ x) 10))))
|
|
|
|
(defun concat-branch (equation)
|
|
(let* ((r (equation-result equation))
|
|
(os (equation-operands equation))
|
|
(o (first os))
|
|
(wrap (wrapping-power-of-10 o)))
|
|
(and (= (mod r wrap) o)
|
|
(make-equation :result (floor (/ r wrap)) :operands (cdr os)))))
|
|
|
|
(defun valid-equation-part2 (equation)
|
|
(if (equation-operands equation)
|
|
(let ((mb (mul-branch equation))
|
|
(pb (plus-branch equation))
|
|
(cb (concat-branch equation)))
|
|
(or
|
|
(solvedp equation)
|
|
(and cb (valid-equation-part2 cb))
|
|
(and mb (valid-equation-part2 mb))
|
|
(and pb (valid-equation-part2 pb))
|
|
))
|
|
nil))
|
|
|
|
(defun sum-valid-eqs-part2 (eqs)
|
|
(loop
|
|
for eq in eqs
|
|
if (valid-equation-part2 eq)
|
|
sum (equation-result eq)))
|
|
|
|
(defun part2 (data)
|
|
(format nil "~A" (sum-valid-eqs-part2 data)))
|
|
|
|
(defun solve-day ()
|
|
(format t "part1: ~A~%" (part1 input-data))
|
|
(format t "part2: ~A~%" (part2 input-data)))
|