LD
Change your colour scheme

Advent of Code 2023: Day Two

Published:

On to Day Two of Advent of Code. As before, this post contains spoilers for the solution. You can follow all of the Advent of Code posts using the Advent of Code tag, and the code is available on Git.

A bit of extra setup

Yesterday I was rushing, because it was my second language-change of the morning (PICO-8 -> Rust -> Typescript), so I didn’t bother setting up a test framework. But today I’ve got a bit more time, so I made sure to add ts-jest to the project, so I can actually write “proper” tests.

I haven’t gone back to Day One and added the tests. I have no idea if I will or not - I might just leave it as-is for posterity.

Part One

Given a set of strings that represent games where each game has a round where cubes are pulled from a bag. The data looked like this: Game 1: 2 red, 5 blue; 6 red, 11 green, 2 blue; 2 red, 4 green.

Then calculate which game IDs would be possible given certain limits (in this case, available cubes). The limits are: green: 13, red: 12, blue: 14.

My solution was pretty simple, I parsed each game into an object, that was shaped as:

{
id: number;
blue: number;
red: number;
green: number;
}

I constructed the object:

const parseGame = (input: string): Game => {
const [gameId, rounds] = input.split(':');
const id = parseInt(gameId.split(' ')[1], 10);

const game = rounds.split(';').reduce((game, round) => {
const colors = round.split(',').map(color => color.trim());
colors.forEach(color => {
const [count, colorName] = color.split(' ');
game[colorName as 'blue' | 'green' | 'red'] += parseInt(count, 10);
});
return game;
}, {
blue:0 ,
red: 0,
green: 0
});
return {
id,
...game
}
}

And then filtered out games that had cubes beyond the limits, and summed the ids:

const sumPossibleGames = (games: Game[], limits: Cubes): number => {
const possibleGames = games.filter(game => {
return Object.values(limits).every(color => {
return game[color as keyof Cubes] <= limits[color as keyof Cubes];
});
});
});
return possibleGames.reduce((total, game) => total + game.id, 0);
}

And that worked! Onto part two

## Part Two

Okay now we have to work out the minimum required cubes for each game, multiply them together, and then calculate the sum of that for every game.

Which is where I realised my data model was wrong. I needed to change it so that each game held the individual rounds.

So now, my model is:

type Cubes = {
blue: number;
red: number;
green: number;
}

type Game = {
id: number;
rounds: Cubes[];
}

And my parsing is slightly different:

const parseGame = (input: string): Game => {
const [gameId, roundsInput] = input.split(':');
const id = parseInt(gameId.split(' ')[1], 10);

const rounds = roundsInput.split(';').map(round => {
return round.trim().split(',').map(cube => cube.trim()).reduce((total, cube) => {
const [amount, color] = cube.split(' ');
total[color as keyof Cubes] = parseInt(amount, 10);
return total;
}, {blue: 0, green: 0, red: 0} as Cubes);
});
return {
id,
rounds
}
}

But now I’m able to calculate the results and move on with my day:

const minimumCubesRequiredForGame = (game: Game): Cubes => {
return game.rounds.reduce((total, round) => {
Object.keys(round).forEach(color => {
total[color as keyof Cubes] = Math.max(total[color as keyof Cubes], round[color as keyof Cubes]);
});
return total;
}, {blue: 0, green: 0, red: 0} as Cubes);
}

const calculateMinimumCubePowers = (games: Game[]): number => {
const minimumCubes = games.map(minimumCubesRequiredForGame);
return minimumCubes.reduce((total, cubes) => {
return total + (cubes.blue * cubes.green * cubes.red);
}, 0);
}

And that was enough to complete Day Two. I’m glad it was much simpler than Day One at least 😅

Tags:

About the author

My face

I'm Lewis Dale, a software engineer and web developer based in the UK. I write about writing software, silly projects, and cycling. A lot of cycling. Too much, maybe.

Responses