Advent of Code 2023 β€” Day 6

Catchup time! πŸ˜… Time for day 6 β€” on day 11.

Today's puzzle has us racing boats. But not any boats, toy boats that are wound up with the hold of a button. The longer the button is held, the higher their speed. So holding the button for 3ms, sends the boat off at 3mm/s, 4ms sends the boat off at 4mm/s and so on.

Part 1

There are 3 races to be sailed, for each race we have a maximum number of milliseconds for the race. The race starts when the button to wind up the boat is pressed down, and the time it's held for counts towards the total time.

Our goal is to work out how many ways we can win each race, and multiply the results.

Time:      7  15   30
Distance:  9  40  200

For instance, the first race can be won by folding the button down for 2ms, giving the boat a speed of 2mm/s, which means it will travel for 10mm over 5s. 3ms, gives a speed of 3mm/s over 4s, resulting in a distance of 12mm and so on, for a total of 4 possible winning scenarios.

races = input.map { |l| l.scan(/\d+/).map(&:to_i) }  
races = races[0].zip(races[1])  

wins = {}  
races.each_with_object(wins) do |race, memo|  
  (0...(race[0]).round).each do |time_held|  
    wins[race[1]] ||= 0  
    memo[race[1]] +=1 if time_held * (race[0] - time_held) > race[1]  
  end  
end

This is my code for part 1.

We first build up an array of [[time, distance], ...] then for each race, we check the time we hold the button for incrementally to see if the speed of the boat (the time we've held the button for) is greater than the target distance when speed is multiplied by the time remaining in the race. Then, multiply the scores.

⭐️ Success!

Part 2

As usual with part 2, it's caused by us not reading the input properly the first time! In part 2, we realise that the race times we saw are actually poorly kerned, and it is actually a single race!

So now our time and distance look like this:

Time:      71530
Distance:  940200

In this part, we just need to work out how many times we can win the race.

race = input.map { |l| l.scan(/\d+/).inject(:+) }.map(&:to_i)  

(0...(race[0])).map do |time_held|  
  if time_held * (race[0] - time_held) > race[1]  
    1  
  else  
    0  
  end  
end.inject(:+)

Here's a super simple pass at it, using exactly the same logic as before. I did try and speed it up by only checking half the total time, because it looked like once you reached a maximum at the half-way mark, the rest of the numbers would mirror the first half of the range, but I was off by 1 in a couple of cases, and wanted to move on to day 7, so left it for now.

⭐️ Success!

Performance

day 06
β”œβ”€ part 1 β€” 0.000040s
╰─ part 2 β€” 2.095320s

Part 2, not super fast, but no time to make any improvements!

Published

by Daniel Nitsikopoulos

in posts

Tagged

Β© 2010 - 2024 Daniel Nitsikopoulos. All rights reserved.

πŸ•ΈπŸ’  →