day 3: strings as sets, loop
This commit is contained in:
108
day3-rucksack-reorganisation.lisp
Normal file
108
day3-rucksack-reorganisation.lisp
Normal file
@@ -0,0 +1,108 @@
|
||||
;; 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
|
||||
Reference in New Issue
Block a user