Day 2

Author

Julia Romanowska

The input

Each line is a different game. Each game contains draws separated by semicolon. Each draw contains number of cubes that were selected in each color: red, green, or blue.

input_file = open("../../DATA/2023/input_day02.txt", "r");
#input_file = open("DATA/2023/example_input_day02.txt", "r");
peek(input_file, String)
"Game 1: 4 blue, 16 green, 2 red; 5 red, 11 blue, 16 green; 9 green, 11 blue; 10 blue, 6 green, 4 red\nGame 2: 15 green, 20 red, 8 blue; 12 green, 7 red; 10 green, 2 blue, 15 red; 13 blue, 15 red\nGame 3: 8 red, 2 blue; 3 green, 10 blue, 10 red; 7 green, 4 blue, 7 red; 8 r" ⋯ 10303 bytes ⋯ "98: 4 blue, 9 red; 10 red, 1 green, 11 blue; 7 blue, 1 red; 1 red, 6 blue, 1 green\nGame 99: 7 red, 6 green, 2 blue; 8 red; 16 green, 7 red, 4 blue\nGame 100: 1 red, 1 green, 9 blue; 6 blue, 4 green, 3 red; 4 red, 2 green; 3 green, 2 red, 11 blue; 6 green, 5 blue, 1 red\n"

Part 1

The problem

Determine which games would have been possible if the bag had been loaded with only 12 red cubes, 13 green cubes, and 14 blue cubes.

First, let’s create a dataset with all draws.

all_games = DataFrame(
    game_no = 0,
    colors = "",
    draws = 0
);

We will also need a function to find these different numbers and colors.

function find_colors_numbers(draws::String, color::String)
    out_num_cubes = Int32[];
    idx = 1;
    while idx < lastindex(draws)
        m = match(
            Regex(" (?<num_cubes>\\d+) $color"),
            draws,
            idx
        );
        if isnothing(m)
            break
        end
        push!(out_num_cubes, parse(Int32, m["num_cubes"]));
        idx = m.offset + length(m.match);
    end
    return out_num_cubes
end
find_colors_numbers (generic function with 1 method)
all_colors = ["red", "green", "blue"];

line = readline(input_file);
while line != ""
    split_first = split(line, ":");
    game_no = split(
        first(split_first), " "
    ) |>
    x -> parse(Int32, last(x));
    draws = map(
        find_colors_numbers,
        [line, line, line],
        all_colors
    );
    cur_games = DataFrame(
        game_no = game_no,
        colors = all_colors,
        draws = draws
    ) |>
        x -> flatten(x, :draws);
    append!(all_games, cur_games);

    # read the next line:
    global line = readline(input_file);
end

close(input_file)

The solution

Let’s check which draws gave more than 12 red cubes, 13 green cubes, and 14 blue cubes.

all_no_draws = [12, 13, 14];

function get_games_not_possible(color, no_draws)
    cur_subset = subset(
        all_games,
        :colors => col -> col .== color,
        :draws => dr -> dr .> no_draws
    );
    return unique(cur_subset.game_no)
end
get_games_not_possible (generic function with 1 method)
all_games_ids_not_possible = map(
        get_games_not_possible,
        all_colors,
        all_no_draws
    ) |>
        x -> unique(vcat(x...));
all_games_ids_possible = setdiff(unique(all_games.game_no), all_games_ids_not_possible);

The sum of these numbers is 2685.

Part 2

The problem

What is the minimum number of cubes that makes each game possible?

This means, that I need to find the minimum number in each game, for each color.

min_cubes_all_games = combine(
    groupby(all_games, [:game_no, :colors]),
    :draws => (x -> max(x...)) => :max_draw
)
301×3 DataFrame
276 rows omitted
Row game_no colors max_draw
Int64 String Int64
1 0 0
2 1 red 5
3 1 green 16
4 1 blue 11
5 2 red 20
6 2 green 15
7 2 blue 13
8 3 red 10
9 3 green 7
10 3 blue 13
11 4 red 14
12 4 green 13
13 4 blue 18
290 97 red 4
291 97 green 1
292 97 blue 15
293 98 red 10
294 98 green 1
295 98 blue 11
296 99 red 8
297 99 green 16
298 99 blue 4
299 100 red 4
300 100 green 6
301 100 blue 11

The solution

Then, for each game, multiply the minimal numbers and sum up.

powers_per_game = combine(
    groupby(min_cubes_all_games, :game_no),
    :max_draw => (x -> reduce(*, x)) => :power
)
101×2 DataFrame
76 rows omitted
Row game_no power
Int64 Int64
1 0 0
2 1 880
3 2 3900
4 3 910
5 4 3276
6 5 216
7 6 198
8 7 384
9 8 40
10 9 728
11 10 288
12 11 1980
13 12 70
90 89 2250
91 90 51
92 91 864
93 92 1848
94 93 18
95 94 378
96 95 840
97 96 810
98 97 60
99 98 110
100 99 512
101 100 264

The sum of these numbers is 83707.