Most of day 6
This commit is contained in:
parent
6228043bf0
commit
e01dc06f7a
285
chicken.org
285
chicken.org
|
@ -2419,3 +2419,288 @@ humidity-to-location map:
|
|||
4182586423 2386599151 112380873
|
||||
2564353322 975015905 381274978
|
||||
#+end_src
|
||||
|
||||
|
||||
* Day 6: Wait For It
|
||||
|
||||
** Part One
|
||||
|
||||
*** Quest
|
||||
|
||||
The ferry quickly brings you across Island Island. After asking around, you discover that there is
|
||||
indeed normally a large pile of sand somewhere near here, but you don't see anything besides lots of
|
||||
water and the small island where the ferry has docked.
|
||||
|
||||
As you try to figure out what to do next, you notice a poster on a wall near the ferry dock. "Boat
|
||||
races! Open to the public! Grand prize is an all-expenses-paid trip to *Desert Island*!" That must
|
||||
be where the sand comes from! Best of all, the boat races are starting in just a few minutes.
|
||||
|
||||
You manage to sign up as a competitor in the boat races just in time. The organizer explains that
|
||||
it's not really a traditional race - instead, you will get a fixed amount of time during which your
|
||||
boat has to travel as far as it can, and you win if your boat goes the farthest.
|
||||
|
||||
As part of signing up, you get a sheet of paper (your puzzle input) that lists the *time* allowed
|
||||
for each race and also the best *distance* ever recorded in that race. To guarantee you win the
|
||||
grand prize, you need to make sure you *go farther in each race* than the current record holder.
|
||||
|
||||
The organizer brings you over to the area where the boat races are held. The boats are much smaller
|
||||
than you expected - they're actually *toy boats*, each with a big button on top. Holding down the
|
||||
button *charges the boat*, and releasing the button *allows the boat to move*. Boats move faster if
|
||||
their button was held longer, but time spent holding the button counts against the total race
|
||||
time. You can only hold the button at the start of the race, and boats don't move until the button
|
||||
is released.
|
||||
|
||||
For example:
|
||||
|
||||
#+begin_example
|
||||
Time: 7 15 30
|
||||
Distance: 9 40 200
|
||||
#+end_example
|
||||
|
||||
This document describes three races:
|
||||
|
||||
- The first race lasts 7 milliseconds. The record distance in this race is 9 millimeters.
|
||||
- The second race lasts 15 milliseconds. The record distance in this race is 40 millimeters.
|
||||
- The third race lasts 30 milliseconds. The record distance in this race is 200 millimeters.
|
||||
|
||||
Your toy boat has a starting speed of *zero millimeters per millisecond*. For each whole millisecond
|
||||
you spend at the beginning of the race holding down the button, the boat's speed increases by *one
|
||||
millimeter per millisecond*.
|
||||
|
||||
So, because the first race lasts 7 milliseconds, you only have a few options:
|
||||
|
||||
- Don't hold the button at all (that is, hold it for *=0= milliseconds*) at the start of the
|
||||
race. The boat won't move; it will have traveled *=0= millimeters* by the end of the race.
|
||||
- Hold the button for *=1= millisecond* at the start of the race. Then, the boat will travel at a
|
||||
speed of =1= millimeter per millisecond for =6= milliseconds, reaching a total distance traveled
|
||||
of *=6 millimeters=.
|
||||
- Hold the button for *=2= milliseconds*, giving the boat a speed of =2= millimeters per
|
||||
millisecond. It will then get =5= milliseconds to move, reaching a total distance of *=10=
|
||||
millimeters*.
|
||||
- Hold the button for *=3= milliseconds*. After its remaining =4= milliseconds of travel time, the
|
||||
boat will have gone *=12= millimeters=.
|
||||
- Hold the button for *=4= milliseconds*. After its remaining =3= milliseconds of travel time, the
|
||||
boat will have gone *=12= millimeters*.
|
||||
- Hold the button for *=5= milliseconds*, causing the boat to travel a total of *=10= millimeters*.
|
||||
- Hold the button for *=6= milliseconds*, causing the boat to travel a total of *=6= millimeters*.
|
||||
- Hold the button for *=7= milliseconds*. That's the entire duration of the race. You never let go
|
||||
of the button. The boat can't move until you let go of the button. Please make sure you let go of
|
||||
the button so the boat gets to move. *=0= millimeters*.
|
||||
|
||||
Since the current record for this race is =9= millimeters, there are actually *=4=* different ways
|
||||
you could win: you could hold the button for =2=, =3=, =4=, or =5= milliseconds at the start of the
|
||||
race.
|
||||
|
||||
In the second race, you could hold the button for at least =4= milliseconds and at most =11=
|
||||
milliseconds and beat the record, a total of *=8=* different ways to win.
|
||||
|
||||
In the third race, you could hold the button for at least =11= milliseconds and no more than =19=
|
||||
milliseconds and still beat the record, a total of *=9=* ways you could win.
|
||||
|
||||
To see how much margin of error you have, determine the *number of ways you can beat the record* in
|
||||
each race; in this example, if you multiply these values together, you get *=288=* (=4= * =8= *
|
||||
=9=).
|
||||
|
||||
Determine the number of ways you could beat the record in each race. *What do you get if you
|
||||
multiply these numbers together?*
|
||||
|
||||
|
||||
*** Puzzle Solution
|
||||
|
||||
#+NAME: day6-part1-imports
|
||||
#+begin_src scheme :exports none :noweb yes :tangle day6.scm
|
||||
(import (chicken string)
|
||||
(chicken irregex))
|
||||
#+end_src
|
||||
|
||||
#+NAME: day6-input-scm
|
||||
#+begin_src scheme :tangle day6.scm :noweb yes :exports none
|
||||
(define input "
|
||||
<<day6-input>>")
|
||||
#+end_src
|
||||
|
||||
**** Data Extraction
|
||||
|
||||
First, we need to define the record for the race data.
|
||||
|
||||
#+NAME: day6-part1-race-record
|
||||
#+begin_src scheme :tangle day6.scm
|
||||
(define-record race time-limit record-distance winning-distances losing-distances)
|
||||
#+end_src
|
||||
|
||||
The solution starts with the usual data extraction using ~irregex~.
|
||||
|
||||
#+NAME: day6-part1-input-extraction-irregex
|
||||
#+begin_src scheme :tangle day6.scm
|
||||
(define input-extraction-irregex
|
||||
'(: "Time:"
|
||||
(submatch-named time-vals (+ (or numeric whitespace)))
|
||||
"Distance:"
|
||||
(submatch-named distance-vals (+ (or numeric whitespace)))))
|
||||
#+end_src
|
||||
|
||||
Next, the data is converted into ~race~ records.
|
||||
|
||||
#+NAME: day6-part1-input--race-records
|
||||
#+begin_src scheme :tangle day6.scm
|
||||
(define (input->race-records input)
|
||||
(let ((match (irregex-search input-extraction-irregex
|
||||
input)))
|
||||
(map (lambda (time distance)
|
||||
(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))))))
|
||||
#+end_src
|
||||
|
||||
**** Race Calculations
|
||||
|
||||
#+NAME: day6-part1-get-distance
|
||||
#+begin_src scheme :tangle day6.scm
|
||||
(define (get-distance race hold-time)
|
||||
(let ((time-remaining (- (race-time-limit race) hold-time)))
|
||||
(* time-remaining hold-time)))
|
||||
#+end_src
|
||||
|
||||
#+NAME: day6-part1-calc-race-distances
|
||||
#+begin_src scheme :tangle day6.scm
|
||||
(define (calc-race-distances race
|
||||
#!optional (hold-time 1) (winning-distances '()) (losing-distances '()))
|
||||
(let* ((record-distance (race-record-distance race))
|
||||
(new-distance (get-distance race hold-time))
|
||||
(is-new-record? (> new-distance record-distance)))
|
||||
(cond
|
||||
((= new-distance 0)
|
||||
(begin
|
||||
(race-winning-distances-set! race winning-distances)
|
||||
(race-losing-distances-set! race losing-distances)
|
||||
race))
|
||||
(else
|
||||
(calc-race-distances
|
||||
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)))))))
|
||||
#+end_src
|
||||
|
||||
**** Getting The Result
|
||||
|
||||
#+NAME: day6-part1-calc-fn
|
||||
#+begin_src scheme :tangle day6.scm :noweb strip-tangle
|
||||
<<day6-part1-imports>>
|
||||
<<day6-input-scm>>
|
||||
<<day6-part1-race-record>>
|
||||
<<day6-part1-input-extraction-irregex>>
|
||||
<<day6-part1-input--race-records>>
|
||||
<<day6-part1-get-distance>>
|
||||
<<day6-part1-calc-race-distances>>
|
||||
(define (calc-part-1)
|
||||
(foldl *
|
||||
1 (map (compose length race-winning-distances)
|
||||
(map calc-race-distances (input->race-records input)))))
|
||||
#+end_src
|
||||
|
||||
#+CALL: day6-part1-calc-fn[:epilogue "(calc-part-1)"]()
|
||||
|
||||
#+RESULTS:
|
||||
: 1159152
|
||||
|
||||
** Part Two
|
||||
|
||||
*** Quest
|
||||
|
||||
As the race is about to start, you realize the piece of paper with race times and record distances
|
||||
you got earlier actually just has very bad [[https://en.wikipedia.org/wiki/Kerning][kerning]]. There's really *only one race* - ignore the
|
||||
spaces between the numbers on each line.
|
||||
|
||||
So, the example from before:
|
||||
|
||||
#+begin_example
|
||||
Time: 7 15 30
|
||||
Distance: 9 40 200
|
||||
#+end_example
|
||||
|
||||
...now instead means this:
|
||||
|
||||
#+begin_example
|
||||
Time: 71530
|
||||
Distance: 940200
|
||||
#+end_example
|
||||
|
||||
Now, you have to figure out how many ways there are to win this single race. In this example, the
|
||||
race lasts for *=71530= milliseconds* and the record distance you need to beat is *=940200=
|
||||
millimeters*. You could hold the button anywhere from =14= to =71516= milliseconds and beat the
|
||||
record, a total of =71503= ways!
|
||||
|
||||
*How many ways can you beat the record in this one much longer race?*
|
||||
|
||||
*** Puzzle Solution
|
||||
|
||||
**** Code Changes
|
||||
|
||||
The ~input->race-records~ function has to be rewritten:
|
||||
|
||||
#+NAME: day6-part2-input--race-record
|
||||
#+begin_src scheme :tangle day6.scm
|
||||
(define (input->race-record input)
|
||||
(let* ((match (irregex-search input-extraction-irregex input))
|
||||
(time-val ((compose string->number
|
||||
(cut foldl string-append "" <>)
|
||||
string-split
|
||||
(cut irregex-match-substring <> 'time-vals))
|
||||
match))
|
||||
(distance-val ((compose string->number
|
||||
(cut foldl string-append "" <>)
|
||||
string-split
|
||||
(cut irregex-match-substring <> 'distance-vals))
|
||||
match)))
|
||||
(make-race time-val distance-val #f #f)))
|
||||
#+end_src
|
||||
|
||||
And instead of keeping a list of all winning and losing distances, I use a counter.
|
||||
|
||||
#+NAME: day6-part2-calc-race-distances
|
||||
#+begin_src scheme :tangle day6.scm
|
||||
(define (calc-race-distances-with-counter race
|
||||
#!optional (hold-time 1) (winning-distances 0) (losing-distances 0))
|
||||
(let* ((record-distance (race-record-distance race))
|
||||
(new-distance (get-distance race hold-time))
|
||||
(is-new-record? (> new-distance record-distance)))
|
||||
(cond
|
||||
((= new-distance 0)
|
||||
(begin
|
||||
(race-winning-distances-set! race winning-distances)
|
||||
(race-losing-distances-set! race losing-distances)
|
||||
race))
|
||||
(else
|
||||
(calc-race-distances
|
||||
race (+ hold-time 1)
|
||||
(if is-new-record? (+ 1 winning-distances) winning-distances)
|
||||
(if is-new-record? losing-distances (+ 1 losing-distances)))))))
|
||||
#+end_src
|
||||
|
||||
**** Race Variant Results
|
||||
|
||||
#+NAME: day6-part2-calc-fn
|
||||
#+begin_src scheme :tangle day6.scm :noweb strip-tangle
|
||||
<<day6-part1-imports>>
|
||||
<<day6-input-scm>>
|
||||
<<day6-part1-race-record>>
|
||||
<<day6-part1-input-extraction-irregex>>
|
||||
<<day6-part2-input--race-record>>
|
||||
<<day6-part1-get-distance>>
|
||||
<<day6-part2-calc-race-distances>>
|
||||
(define (calc-part-2)
|
||||
(race-winning-distances
|
||||
(calc-race-distances-with-counter (input->race-record input))))
|
||||
#+end_src
|
||||
|
||||
#+CALL: day6-part2-calc-fn[:epilogue "(calc-part-2)"]()
|
||||
|
||||
#+RESULTS:
|
||||
|
||||
** Puzzle Input
|
||||
|
||||
#+NAME: day6-input
|
||||
#+begin_src org
|
||||
Time: 58 81 96 76
|
||||
Distance: 434 1041 2219 1218
|
||||
#+end_src
|
||||
|
|
Loading…
Reference in New Issue