From 784b3a003b8673f784d5a5a993d7f37a131e2d16 Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sat, 2 Dec 2023 14:48:09 +0200 Subject: [PATCH] solve day 2 --- src/day1.zig | 1 - src/day2.zig | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.zig | 8 +++- 3 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 src/day2.zig diff --git a/src/day1.zig b/src/day1.zig index 4bac956..f56895e 100644 --- a/src/day1.zig +++ b/src/day1.zig @@ -1,6 +1,5 @@ const std = @import("std"); -const StringArray = std.ArrayList([]const u8); const digits = [_][]const u8{ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; pub fn part1(lines: [][]const u8) u32 { diff --git a/src/day2.zig b/src/day2.zig new file mode 100644 index 0000000..dee3697 --- /dev/null +++ b/src/day2.zig @@ -0,0 +1,124 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; + +const Cube = enum { Red, Green, Blue }; +const CubeSet = std.EnumArray(Cube, u32); +const Game = struct { + sets: [10]CubeSet, + set_count: u32, +}; + +fn parse_cube(cube_name: []const u8) ?Cube { + if (std.mem.eql(u8, cube_name, "blue")) { + return .Blue; + } else if (std.mem.eql(u8, cube_name, "red")) { + return .Red; + } if (std.mem.eql(u8, cube_name, "green")) { + return .Green; + } + return null; +} + +fn parse_game(game: *Game, line: []const u8) void { + const colon = std.mem.indexOf(u8, line, ":") orelse @panic("Invalid line, missing ':'"); + + game.set_count = 0; + + var game_sets = std.mem.splitSequence(u8, line[(colon+2)..], "; "); + while (game_sets.next()) |game_set_str| { + var cube_set = &game.sets[game.set_count]; + cube_set.* = CubeSet.initFill(0); + game.set_count += 1; + + var cubes = std.mem.splitSequence(u8, game_set_str, ", "); + while (cubes.next()) |cube_count| { + var space = std.mem.indexOf(u8, cube_count, " ") orelse @panic("Invalid format, expected space"); + + var cube = parse_cube(cube_count[(space+1)..]) orelse @panic("Invalid cube name"); + var count = std.fmt.parseInt(u32, cube_count[0..space], 10) catch @panic("Invalid format"); + cube_set.set(cube, count); + } + } +} + +fn parse_games(allocator: Allocator, lines: [][]const u8) ![]Game { + var games = try allocator.alloc(Game, lines.len); + for (0.., lines) |i, line| { + parse_game(&games[i], line); + } + return games; +} + +pub fn part1(allocator: Allocator, lines: [][]const u8) !u32 { + var games = try parse_games(allocator, lines); + defer allocator.free(games); + + const max_red = 12; + const max_green = 13; + const max_blue = 14; + var sum: u32 = 0; + for (1.., games) |idx, game| { + + var possible = true; + for (game.sets[0..game.set_count]) |cube_set| { + if ((cube_set.get(.Red) > max_red) or (cube_set.get(.Blue) > max_blue) or (cube_set.get(.Green) > max_green)) { + possible = false; + break; + } + } + + if (possible) { + sum += @intCast(idx); + } + } + + return sum; +} + +pub fn part2(allocator: Allocator, lines: [][]const u8) !u32 { + var games = try parse_games(allocator, lines); + defer allocator.free(games); + + var sum: u32 = 0; + for (games) |game| { + var max_red: u32 = 0; + var max_green: u32 = 0; + var max_blue: u32 = 0; + + for (game.sets[0..game.set_count]) |cube_set| { + max_red = @max(max_red, cube_set.get(.Red)); + max_green = @max(max_green, cube_set.get(.Green)); + max_blue = @max(max_blue, cube_set.get(.Blue)); + } + + sum += max_red*max_green*max_blue; + } + + return sum; +} + +test "part 1 example" { + var input = [_][]const u8{ + "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" + }; + var actual = try part1(std.testing.allocator, &input); + var expected: u32 = 8; + try std.testing.expectEqual(expected, actual); +} + +test "part 2 example" { + var input = [_][]const u8{ + "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" + }; + var actual = try part2(std.testing.allocator, &input); + var expected: u32 = 2286; + try std.testing.expectEqual(expected, actual); +} diff --git a/src/main.zig b/src/main.zig index b9bae83..b0aadb7 100644 --- a/src/main.zig +++ b/src/main.zig @@ -2,6 +2,7 @@ const std = @import("std"); const StringArray = std.ArrayList([]const u8); const Day1 = @import("./day1.zig"); +const Day2 = @import("./day2.zig"); pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -30,6 +31,9 @@ pub fn main() !void { try lines.append(try allocator.dupe(u8, trimmed_line)); } - std.debug.print("day1: {d}\n", .{Day1.part1(lines.items)}); - std.debug.print("day2: {d}\n", .{Day1.part2(lines.items)}); + // std.debug.print("day1: {d}\n", .{Day1.part1(lines.items)}); + // std.debug.print("day2: {d}\n", .{Day1.part2(lines.items)}); + + std.debug.print("day1: {d}\n", .{try Day2.part1(allocator, lines.items)}); + std.debug.print("day2: {d}\n", .{try Day2.part2(allocator, lines.items)}); }