Part 1:
The challenge involves analyzing recorded games where an Elf reveals subsets of cubes in a bag, each identified by a game ID. The goal is to determine which games would be possible if the bag contained specific quantities of red, green, and blue cubes.
For example, the record of a few games might look like this:
Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green
In game 1, three sets of cubes are revealed from the bag (and then put back again). The first set is 3 blue cubes and 4 red cubes; the second set is 1 red cube, 2 green cubes, and 6 blue cubes; the third set is only 2 green cubes.
The Elf would first like to know which games would have been possible if the bag contained only 12 red cubes, 13 green cubes, and 14 blue cubes?
In the example above, games 1, 2, and 5 would have been possible if the bag had been loaded with that configuration. The solution involves summing up the IDs of these possible games. In the provided example, the answer was 8, corresponding to games 1, 2, and 5.
#!/usr/bin/env python3
import sys
from typing import Iterable
MAX_RED = 12
MAX_GREEN = 13
MAX_BLUE = 14
GID_SEP = ": "
DRAW_SEP = "; "
PICK_SEP = ", "
def parse_cubes(cubes: str) -> dict:
counts = {"green": 0, "red": 0, "blue": 0}
for cube in cubes:
count, name = cube.split()
counts[name] += int(count)
return counts
def is_eligible_game(counts: dict) -> bool:
return (
counts["red"] <= MAX_RED
and counts["blue"] <= MAX_BLUE
and counts["green"] <= MAX_GREEN
)
def play_game(line: str) -> int:
# Game N: 3 X, 4 Y; .... ; ..
round_num, round_sets = map(str.strip, line.split(GID_SEP))
round_num = round_num.split()[-1]
round_sets = round_sets.split(DRAW_SEP)
if all(
is_eligible_game(parse_cubes(turns.split(PICK_SEP))) for turns in round_sets
):
return int(round_num)
return 0
def total_eligible_games(lines: Iterable[str]) -> int:
return sum(map(play_game, lines))
def main():
if len(sys.argv) != 2:
sys.exit("Error - No file provided.")
with open(sys.argv[1], "r") as f:
total = total_eligible_games(f)
print(f"Total: {total}")
if __name__ == "__main__":
main()
Part 2:
In Part Two, the Elf poses a second question: finding the fewest number of cubes for each color to make a game possible. The power of a set of cubes is calculated by multiplying the numbers of red, green, and blue cubes together.
Again consider the example games from earlier:
Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green
The power of a set of cubes is equal to the numbers of red, green, and blue cubes multiplied together. The power of the minimum set of cubes in game 1 is 48. In games 2-5 it was 12, 1560, 630, and 36, respectively. The solution involves summing up the power of the minimum set of cubes of these possible games. In the provided example, the answer was 2286.
#!/usr/bin/env python3
import sys
from typing import Iterable
GID_SEP = ": "
DRAW_SEP = "; "
PICK_SEP = ", "
def parse_cubes(cubes: str) -> dict:
counts = {"green": 0, "red": 0, "blue": 0}
for cube in cubes:
count, name = cube.split()
counts[name] += int(count)
return counts
def play_game(line: str) -> int:
# Game N: 3 X, 4 Y; .... ; ..
round_num, round_sets = map(str.strip, line.split(GID_SEP))
round_num = round_num.split()[-1]
round_sets = round_sets.split(DRAW_SEP)
max_counts = {"green": 0, "red": 0, "blue": 0}
for round_set in round_sets:
cur_counts = parse_cubes(round_set.split(PICK_SEP))
for color in ["green", "red", "blue"]:
max_counts[color] = max(max_counts[color], cur_counts[color])
return max_counts["green"] * max_counts["red"] * max_counts["blue"]
def total_powers(lines: Iterable[str]) -> int:
return sum(map(play_game, lines))
def main():
if len(sys.argv) != 2:
sys.exit("Error - No file provided.")
with open(sys.argv[1], "r") as f:
total = total_powers(f)
print(f"Total: {total}")
if __name__ == "__main__":
main()
Review Goals:
General coding comments, style, etc.
What are some possible simplifications? What would you do differently?