Day 8: Haunted Wasteland
This commit is contained in:
parent
bb5cdf04f2
commit
4bb9840f51
1057
chicken-src.org
1057
chicken-src.org
File diff suppressed because it is too large
Load Diff
1381
chicken.org
1381
chicken.org
File diff suppressed because it is too large
Load Diff
108
day3.scm
108
day3.scm
|
@ -1,8 +1,3 @@
|
|||
;; Puzzle Solution
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*Puzzle Solution][Puzzle Solution:1]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(import (chicken string)
|
||||
(chicken format))
|
||||
(define input "
|
||||
|
@ -147,25 +142,11 @@
|
|||
..666........*....*.....920.....................................................&......*........................759..........875$...........
|
||||
......138....366..797...........584.......247.........................427..206..843...618.....530......................................172..
|
||||
")
|
||||
;; Puzzle Solution:1 ends here
|
||||
|
||||
;; Records
|
||||
|
||||
;; #+NAME: day3-part1-records
|
||||
|
||||
;; [[file:chicken-src.org::day3-part1-records][day3-part1-records]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define-record part-number number line start-col end-col)
|
||||
(define-record part-symbol sym line start-col end-col)
|
||||
(define-record buffer-char char line col)
|
||||
;; day3-part1-records ends here
|
||||
|
||||
;; Indexing the Input
|
||||
|
||||
;; #+NAME: day3-part1-indexing
|
||||
|
||||
;; [[file:chicken-src.org::day3-part1-indexing][day3-part1-indexing]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (index-input input #!optional (indexed-input '()) (line-index 0) (col-index 0))
|
||||
(if (= 0 (length input))
|
||||
(reverse indexed-input)
|
||||
|
@ -181,26 +162,12 @@
|
|||
indexed-input)
|
||||
line-index
|
||||
(+ col-index 1))))))
|
||||
;; day3-part1-indexing ends here
|
||||
|
||||
;; Tokenizing the Indexed Input
|
||||
|
||||
;; #+NAME: day3-part1-number-char-p
|
||||
|
||||
;; [[file:chicken-src.org::day3-part1-number-char-p][day3-part1-number-char-p]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (number-char? c)
|
||||
(case (buffer-char-char c)
|
||||
((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) #t)
|
||||
(else #f)))
|
||||
;; day3-part1-number-char-p ends here
|
||||
|
||||
|
||||
|
||||
;; #+NAME: day3-part1-finalize-token
|
||||
|
||||
;; [[file:chicken-src.org::day3-part1-finalize-token][day3-part1-finalize-token]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (finalize-token buffer)
|
||||
(let* ((rev-buffer (reverse buffer))
|
||||
(line (buffer-char-line (car buffer)))
|
||||
|
@ -213,14 +180,7 @@
|
|||
(make-part-symbol (string->symbol
|
||||
(apply string (map buffer-char-char buffer)))
|
||||
line start-col end-col))))
|
||||
;; day3-part1-finalize-token ends here
|
||||
|
||||
|
||||
|
||||
;; #+NAME: day3-part1-compatible-with-buffer-p
|
||||
|
||||
;; [[file:chicken-src.org::day3-part1-compatible-with-buffer-p][day3-part1-compatible-with-buffer-p]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (compatible-with-buffer? buffer char)
|
||||
(and
|
||||
(not (eqv? #\. (buffer-char-char char)))
|
||||
|
@ -229,14 +189,7 @@
|
|||
(number-char? char))
|
||||
(and (not (number-char? (car buffer)))
|
||||
(not (number-char? char))))))
|
||||
;; day3-part1-compatible-with-buffer-p ends here
|
||||
|
||||
|
||||
|
||||
;; #+NAME: day3-part1-tokenize-indexed-input
|
||||
|
||||
;; [[file:chicken-src.org::day3-part1-tokenize-indexed-input][day3-part1-tokenize-indexed-input]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (tokenize-indexed-input indexed-input #!optional (token-buffer '()) (part-nums '()) (part-syms '()))
|
||||
(if (= 0 (length indexed-input))
|
||||
(values (reverse part-nums)
|
||||
|
@ -260,14 +213,7 @@
|
|||
(if (eqv? #\. (buffer-char-char next-char)) '() (list (car indexed-input)))
|
||||
(if (part-number? token) (cons token part-nums) part-nums)
|
||||
(if (part-symbol? token) (cons token part-syms) part-syms))))))))
|
||||
;; day3-part1-tokenize-indexed-input ends here
|
||||
|
||||
;; Checking for Part Neighbours
|
||||
|
||||
;; #+NAME: day3-part1-neighbours-p
|
||||
|
||||
;; [[file:chicken-src.org::day3-part1-neighbours-p][day3-part1-neighbours-p]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (neighbours? part-num part-sym)
|
||||
(let ((part-num-line (part-number-line part-num))
|
||||
(col-min (- (part-number-start-col part-num) 1))
|
||||
|
@ -278,98 +224,44 @@
|
|||
(<= (part-symbol-start-col part-sym) col-max)
|
||||
(>= (part-symbol-end-col part-sym) col-min)
|
||||
(<= (part-symbol-end-col part-sym) col-max))))
|
||||
;; day3-part1-neighbours-p ends here
|
||||
|
||||
;; Folding Everything Together
|
||||
|
||||
;; #+NAME: day3-part1-real-part-number-p
|
||||
|
||||
;; [[file:chicken-src.org::day3-part1-real-part-number-p][day3-part1-real-part-number-p]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (is-real-part-number? part-num part-syms)
|
||||
(and (< 0 (length part-syms))
|
||||
(or (neighbours? part-num (car part-syms))
|
||||
(is-real-part-number? part-num (cdr part-syms)))))
|
||||
;; day3-part1-real-part-number-p ends here
|
||||
|
||||
|
||||
|
||||
;; #+NAME: day3-part1-fold
|
||||
|
||||
;; [[file:chicken-src.org::day3-part1-fold][day3-part1-fold]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (fold-part-numbers part-nums part-syms)
|
||||
(foldl (lambda (output input)
|
||||
(if (is-real-part-number? input part-syms)
|
||||
(+ output (part-number-number input))
|
||||
output))
|
||||
0 part-nums))
|
||||
;; day3-part1-fold ends here
|
||||
|
||||
|
||||
|
||||
;; #+RESULTS: day3-part1-calc-full
|
||||
;; : 509115
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*Folding Everything Together][Folding Everything Together:5]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (calc-part-1)
|
||||
(let-values (((part-nums part-syms) (tokenize-indexed-input (index-input (string->list input)))))
|
||||
(fold-part-numbers part-nums part-syms)))
|
||||
;; Folding Everything Together:5 ends here
|
||||
|
||||
;; Gather Symbol Neighbours
|
||||
|
||||
;; #+NAME: day3-part2-sym-neighbour-count
|
||||
|
||||
;; [[file:chicken-src.org::day3-part2-sym-neighbour-count][day3-part2-sym-neighbour-count]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (gather-neighbours part-sym part-nums)
|
||||
(foldl (lambda (output input)
|
||||
(if (neighbours? input part-sym)
|
||||
(cons input output)
|
||||
output))
|
||||
(list) part-nums))
|
||||
;; day3-part2-sym-neighbour-count ends here
|
||||
|
||||
;; Put Everything Together
|
||||
|
||||
;; #+NAME: day3-part2-filter
|
||||
|
||||
;; [[file:chicken-src.org::day3-part2-filter][day3-part2-filter]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (filter-gear-candidates part-syms)
|
||||
(foldl (lambda (output input)
|
||||
(if (eqv? '* (part-symbol-sym input))
|
||||
(cons input output) output))
|
||||
(list) part-syms))
|
||||
;; day3-part2-filter ends here
|
||||
|
||||
|
||||
|
||||
;; #+NAME: day3-part2-fold
|
||||
|
||||
;; [[file:chicken-src.org::day3-part2-fold][day3-part2-fold]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (calc-gear-ratio gears)
|
||||
(foldl (lambda (output input)
|
||||
(if (= 2 (length input))
|
||||
(+ output (apply * (map part-number-number input)))
|
||||
output))
|
||||
0 gears))
|
||||
;; day3-part2-fold ends here
|
||||
|
||||
|
||||
|
||||
;; #+RESULTS: day3-part2-calc-full
|
||||
;; : 75220503
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*Put Everything Together][Put Everything Together:5]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (calc-part-2)
|
||||
(let-values (((part-nums part-syms) (tokenize-indexed-input (index-input (string->list input)))))
|
||||
(let ((gear-candidates (map (lambda (x) (gather-neighbours x part-nums)) (filter-gear-candidates part-syms))))
|
||||
(calc-gear-ratio gears))))
|
||||
;; Put Everything Together:5 ends here
|
||||
|
|
102
day4.scm
102
day4.scm
|
@ -1,8 +1,3 @@
|
|||
;; Puzzle Solution
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*Puzzle Solution][Puzzle Solution:1]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(import (chicken string)
|
||||
(chicken irregex))
|
||||
(define input "
|
||||
|
@ -213,35 +208,9 @@
|
|||
Card 205: 2 99 53 15 32 6 16 69 21 14 | 96 98 24 66 6 47 4 54 45 46 42 13 75 11 80 18 34 35 93 79 65 37 40 92 91
|
||||
Card 206: 74 30 29 66 68 2 3 34 79 87 | 63 45 88 78 98 27 97 32 38 75 9 11 71 93 55 69 56 20 12 82 81 41 80 23 94
|
||||
")
|
||||
;; Puzzle Solution:1 ends here
|
||||
|
||||
;; A Record For The Start
|
||||
|
||||
;; Records are always useful, so let's create one to represent an individual card. We want to store the
|
||||
;; card's id (it might be useful in part 2), the winning numbers, and the card's numbers.
|
||||
|
||||
;; Since it could potentially be relevant, I also add a slot for the matches.
|
||||
|
||||
;; /UPDATE: I also added a slot for the number of copies of the scratch card - relevant for part 2./
|
||||
|
||||
;; #+NAME: day4-part1-scratchcard
|
||||
|
||||
;; [[file:chicken-src.org::day4-part1-scratchcard][day4-part1-scratchcard]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define-record scratchcard id winning-numbers card-numbers match-numbers copies)
|
||||
;; day4-part1-scratchcard ends here
|
||||
|
||||
;; Parsing The Input
|
||||
|
||||
;; We know the drill by now, we have to take apart the input strings, and parse them into an easy
|
||||
;; format for us - in our case, this is the ~scratchcard~ record.
|
||||
|
||||
;; For that, I first create the pattern for a card.
|
||||
|
||||
;; #+NAME: day4-part1-card-irregex
|
||||
|
||||
;; [[file:chicken-src.org::day4-part1-card-irregex][day4-part1-card-irregex]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define card-irregex
|
||||
'(: bol
|
||||
(* whitespace)
|
||||
|
@ -253,17 +222,7 @@
|
|||
" | "
|
||||
(submatch-named card-numbers-str (+ (or numeric whitespace)))
|
||||
eol))
|
||||
;; day4-part1-card-irregex ends here
|
||||
|
||||
|
||||
|
||||
;; The pattern is then used to extract every scratch card which is then being parsed in a fold
|
||||
;; statement.
|
||||
|
||||
;; #+NAME: day4-part1-card-fold
|
||||
|
||||
;; [[file:chicken-src.org::day4-part1-card-fold][day4-part1-card-fold]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (input->cards input-str)
|
||||
(irregex-fold card-irregex
|
||||
(lambda (from-index match seed)
|
||||
|
@ -277,19 +236,7 @@
|
|||
'() 1)
|
||||
seed))
|
||||
'() input-str))
|
||||
;; day4-part1-card-fold ends here
|
||||
|
||||
;; Processing The Cards
|
||||
|
||||
;; I compare every card number with every winning number on a card, and put every card number
|
||||
;; with at least one match into the special slot of the record. Note that this is a non-functional
|
||||
;; operation, and thus modifies the original record! That is also the reason why the procedure
|
||||
;; name ends with an ~!~.
|
||||
|
||||
;; #+NAME: day4-part1-card-matching
|
||||
|
||||
;; [[file:chicken-src.org::day4-part1-card-matching][day4-part1-card-matching]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (calc-card-matches card)
|
||||
(let ((winning-nums (scratchcard-winning-numbers card))
|
||||
(card-nums (scratchcard-card-numbers card)))
|
||||
|
@ -301,16 +248,7 @@
|
|||
(scratchcard-match-numbers-set!
|
||||
card (cons card-num (scratchcard-match-numbers card)))))
|
||||
card-nums)))
|
||||
;; day4-part1-card-matching ends here
|
||||
|
||||
|
||||
|
||||
;; As a next step, I calculate the points for each card.
|
||||
|
||||
;; #+NAME: day4-part1-card-points
|
||||
|
||||
;; [[file:chicken-src.org::day4-part1-card-points][day4-part1-card-points]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (card-points card)
|
||||
(let ((match-nums (scratchcard-match-numbers card)))
|
||||
(foldl (lambda (points num)
|
||||
|
@ -318,16 +256,7 @@
|
|||
1
|
||||
(* points 2)))
|
||||
0 match-nums)))
|
||||
;; day4-part1-card-points ends here
|
||||
|
||||
|
||||
|
||||
;; #+RESULTS: day4-part1-calc-full
|
||||
;; : 23441
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*Processing The Cards][Processing The Cards:5]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (calc-part-1)
|
||||
(foldl
|
||||
(lambda (sum card)
|
||||
|
@ -335,14 +264,7 @@
|
|||
(+ sum
|
||||
(card-points card)))
|
||||
0 (input->cards input)))
|
||||
;; Processing The Cards:5 ends here
|
||||
|
||||
;; Puzzle Solution
|
||||
|
||||
;; #+NAME: day4-part2-card-alist
|
||||
|
||||
;; [[file:chicken-src.org::day4-part2-card-alist][day4-part2-card-alist]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (card-alist cards)
|
||||
(foldl (lambda (alist card)
|
||||
(calc-card-matches card)
|
||||
|
@ -350,14 +272,7 @@
|
|||
card
|
||||
alist))
|
||||
'() (reverse cards)))
|
||||
;; day4-part2-card-alist ends here
|
||||
|
||||
|
||||
|
||||
;; #+NAME: day4-part2-gen-copies
|
||||
|
||||
;; [[file:chicken-src.org::day4-part2-gen-copies][day4-part2-gen-copies]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (generate-copies cardlist #!optional (index 1))
|
||||
(let ((index-card (alist-ref index cardlist)))
|
||||
(if index-card
|
||||
|
@ -377,28 +292,11 @@
|
|||
cardlist
|
||||
(+ index 1)))
|
||||
cardlist)))
|
||||
;; day4-part2-gen-copies ends here
|
||||
|
||||
|
||||
|
||||
;; #+NAME: day4-part2-count-scratchcards
|
||||
|
||||
;; [[file:chicken-src.org::day4-part2-count-scratchcards][day4-part2-count-scratchcards]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (count-scratchcards cardlist)
|
||||
(foldl + 0 (map (compose scratchcard-copies cdr) cardlist)))
|
||||
;; day4-part2-count-scratchcards ends here
|
||||
|
||||
|
||||
|
||||
;; #+RESULTS: day4-part2-calc-full
|
||||
;; : 5923918
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*Puzzle Solution][Puzzle Solution:6]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (calc-part-2)
|
||||
(let ((cardlist (card-alist (input->cards input))))
|
||||
(generate-copies cardlist)
|
||||
(count-scratchcards cardlist)))
|
||||
;; Puzzle Solution:6 ends here
|
||||
|
|
169
day5.scm
169
day5.scm
|
@ -1,8 +1,3 @@
|
|||
;; Puzzle Solution
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*Puzzle Solution][Puzzle Solution:1]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(import (chicken fixnum)
|
||||
(chicken sort)
|
||||
(chicken string)
|
||||
|
@ -149,50 +144,22 @@
|
|||
4182586423 2386599151 112380873
|
||||
2564353322 975015905 381274978
|
||||
")
|
||||
;; Puzzle Solution:1 ends here
|
||||
|
||||
;; Mapping Record
|
||||
|
||||
;; #+NAME: day5-part1-mapping-record
|
||||
|
||||
;; [[file:chicken-src.org::day5-part1-mapping-record][day5-part1-mapping-record]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define-record entity type id)
|
||||
(define-record mapping-entry from-type to-type from-start from-end to-start to-end)
|
||||
;; day5-part1-mapping-record ends here
|
||||
|
||||
;; Irregexes
|
||||
|
||||
;; #+NAME: day5-part1-seed-irregex
|
||||
|
||||
;; [[file:chicken-src.org::day5-part1-seed-irregex][day5-part1-seed-irregex]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define seed-irregex
|
||||
'(: (* whitespace)
|
||||
"seeds: "
|
||||
(submatch-named seed-numbers (+ (or numeric whitespace)))))
|
||||
;; day5-part1-seed-irregex ends here
|
||||
|
||||
|
||||
|
||||
;; #+NAME: day5-part1-mapping-irregex
|
||||
|
||||
;; [[file:chicken-src.org::day5-part1-mapping-irregex][day5-part1-mapping-irregex]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define mapping-irregex
|
||||
'(: (submatch-named mapping-from (+ alphabetic))
|
||||
"-to-"
|
||||
(submatch-named mapping-to (+ alphabetic))
|
||||
" map:"
|
||||
(submatch-named mapping-vals (+ (or numeric whitespace)))))
|
||||
;; day5-part1-mapping-irregex ends here
|
||||
|
||||
|
||||
|
||||
;; #+NAME: day5-part1-mapping-nums-irregex
|
||||
|
||||
;; [[file:chicken-src.org::day5-part1-mapping-nums-irregex][day5-part1-mapping-nums-irregex]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define mapping-nums-irregex
|
||||
'(: (* whitespace)
|
||||
(submatch-named to-range (+ numeric))
|
||||
|
@ -200,31 +167,13 @@
|
|||
(submatch-named from-range (+ numeric))
|
||||
(* whitespace)
|
||||
(submatch-named range-size (+ numeric))))
|
||||
;; day5-part1-mapping-nums-irregex ends here
|
||||
|
||||
;; Data Reading
|
||||
|
||||
;; A list of seed numbers:
|
||||
|
||||
;; #+NAME: day5-part1-seeds-list
|
||||
|
||||
;; [[file:chicken-src.org::day5-part1-seeds-list][day5-part1-seeds-list]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (input->seeds-list input)
|
||||
(let ((seeds-str (irregex-match-substring
|
||||
(irregex-search seed-irregex input)
|
||||
'seed-numbers)))
|
||||
(map string->number (string-split seeds-str))))
|
||||
;; day5-part1-seeds-list ends here
|
||||
|
||||
|
||||
|
||||
;; And a mapping from input type (e.g. ~#:soil~) to the mappings to the next type:
|
||||
|
||||
;; #+NAME: day5-part1-mapping-alist
|
||||
|
||||
;; [[file:chicken-src.org::day5-part1-mapping-alist][day5-part1-mapping-alist]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (input->mapping-alist input)
|
||||
(irregex-fold mapping-irregex
|
||||
(lambda (from-index match seed)
|
||||
|
@ -251,14 +200,7 @@
|
|||
'() mapping-vals-str))
|
||||
seed)))
|
||||
'() input))
|
||||
;; day5-part1-mapping-alist ends here
|
||||
|
||||
;; Processing The Data
|
||||
|
||||
;; #+NAME: day5-part1-map-entity-forward
|
||||
|
||||
;; [[file:chicken-src.org::day5-part1-map-entity-forward][day5-part1-map-entity-forward]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (map-entity-forward entity mapping-alist)
|
||||
(let ((maplist (alist-ref (entity-type entity) mapping-alist)))
|
||||
(if maplist
|
||||
|
@ -277,29 +219,13 @@
|
|||
#f maplist)
|
||||
(make-entity default-target-type (entity-id entity))))
|
||||
#f)))
|
||||
;; day5-part1-map-entity-forward ends here
|
||||
|
||||
|
||||
|
||||
;; #+NAME: day5-part1-map-entity-forward-fully
|
||||
|
||||
;; [[file:chicken-src.org::day5-part1-map-entity-forward-fully][day5-part1-map-entity-forward-fully]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (map-entity-forward-fully entity mapping-alist)
|
||||
(let ((new-entity (map-entity-forward entity mapping-alist)))
|
||||
(if new-entity
|
||||
(map-entity-forward-fully new-entity mapping-alist)
|
||||
entity)))
|
||||
;; day5-part1-map-entity-forward-fully ends here
|
||||
|
||||
|
||||
|
||||
;; #+RESULTS: day5-part1-calc-full
|
||||
;; : 1181555926
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*Solution][Solution:3]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (calc-part-1)
|
||||
(let ((seeds (map (cut make-entity #:seed <>) (input->seeds-list input)))
|
||||
(mapping-alist (input->mapping-alist input)))
|
||||
|
@ -307,18 +233,7 @@
|
|||
entity-id
|
||||
(cut map-entity-forward-fully <> mapping-alist))
|
||||
seeds))))
|
||||
;; Solution:3 ends here
|
||||
|
||||
;; Puzzle Solution
|
||||
|
||||
;; All that is needed is to "expand" the seed numbers before continuing. Since we are dealing with such
|
||||
;; a huge number of seeds, I use ~delay-force~ to delay calculation of the later ones until they're
|
||||
;; actually needed.
|
||||
|
||||
;; #+NAME: day5-part2-expand-seeds
|
||||
|
||||
;; [[file:chicken-src.org::day5-part2-expand-seeds][day5-part2-expand-seeds]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (expand-seed existing-seeds start size)
|
||||
(let ((max (- (+ start size) 1)))
|
||||
(do ((seedlist (cons start existing-seeds)
|
||||
|
@ -334,17 +249,7 @@
|
|||
(car seed-nums)
|
||||
(cadr seed-nums))))
|
||||
(expand-seed existing-seeds (car seed-nums) (cadr seed-nums))))
|
||||
;; day5-part2-expand-seeds ends here
|
||||
|
||||
|
||||
|
||||
;; After that, it is /almost/ identical to part 1, but we have to replace the ~foldl~ with a recursive
|
||||
;; function that handles the promises.
|
||||
|
||||
;; #+NAME: day5-part2-fold-seeds
|
||||
|
||||
;; [[file:chicken-src.org::day5-part2-fold-seeds][day5-part2-fold-seeds]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (fold-seeds seeds mapping-alist #!optional (minimum most-positive-fixnum))
|
||||
(let* ((seeds (if (promise? seeds) (force seeds) seeds))
|
||||
(seeds-available? (not (eqv? '() seeds))))
|
||||
|
@ -357,45 +262,14 @@
|
|||
mapping-alist
|
||||
(min minimum location-entity-id)))
|
||||
minimum)))
|
||||
;; day5-part2-fold-seeds ends here
|
||||
|
||||
|
||||
|
||||
;; #+RESULTS: day5-part2-calc-full
|
||||
;; : 37806486
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*Puzzle Solution][Puzzle Solution:5]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (calc-part-2)
|
||||
(let ((seeds (expand-seeds (input->seeds-list input)))
|
||||
(mapping-alist (input->mapping-alist input)))
|
||||
(fold-seeds seeds mapping-alist)))
|
||||
;; Puzzle Solution:5 ends here
|
||||
|
||||
;; The Optimized Solution
|
||||
|
||||
;; For the optimized solution using ranges, a new record type is needed: ~ranged-entity~.
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:1]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define-record ranged-entity type from-id to-id)
|
||||
;; The Optimized Solution:1 ends here
|
||||
|
||||
|
||||
|
||||
;; To map the ~ranged-entity~ onto the next step, it has to be split up according to the
|
||||
;; ~mapping-entry~ ranges.
|
||||
|
||||
;; There are different types of splitting, and when they apply:
|
||||
|
||||
;; - The beginning of ~ranged-entity~ lies lower than the ~mapping-entry~: the part lower has to be
|
||||
;; extracted into a 1:1-mapping for the next step type.
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:2]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (extract-dangling-entity-part ranged-entity type mapping-entry)
|
||||
(let ((mapping-entry-lower-bound (mapping-entry-from-start mapping-entry)))
|
||||
(values (make-ranged-entity type
|
||||
|
@ -404,16 +278,7 @@
|
|||
(make-ranged-entity (ranged-entity-type ranged-entity)
|
||||
mapping-entry-lower-bound
|
||||
(ranged-entity-to-id ranged-entity)))))
|
||||
;; The Optimized Solution:2 ends here
|
||||
|
||||
|
||||
|
||||
;; - The beginning of ~ranged-entity~ is somewhere inside ~mapping-entry~: the part inside the
|
||||
;; ~mapping-entity~'s range has to be extracted and the ids shifted accordingly.
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:3]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (extract-matching-entity-part ranged-entity type mapping-entry)
|
||||
(let* ((mapping-entry-lower-bound (mapping-entry-from-start mapping-entry))
|
||||
(mapping-entry-upper-bound (mapping-entry-from-end mapping-entry))
|
||||
|
@ -434,30 +299,13 @@
|
|||
(+ mapping-entry-upper-bound 1)
|
||||
ranged-entity-upper-bound)
|
||||
#f))))
|
||||
;; The Optimized Solution:3 ends here
|
||||
|
||||
|
||||
|
||||
;; - There is just ~ranged-entity~ left, with nothing else: then it gets a new type, and is otherwise
|
||||
;; passed on 1:1.
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:4]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (map-dangling-entity ranged-entity type)
|
||||
(values (make-ranged-entity type
|
||||
(ranged-entity-from-id ranged-entity)
|
||||
(ranged-entity-to-id ranged-entity))
|
||||
#f))
|
||||
;; The Optimized Solution:4 ends here
|
||||
|
||||
|
||||
|
||||
;; This behemoth determines which of the functions above to call.
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:5]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (map-ranged-entity-forward ranged-entity type level-mappings)
|
||||
(let ((processed-ranged-entity #f)
|
||||
(remaining-ranged-entity #f)
|
||||
|
@ -493,15 +341,7 @@
|
|||
(cons processed-ranged-entity
|
||||
(map-ranged-entity-forward remaining-ranged-entity type (cdr level-mappings)))
|
||||
(list processed-ranged-entity)))))
|
||||
;; The Optimized Solution:5 ends here
|
||||
|
||||
|
||||
|
||||
;; Here, the mapping is being done.
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:6]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (map-ranged-entity-forward-fully ranged-entity mapping-alist)
|
||||
(let ((mappings (alist-ref (ranged-entity-type ranged-entity) mapping-alist)))
|
||||
(if (and (not (eqv? '() mappings))
|
||||
|
@ -523,15 +363,7 @@
|
|||
(- (+ (car seeds) (cadr seeds)) 1))
|
||||
(seeds-list->ranged-entities (cddr seeds)))
|
||||
'()))
|
||||
;; The Optimized Solution:6 ends here
|
||||
|
||||
|
||||
|
||||
;; And here, it is all put together.
|
||||
|
||||
|
||||
;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:7]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (calc-part-2-optimized)
|
||||
(let ((seeds (seeds-list->ranged-entities (input->seeds-list input)))
|
||||
(mapping-alist (input->mapping-alist input)))
|
||||
|
@ -540,4 +372,3 @@
|
|||
(foldl append '()
|
||||
(map (cut map-ranged-entity-forward-fully <> mapping-alist)
|
||||
seeds))))))
|
||||
;; The Optimized Solution:7 ends here
|
||||
|
|
101
day6.scm
101
day6.scm
|
@ -1,58 +1,18 @@
|
|||
;; Puzzle Solution
|
||||
|
||||
;; #+NAME: day6-part1-imports
|
||||
|
||||
;; [[file:chicken-src.org::day6-part1-imports][day6-part1-imports]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(import (chicken string)
|
||||
(chicken irregex))
|
||||
;; day6-part1-imports ends here
|
||||
|
||||
|
||||
|
||||
;; #+NAME: day6-input-scm
|
||||
|
||||
;; [[file:chicken-src.org::day6-input-scm][day6-input-scm]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define input "
|
||||
Time: 58 81 96 76
|
||||
Distance: 434 1041 2219 1218")
|
||||
;; day6-input-scm ends here
|
||||
|
||||
;; Data Extraction
|
||||
|
||||
;; First, we need to define the record for the race data.
|
||||
|
||||
;; #+NAME: day6-part1-race-record
|
||||
|
||||
;; [[file:chicken-src.org::day6-part1-race-record][day6-part1-race-record]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define-record race time-limit record-distance winning-distances losing-distances)
|
||||
;; day6-part1-race-record ends here
|
||||
|
||||
|
||||
|
||||
;; The solution starts with the usual data extraction using ~irregex~.
|
||||
|
||||
;; #+NAME: day6-part1-input-extraction-irregex
|
||||
|
||||
;; [[file:chicken-src.org::day6-part1-input-extraction-irregex][day6-part1-input-extraction-irregex]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define input-extraction-irregex
|
||||
'(: "Time:"
|
||||
(submatch-named time-vals (+ (or numeric whitespace)))
|
||||
"Distance:"
|
||||
(submatch-named distance-vals (+ (or numeric whitespace)))))
|
||||
;; day6-part1-input-extraction-irregex ends here
|
||||
|
||||
|
||||
|
||||
;; Next, the data is converted into ~race~ records.
|
||||
|
||||
;; #+NAME: day6-part1-input--race-records
|
||||
|
||||
;; [[file:chicken-src.org::day6-part1-input--race-records][day6-part1-input--race-records]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (input->race-records input)
|
||||
(let ((match (irregex-search input-extraction-irregex
|
||||
input)))
|
||||
|
@ -60,25 +20,11 @@
|
|||
(make-race time distance #f #f))
|
||||
(map string->number (string-split (irregex-match-substring match 'time-vals)))
|
||||
(map string->number (string-split (irregex-match-substring match 'distance-vals))))))
|
||||
;; day6-part1-input--race-records ends here
|
||||
|
||||
;; Race Calculations
|
||||
|
||||
;; #+NAME: day6-part1-get-distance
|
||||
|
||||
;; [[file:chicken-src.org::day6-part1-get-distance][day6-part1-get-distance]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (get-distance race hold-time)
|
||||
(let ((time-remaining (- (race-time-limit race) hold-time)))
|
||||
(* time-remaining hold-time)))
|
||||
;; day6-part1-get-distance ends here
|
||||
|
||||
|
||||
|
||||
;; #+NAME: day6-part1-calc-race-distances
|
||||
|
||||
;; [[file:chicken-src.org::day6-part1-calc-race-distances][day6-part1-calc-race-distances]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (calc-race-distances race
|
||||
#!optional (hold-time 1) (winning-distances '()) (losing-distances '()))
|
||||
(let* ((record-distance (race-record-distance race))
|
||||
|
@ -95,35 +41,12 @@
|
|||
race (+ hold-time 1)
|
||||
(if is-new-record? (cons new-distance winning-distances) winning-distances)
|
||||
(if is-new-record? losing-distances (cons new-distance losing-distances)))))))
|
||||
;; day6-part1-calc-race-distances ends here
|
||||
|
||||
;; Getting The Result
|
||||
|
||||
;; #+NAME: day6-part1-calc-fn
|
||||
|
||||
;; [[file:chicken-src.org::day6-part1-calc-fn][day6-part1-calc-fn]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(define (calc-part-1)
|
||||
(foldl *
|
||||
1 (map (compose length race-winning-distances)
|
||||
(map calc-race-distances (input->race-records input)))))
|
||||
;; day6-part1-calc-fn ends here
|
||||
|
||||
;; Code Changes
|
||||
|
||||
;; The ~input->race-records~ function has to be rewritten:
|
||||
|
||||
;; #+NAME: day6-part2-input--race-record
|
||||
|
||||
;; [[file:chicken-src.org::day6-part2-input--race-record][day6-part2-input--race-record]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (input->race-record input)
|
||||
(let* ((match (irregex-search input-extraction-irregex input))
|
||||
(time-val ((compose string->number
|
||||
|
@ -137,16 +60,7 @@
|
|||
(cut irregex-match-substring <> 'distance-vals))
|
||||
match)))
|
||||
(make-race time-val distance-val #f #f)))
|
||||
;; day6-part2-input--race-record ends here
|
||||
|
||||
|
||||
|
||||
;; And instead of keeping a list of all winning and losing distances, I use a counter.
|
||||
|
||||
;; #+NAME: day6-part2-calc-race-distances
|
||||
|
||||
;; [[file:chicken-src.org::day6-part2-calc-race-distances][day6-part2-calc-race-distances]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
(define (calc-race-distances-with-counter race
|
||||
#!optional (hold-time 1) (winning-distances 0) (losing-distances 0))
|
||||
(let* ((record-distance (race-record-distance race))
|
||||
|
@ -163,22 +77,7 @@
|
|||
race (+ hold-time 1)
|
||||
(if is-new-record? (+ 1 winning-distances) winning-distances)
|
||||
(if is-new-record? losing-distances (+ 1 losing-distances)))))))
|
||||
;; day6-part2-calc-race-distances ends here
|
||||
|
||||
;; Race Variant Results
|
||||
|
||||
;; #+NAME: day6-part2-calc-fn
|
||||
|
||||
;; [[file:chicken-src.org::day6-part2-calc-fn][day6-part2-calc-fn]]
|
||||
;; -*- geiser-scheme-implementation: chicken -*-
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(define (calc-part-2)
|
||||
(race-winning-distances
|
||||
(calc-race-distances-with-counter (input->race-record input))))
|
||||
;; day6-part2-calc-fn ends here
|
||||
|
|
Loading…
Reference in New Issue