(ql:quickload "split-sequence")
(ql:quickload "fset")
(defun read-data (path)
(with-open-file (stream path)
(loop for line = (read-line stream nil)
while line collect line)))
(defparameter *input-source*
(cadr *posix-argv*))
;; Useful in testing
(defparameter *input-source* "example_input")
(defparameter *input-source* "input")
(defun parse-line (line)
(split-sequence:split-sequence
(fset:set #\|) (mapcar (lambda (e) (fset:convert 'fset:set e)) (split-sequence:split-sequence #\Space line)) :test #'fset:equal?))
(defun parse-input (lines)
(map 'list #'parse-line lines))
(defparameter *data* (parse-input (read-data *input-source*)))
(defun part1 (input)
(loop for line in input
sum (loop for piece in (cadr line)
as l = (fset:size piece)
count (member l '(2 3 4 7)))))
(defun build-line-legend (line)
(let* ((sets (car line))
(eight (find-if (lambda (e) (= 7 (fset:size e))) sets))
(one (find-if (lambda (e) (= 2 (fset:size e))) sets))
(seven (find-if (lambda (e) (= 3 (fset:size e))) sets))
(four (find-if (lambda (e) (= 4 (fset:size e))) sets))
(three (find-if (lambda (e) (and (= 5 (fset:size e))
(fset:equal? (fset:intersection e seven) seven))) sets))
(nine (fset:union three four))
(two (find-if (lambda (e) (and (= 5 (fset:size e))
(fset:equal? (fset:union e four) eight))) sets))
(five (find-if (lambda (e) (and (= 5 (fset:size e))
(not (fset:equal? e two))
(not (fset:equal? e three)))) sets))
(six (fset:union five (fset:set-difference eight nine)))
(zero (find-if (lambda (e) (and (= 6 (fset:size e))
(not (fset:equal? e six))
(not (fset:equal? e nine)))) sets)))
(list zero one two three four five six seven eight nine)))
(defun digits-to-decimal (digits)
(loop with counter = 0
for digit in digits
do (setf counter (+ (* 10 counter) digit))
finally (return counter)))
(defun decode-number (legend line)
(digits-to-decimal (mapcar (lambda (e) (position e legend :test #'fset:equal?)) line)))
(defun part2 (input)
(loop for line in input
as legend = (build-line-legend line)
sum (decode-number legend (cadr line))))
(format t "===== Part 1 =====")
(format t "Result: ~A~%~%" (time (part1 *data*)))
(format t "===== Part 2 =====")
(format t "Result: ~A~%" (time (part2 *data*)))