--- title: "Advent of Code 2023: Day Six" date: 2023-12-06T08:28:43 slug: advent-of-code-2023-day-six tags: [advent-of-code-2023] --- Back to Advent of Code! This post contains spoilers. You can see the rest of the [Advent of Code posts](https://lewisdale.dev/post/tag/advent-of-code-2023), or checkout the [Git repository](https://git.lewisdale.dev/lewis/advent-of-code-2023). I missed yesterdays Advent of Code, so I'll go back and do it later. But, until then, here's Day Six. ## Part One We're having a boat race! We've got some input that looks like: ```txt Time: 7 15 30 Distance: 9 40 200 ``` If we pair each column up, we get a Time/Distance pairing that tells us how long the race lasts, and how far we go. We can "charge up" our boat, by holding down the button, which gives us an extra 1mm/ms velocity. The task: work out how many different ways there are to win each race, and then multiply the results together. Firstly, I'm using [ParJS](https://github.com/GregRos/parjs) as an input parser, because I wanted something similar to [Rust's Nom](https://docs.rs/nom/latest/nom/) that I used last year. Creating the parser was simple enough: ```javascript const timeName = string('Time:').pipe(then(spaces1())); const distanceName = string('Distance:').pipe(then(spaces1())); const timeParser = int().pipe(manySepBy(whitespace().pipe(exactly(2))), between(timeName, whitespace())); const distanceParser = int().pipe(manySepBy(whitespace().pipe(exactly(2))), between(distanceName, whitespace())); const parser = timeParser.pipe(then(distanceParser)); export class BoatRace { private races: Race[] = []; constructor(input: string) { const [times, distances] = parser.parse(input).value; this.races = zip(times, distances) as Race[]; } } ``` Then I just used Range from [immutable.js])(https://immutable-js.com/) to create all of the values between `0` and `time`, and filtered it using a function that tested whether the new velocity was enough to beat the distance with the remaining time. The resulting array length was my number of possible solutions: ```javascript numberOfWinningMethods = (race: Race): number => { const [time, distance] = race; const canWin = (holdingTime: number) => ((time - holdingTime) * holdingTime) > distance; const range = Range(0, time).filter(canWin).cacheResult(); return range.size || 0; } public totalNumberOfWaysToBeatRace(): number { return this.races.map(this.numberOfWinningMethods).reduce((total, value) => total * value, 1); } ``` ## Part Two Oh no, bad kerning strikes again! It turns out that it's not multiple races - it's a single race and the whitespace is just throwing us off. So instead of `7 15 30`, the time is actually `71530`. All I actually had to change here was my parser: ```javascript const numbersParser = anyCharOf("0123456789").pipe(manySepBy(whitespace().pipe(exactly(2))), stringify()); const timeParser = numbersParser.pipe(between(timeName, whitespace())); const distanceParser = numbersParser.pipe(between(distanceName, whitespace())); export class BoatRace { private readonly race: Race; constructor(input: string) { const [times, distances] = parser.parse(input).value; this.race = [parseInt(times), parseInt(distances)]; } public totalNumberOfWaysToBeatRace(): number { return this.numberOfWinningMethods(this.race); } } ``` And that was it! It ran first time! I'm sure there are more efficient solutions that you can get by working out the upper & lower bounds, but if I wanted to do maths by hand I wouldn't have bought a computer.