Day 8: Haunted Wasteland

This commit is contained in:
Daniel Ziltener 2023-12-09 10:42:17 +01:00
parent bb5cdf04f2
commit 4bb9840f51
Signed by: zilti
GPG Key ID: B38976E82C9DAE42
7 changed files with 3234 additions and 711 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

108
day3.scm
View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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

1027
day8.scm Normal file

File diff suppressed because it is too large Load Diff