Advent-of-Code/day3-rucksack-reorganisatio...

109 lines
4.6 KiB
Common Lisp

;; rucksack has 2 compartments
;; items have types
;; for each type there's 1 compartment where the item must go
;; elf put exactly 1 item into wrong compartment for each rucksack
;; item type is identified by letters a .. z A .. Z case sensitive
;; first half exactly is items in first compartment, second half of chars - items in second compartment
;;; find item type that appears in both compartments for each rucksack
;; translate then item type into priority a .. z -> 1 .. 26 ; A .. Z -> 27 .. 52
;; return sum of all priorities
;;; ok. how to start solving that?
(setq test-line "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL")
;; i need to find char that appears in the first half and in the second half.
;; i could split the line in two, convert to list and use set diff function
(setq half-length (/ (length test-line) 2))
(intersection
(coerce (subseq test-line 0 half-length) 'list)
(coerce (subseq test-line half-length) 'list))
;; and now char to int,
(- (char-int #\a) (- (char-int #\a) 1))
(- (char-int #\z) (- (char-int #\a) 1))
(- (char-int #\A) (- (char-int #\A) 27))
(- (char-int #\Z) (- (char-int #\A) 27))
(lower-case-p #\z)
(lower-case-p #\A)
(defun get-char-priority (ch)
(if (lower-case-p ch) (- (char-int ch) (- (char-int #\a) 1))
(- (char-int ch) (- (char-int #\A) 27))))
(get-char-priority #\a)
(get-char-priority #\z)
(get-char-priority #\A)
(get-char-priority #\L)
(get-char-priority #\Z)
(let* ((test-line "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL")
(first-compartment (coerce (subseq test-line 0 half-length) 'list))
(second-compartment (coerce (subseq test-line half-length) 'list))
(the-misplaced-item-type (intersection first-compartment second-compartment)))
(get-char-priority (car the-misplaced-item-type))) ; in real life I'd need more defensiveness here, CAR woudn't be guaranteed
(defun get-rucksack-misplaced-item-priority (rucksack-as-string)
(let* ((test-line rucksack-as-string)
(half-length (/ (length test-line) 2))
(first-compartment (coerce (subseq test-line 0 half-length)
'list))
(second-compartment (coerce (subseq test-line half-length)
'list))
(the-misplaced-item-type (intersection first-compartment second-compartment)))
(get-char-priority (car the-misplaced-item-type)))
; in real life I'd need more defensiveness here, CAR woudn't be guaranteed
)
(get-rucksack-misplaced-item-priority "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL")
(get-rucksack-misplaced-item-priority "PmmdzqPrVvPwwTWBwg")
;; again I'm making mistakes by referring to the globally visible symbols inside of the functions. so bad.
;; maybe i'd want to use something like "make-symbol" as recommended in the part on macro?
;; now the funciton seems to work, need to iterate over input file, call it for each line and sum
(defun count-priories-in-file (filename)
(let ((running-sum 0))
(with-open-file (in filename)
(loop
for line = (read-line in nil nil)
while line
do (incf running-sum
(get-rucksack-misplaced-item-priority line))
finally (return running-sum)))))
(count-priories-in-file "day3-input.txt")
(count-priories-in-file "day3-test-input.txt")
;;; so, now different task for same input:
;; considering lines in groups of 3, what is their common char (group identification badge)
;; then map to priorities and sum
;; that should be a very similar program.
;; but how can i configure loop to give me 3 lines at a time?
(defun get-three-rucksacks-id-badge (r1 r2 r3)
(let* ((r1 (coerce r1 'list))
(r2 (coerce r2 'list))
(r3 (coerce r3 'list))
(badge-type-char (intersection (intersection r1 r2) r3)))
(get-char-priority (car badge-type-char)))
; in real life I'd need more defensiveness here, CAR woudn't be guaranteed
)
(get-three-rucksacks-id-badge "vJrwpWtwJgWrhcsFMMfFFhFp" "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL" "PmmdzqPrVvPwwTWBwg")
(defun count-id-badges-in-file (filename)
(let ((running-sum 0))
(with-open-file (in filename)
(loop
for line1 = (read-line in nil nil)
for line2 = (read-line in nil nil)
for line3 = (read-line in nil nil)
while line1
do (incf running-sum
(get-three-rucksacks-id-badge line1 line2 line3))
finally (return running-sum)))))
(count-id-badges-in-file "day3-test-input.txt")
(count-id-badges-in-file "day3-input.txt")
;; surely there's a better way to use loop?
;; or maybe a good introduction into how to use it?
;; the documentation site doesn't give examples =C