solve day 4

This commit is contained in:
Rokas Puzonas 2023-12-11 22:11:40 +02:00
parent b863e1b2aa
commit 1d9a506f76
5 changed files with 150 additions and 46 deletions

View File

@ -3,7 +3,7 @@ const Allocator = std.mem.Allocator;
pub const Input = struct {
allocator: Allocator,
lines: [][]const u8
lines: []const []const u8
};
pub const Result = union(enum) {

View File

@ -42,7 +42,7 @@ fn parse_game(game: *Game, line: []const u8) void {
}
}
fn parse_games(allocator: Allocator, lines: [][]const u8) ![]Game {
fn parse_games(allocator: Allocator, lines: []const []const u8) ![]Game {
var games = try allocator.alloc(Game, lines.len);
for (0.., lines) |i, line| {
parse_game(&games[i], line);
@ -102,29 +102,23 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
return .{ .uint = sum };
}
const example_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"
};
test "part 1 example" {
var lines = [_][]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 input = aoc.Input{ .lines = &lines, .allocator = std.testing.allocator };
var input = aoc.Input{ .lines = &example_input, .allocator = std.testing.allocator };
var actual = try part1(&input);
var expected: u32 = 8;
try std.testing.expectEqual(expected, actual.uint);
}
test "part 2 example" {
var lines = [_][]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 input = aoc.Input{ .lines = &lines, .allocator = std.testing.allocator };
var input = aoc.Input{ .lines = &example_input, .allocator = std.testing.allocator };
var actual = try part2(&input);
var expected: u32 = 2286;
try std.testing.expectEqual(expected, actual.uint);

View File

@ -28,7 +28,7 @@ fn append_unique(list: *PointList, point: PointU32) !void {
try list.append(point);
}
fn find_neighbouring_numbers(found_list: *PointList, lines: [][]const u8, x: usize, y: usize) !void {
fn find_neighbouring_numbers(found_list: *PointList, lines: []const []const u8, x: usize, y: usize) !void {
const neighbours = .{
.{ -1, -1 }, .{ 0, -1 }, .{ 1, -1 },
.{ -1, 0 }, .{ 1, 0 },
@ -107,39 +107,28 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
return .{ .uint = sum };
}
const example_input = [_][]const u8{
"467..114..",
"...*......",
"..35..633.",
"......#...",
"617*......",
".....+.58.",
"..592.....",
"......755.",
"...$.*....",
".664.598.."
};
test "part 1 example" {
var lines = [_][]const u8{
"467..114..",
"...*......",
"..35..633.",
"......#...",
"617*......",
".....+.58.",
"..592.....",
"......755.",
"...$.*....",
".664.598.."
};
var input = aoc.Input{ .lines = &lines, .allocator = std.testing.allocator };
var input = aoc.Input{ .lines = &example_input, .allocator = std.testing.allocator };
var actual = try part1(&input);
var expected: u32 = 4361;
try std.testing.expectEqual(expected, actual.uint);
}
test "part 2 example" {
var lines = [_][]const u8{
"467..114..",
"...*......",
"..35..633.",
"......#...",
"617*......",
".....+.58.",
"..592.....",
"......755.",
"...$.*....",
".664.598.."
};
var input = aoc.Input{ .lines = &lines, .allocator = std.testing.allocator };
var input = aoc.Input{ .lines = &example_input, .allocator = std.testing.allocator };
var actual = try part2(&input);
var expected: u32 = 467835;
try std.testing.expectEqual(expected, actual.uint);

119
src/day4.zig Normal file
View File

@ -0,0 +1,119 @@
const aoc = @import("./aoc.zig");
const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const BoundedUintArray = std.BoundedArray(u32, 32);
const Card = struct {
winning: BoundedUintArray,
mine: BoundedUintArray
};
const CardArray = std.ArrayList(Card);
fn parse_numbers(result: *BoundedUintArray, text: []const u8) !void {
var i: usize = 0;
var tokens = std.mem.tokenizeScalar(u8, text, ' ');
while (tokens.next()) |token| : (i += 1) {
const number = try std.fmt.parseInt(u32, token, 10);
try result.append(number);
}
}
fn parse_input(allocator: Allocator, lines: []const []const u8) !CardArray {
var cards = CardArray.init(allocator);
for (lines) |line| {
var card = Card{
.winning = try BoundedUintArray.init(0),
.mine = try BoundedUintArray.init(0)
};
const colon = std.mem.indexOfScalar(u8, line, ':') orelse @panic("Invalid format");
const bar = std.mem.indexOfScalar(u8, line, '|') orelse @panic("Invalid format");
const winning_str = line[(colon+2)..(bar-1)];
try parse_numbers(&card.winning, winning_str);
const mine_str = line[(bar+2)..];
try parse_numbers(&card.mine, mine_str);
try cards.append(card);
}
return cards;
}
pub fn part1(input: *aoc.Input) !aoc.Result {
const allocator = input.allocator;
const cards = try parse_input(allocator, input.lines);
defer cards.deinit();
var result: u32 = 0;
for (cards.items) |card| {
var matches: u32 = 0;
for (card.mine.slice()) |num| {
if (std.mem.indexOfScalar(u32, card.winning.slice(), num) != null) {
matches += 1;
}
}
if (matches >= 1) {
result += try std.math.powi(u32, 2, matches-1);
}
}
return .{ .uint = result };
}
pub fn part2(input: *aoc.Input) !aoc.Result {
const allocator = input.allocator;
const cards = try parse_input(allocator, input.lines);
defer cards.deinit();
var multipliers = try allocator.alloc(u32, cards.items.len);
defer allocator.free(multipliers);
@memset(multipliers, 1);
for (cards.items, 0..) |card, i| {
var matches: u32 = 0;
for (card.mine.slice()) |num| {
if (std.mem.indexOfScalar(u32, card.winning.slice(), num) != null) {
matches += 1;
}
}
for (0..matches) |j| {
multipliers[i+j+1] += multipliers[i];
}
}
var result: u32 = 0;
for (multipliers) |count| {
result += count;
}
return .{ .uint = result };
}
const example_input = [_][]const u8{
"Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53",
"Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19",
"Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1",
"Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83",
"Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36",
"Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11"
};
test "part 1 example" {
var input = aoc.Input{ .lines = &example_input, .allocator = std.testing.allocator };
var actual = try part1(&input);
var expected: u32 = 13;
try std.testing.expectEqual(expected, actual.uint);
}
test "part 2 example" {
var input = aoc.Input{ .lines = &example_input, .allocator = std.testing.allocator };
var actual = try part2(&input);
var expected: u32 = 30;
try std.testing.expectEqual(expected, actual.uint);
}

View File

@ -22,7 +22,8 @@ fn create_day(comptime module: anytype) aoc.Day {
const Days = [_]aoc.Day{
create_day(@import("day1.zig")),
create_day(@import("day2.zig")),
create_day(@import("day3.zig"))
create_day(@import("day3.zig")),
create_day(@import("day4.zig")),
};
pub fn main() !u8 {
@ -100,4 +101,5 @@ test {
_ = @import("day1.zig");
_ = @import("day2.zig");
_ = @import("day3.zig");
_ = @import("day4.zig");
}