1
0

Solve day 3
Some checks failed
Build and test / test (push) Failing after 1m42s

This commit is contained in:
xeals 2023-12-03 17:19:22 +11:00
parent 84344d12e5
commit 3d36485a52
Signed by: xeals
SSH Key Fingerprint: SHA256:53xHRPqZPQewIgPNiVQ96gm8O4xBVzaxNj1LCSJpTf4

145
src/day03.zig Normal file
View File

@ -0,0 +1,145 @@
const std = @import("std");
const util = @import("util.zig");
pub fn main() !void {
const input = @embedFile("data/day03.txt");
const sln = try solve(util.gpa, input);
std.debug.print("{d}\n", .{sln.sum});
std.debug.print("{d}\n", .{sln.gears});
}
const Part = struct {
value: usize,
line: usize,
start: usize,
end: usize,
};
const Symbol = struct { char: u8, line: usize, offset: usize };
const Solution = struct {
sum: usize,
gears: usize,
};
fn absDiff(comptime T: type, a: T, b: T) T {
return @max(a, b) - @min(a, b);
}
fn solve(alloc: std.mem.Allocator, input: []const u8) !Solution {
var parts = std.ArrayList(Part).init(alloc);
var symbols = std.ArrayList(Symbol).init(alloc);
defer parts.deinit();
defer symbols.deinit();
// Accumulate parts and symbols.
var it = std.mem.splitScalar(u8, input, '\n');
var lnum: usize = 0;
while (it.next()) |line| : (lnum += 1) {
var current: Part = undefined;
var in_part = false;
var offset: usize = 0;
for (line) |char| {
switch (char) {
'0'...'9' => {
if (!in_part) {
current.line = lnum;
current.start = offset;
current.value = 0;
in_part = true;
}
current.value = current.value * 10 + (char - '0');
},
'.' => {
if (in_part) {
current.end = offset - 1;
try parts.append(current);
}
in_part = false;
},
else => {
if (in_part) {
current.end = offset - 1;
try parts.append(current);
}
in_part = false;
try symbols.append(.{ .char = char, .line = lnum, .offset = offset });
},
}
offset += 1;
}
// Handle number at the end of a line.
if (in_part) {
current.end = offset - 1;
try parts.append(current);
}
}
// Locate actual parts.
var sum: usize = 0;
var gear_sum: usize = 0;
var gears = std.AutoHashMap(Symbol, Part).init(alloc);
defer gears.deinit();
ploop: for (parts.items) |part| {
// std.debug.print("part {d}x{d}..{d}\n", .{ part.line, part.start, part.end });
for (symbols.items) |symbol| {
// std.debug.print("symbol {d}x{d}\n", .{ symbol.line, symbol.offset });
const inOffset = part.start <= symbol.offset + 1 and part.end + 1 >= symbol.offset;
const inLine = absDiff(usize, part.line, symbol.line) <= 1;
if (inOffset and inLine) {
// std.debug.print("part {d}x({d}..{d})={d}\n", .{ part.line, part.start, part.end, part.value });
sum += part.value;
// Detect gears.
if (symbol.char == '*') {
if (gears.get(symbol)) |other_gear| {
gear_sum += part.value * other_gear.value;
_ = gears.remove(symbol);
} else {
try gears.put(symbol, part);
}
}
continue :ploop;
}
}
}
return .{ .sum = sum, .gears = gear_sum };
}
test "silver" {
const input =
\\467..114..
\\...*......
\\..35..633.
\\......#...
\\617*......
\\.....+.58.
\\..592.....
\\......755.
\\...$.*....
\\664..598..
;
try std.testing.expectEqual(@as(usize, 4361), (try solve(std.testing.allocator, input)).sum);
}
test "gold" {
const input =
\\467..114..
\\...*......
\\..35..633.
\\......#...
\\617*......
\\.....+.58.
\\..592.....
\\......755.
\\...$.*....
\\.664.598..
;
try std.testing.expectEqual(@as(usize, 467835), (try solve(std.testing.allocator, input)).gears);
}