Advent of Code 2023, Day 2
❄️ Back to Advent of Code 2023 solutions homepage ❄️
# Imports
from aoc23.utils import read_input
import math
input_2 = read_input(2)
Part 1
In the first part of today’s puzzle, we are given a collection of games; each game consists of several rounds, and each round consists of multiple cubes being drawn from a bag. The bag can contain cubes of three different colours (red, green or blue), but we do not know in advance what is in the bag. So for each round of each game, we receive details of the number of cubes of each colour drawn (e.g. 3 red, 5 green, 2 blue). The first task is to determine which of the games is compatible with a hypothetical bag, containing 12 red, 13 green and 14 green cubes.
Firstly, let’s process the input into a more useful form. The line describing each game is a string that is of this form:
input_2[1]
'Game 2: 1 green, 19 blue, 1 red; 8 blue, 4 red; 3 red, 6 blue; 1 green, 1 red, 12 blue'
So let’s convert this to something more useful - a dictionary mapping game numbers to a separate list; each element of these lists represents a round, and consists of another dictionary mapping colours to the number of times that colour was drawn in that round. In other words, the type of this object is dict[int, list[dict[str, int]]]
:
def convert_round_string_to_dict(round_string: str) -> dict[str, int]:
round_dict = {}
strings = round_string.split(', ')
for s in strings:
num, colour = s.split(' ')
round_dict[colour] = int(num)
return round_dict
def process_input_2(input_2: list[str]) -> dict[int, list[dict[str, int]]]:
games = {}
for line in input_2:
game_str, rounds_str = line.split(': ')
game = int(game_str.split(' ')[-1])
round_strings = rounds_str.split('; ')
rounds = [convert_round_string_to_dict(round_str) for round_str in round_strings]
games[game] = rounds
return games
processed_input = process_input_2(input_2)
processed_input[1]
[{'green': 3, 'blue': 1, 'red': 3},
{'blue': 3, 'green': 1, 'red': 3},
{'red': 2, 'green': 12, 'blue': 7},
{'red': 1, 'blue': 4, 'green': 5},
{'green': 7, 'blue': 2, 'red': 2}]
Define the hypothetical bag contents, and then for each round check whether the number of drawn cubes of each colour are less than the hypothetical contents:
hypothetical = {'red': 12, 'green': 13, 'blue': 14}
def check_round_possible(round: dict[str, int], hypothetical: dict[str, int]) -> bool:
return all([
round[colour] <= hypothetical[colour]
for colour in round
])
def is_game_possible(game: list[dict[str, int]], hypothetical: dict[str, int]) -> bool:
return all([
check_round_possible(round, hypothetical)
for round in game
])
sum([
game_num
for game_num, game in processed_input.items()
if is_game_possible(game, hypothetical)
])
1853
And so the part 1 answer is 1853.
Part 2
In the second part, we are asked to compute the minimum number of possible cubes in the bag for each game, and then compute the ‘power’ of each minimum bag. Easy enough - for each game, the minimum number of red cubes is the maximum number of red cubes drawn in all the rounds (and likewise for green and blue cubes).
def compute_minimum_set(game: list[dict[str, int]]) -> dict[str, int]:
minimum_set = {'blue': 0, 'green': 0, 'red': 0}
for round in game:
minimum_set = {
colour: max(minimum_set[colour], round.get(colour, 0))
for colour in ['blue', 'red', 'green']
}
return minimum_set
math.prod(compute_minimum_set(processed_input[1]).values())
252
processed_input[1]
[{'green': 3, 'blue': 1, 'red': 3},
{'blue': 3, 'green': 1, 'red': 3},
{'red': 2, 'green': 12, 'blue': 7},
{'red': 1, 'blue': 4, 'green': 5},
{'green': 7, 'blue': 2, 'red': 2}]
The power of each bag is the product of the minimum bag contents of each colour; adding these up gives the final answer:
power_sum = 0
for game in processed_input.values():
minimum_set = compute_minimum_set(game)
power = math.prod(minimum_set.values())
power_sum += power
power_sum
72706
And so the part 2 answer is: 72706.
Comments