(defpackage #:rucksacks
(:use :cl))
(in-package #:rucksacks)
(defvar *rucksacks* ())
(defun chars (s) (loop for c across s collect c))
(with-open-file (s "./list.txt")
(setf *rucksacks*
(loop for line = (read-line s nil)
while line collect (chars line))))
(defmacro find-common-elems (first &rest others)
`(loop for e in ,first when (and ,@(loop for o in others collect `(member e ,o))) collect e))
(defun char-to-priority (c)
(let ((x (char-code c)))
(cond ((and (>= x (char-code #\a)) (<= x (char-code #\z))) (+ 1 (- x (char-code #\a))))
((and (>= x (char-code #\A)) (<= x (char-code #\Z))) (+ 27 (- x (char-code #\A))))
(t 0))))
;----------------------------------Part one------------------------------------
(defun split-bag (bag)
(let ((half (floor (length bag) 2)))
(let ((s1 (subseq bag 0 half)) (s2 (subseq bag half)))
(list s1 s2))))
(defun get-duplicate-priority-by-bag (rucksacks)
(let ((duplicates (mapcar #'(lambda (x) (find-common-elems (car x) (car (cdr x)))) rucksacks)))
(let ((tmp (loop for e in duplicates collect (mapcar #'char-to-priority e))))
(reduce #'+ (loop for e in tmp collect (reduce #'+ (remove-duplicates e)))))))
(defun part-one ()
(get-duplicate-priority-by-bag (mapcar #'split-bag *rucksacks*)))
;----------------------------------Part two------------------------------------
(defun get-groups (bags)
(if bags
(if (> (length bags) 3)
(let ((group (subseq bags 0 3)) (others (subseq bags 3)))
(cons group (get-groups others)))
(list bags))
nil))
(defun get-badge (group)
(let ((b1 (car group)) (group (cdr group)))
(let ((b2 (car group)) (group (cdr group)))
(let ((b3 (car group)))
(remove-duplicates (find-common-elems b1 b2 b3))))))
(defun part-two ()
(let ((groups (get-groups *rucksacks*)))
(reduce #'+
(mapcar #'char-to-priority
(mapcar #'car ;Should only be a single item, so grab the first one we found
(mapcar #'get-badge groups))))))
(format t "Part One: ~d~%Part Two: ~d~%" (part-one) (part-two))