109 lines
4.6 KiB
Common Lisp
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
|