---
title: "Advent of Code 2023: Day Two"
date: 2023-12-02T09:30:06
slug: advent-of-code-2023-day-two
tags: [advent-of-code-2023]
---
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](https://lewisdale.dev/post/tag/advent-of-code-2023/), and the code is available on [Git](https://git.lewisdale.dev/lewis/advent-of-code-2023).

## 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:

```typescript
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:

```typescript
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:

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

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

And my parsing is slightly different:

```typescript
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:

```typescript
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 😅

