summaryrefslogtreecommitdiff
path: root/aoc24
diff options
context:
space:
mode:
authorMathias Magnusson <mathias@magnusson.space>2024-12-04 13:25:01 +0100
committerMathias Magnusson <mathias@magnusson.space>2024-12-04 13:25:06 +0100
commit26063c022ae7d1bef1575cf1487053a2ecd9445f (patch)
treef0d3da9fc4b44037437d423a5b220b86dee0a114 /aoc24
parent45c79eb6508a523f760352c4eb273ec1c9d42b16 (diff)
downloadprogramming-problem-solving-26063c022ae7d1bef1575cf1487053a2ecd9445f.tar.gz
aoc2024: day 4
Diffstat (limited to 'aoc24')
-rw-r--r--aoc24/src/day4.zig109
1 files changed, 109 insertions, 0 deletions
diff --git a/aoc24/src/day4.zig b/aoc24/src/day4.zig
new file mode 100644
index 0000000..13df02d
--- /dev/null
+++ b/aoc24/src/day4.zig
@@ -0,0 +1,109 @@
+const std = @import("std");
+
+fn cast(n: usize) i32 {
+ return @intCast(n);
+}
+
+const Input = struct {
+ buf: []const u8,
+ w: usize,
+ h: usize,
+
+ pub fn at(self: Input, x: i32, y: i32) ?u8 {
+ if (x < 0 or x >= self.w or y < 0 or y >= self.h) return null;
+ return self.buf[@intCast(y * (@as(i32, @intCast(self.w)) + 1) + x)];
+ }
+};
+
+pub fn parse(_: std.mem.Allocator, data: []const u8) !Input {
+ const width = std.mem.indexOf(u8, data, "\n") orelse return error.InvalidInput;
+ const height = data.len / (width + 1);
+ std.debug.assert((width + 1) * height == data.len);
+ return .{ .buf = data, .w = width, .h = height };
+}
+
+test "part1" {
+ var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer arena.deinit();
+
+ const output = try part1(arena.allocator(), try parse(arena.allocator(),
+ \\MMMSXXMASM
+ \\MSAMXMSMSA
+ \\AMXSXMAAMM
+ \\MSAMASMSMX
+ \\XMASAMXAMM
+ \\XXAMMXXAMA
+ \\SMSMSASXSS
+ \\SAXAMASAAA
+ \\MAMMMXMMMM
+ \\MXMXAXMASX
+ \\
+ ));
+ std.debug.print("got {}\n", .{output});
+ std.debug.assert(output == 18);
+}
+
+pub fn part1(_: std.mem.Allocator, input: Input) !u32 {
+ var count: u32 = 0;
+ for (0..input.h) |y| for (0..input.w) |x| for ([_]@Vector(2, i32){
+ .{ 1, 0 },
+ .{ 1, -1 },
+ .{ 0, -1 },
+ .{ -1, -1 },
+ .{ -1, 0 },
+ .{ -1, 1 },
+ .{ 0, 1 },
+ .{ 1, 1 },
+ }) |dir| {
+ for (0.., "XMAS") |dist, c| {
+ if (input.at(cast(x) + dir[0] * cast(dist), cast(y) + cast(dist) * dir[1]) != c) {
+ break;
+ }
+ } else {
+ count += 1;
+ }
+ };
+
+ return count;
+}
+
+test "part2" {
+ var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer arena.deinit();
+
+ const output = try part2(arena.allocator(), try parse(arena.allocator(),
+ \\MMMSXXMASM
+ \\MSAMXMSMSA
+ \\AMXSXMAAMM
+ \\MSAMASMSMX
+ \\XMASAMXAMM
+ \\XXAMMXXAMA
+ \\SMSMSASXSS
+ \\SAXAMASAAA
+ \\MAMMMXMMMM
+ \\MXMXAXMASX
+ \\
+ ));
+ std.debug.print("got {}\n", .{output});
+ std.debug.assert(output == 9);
+}
+
+fn isOther(a: ?u8, b: ?u8) bool {
+ return switch (a orelse return false) {
+ 'M' => b == 'S',
+ 'S' => b == 'M',
+ else => false,
+ };
+}
+
+pub fn part2(_: std.mem.Allocator, input: Input) !u32 {
+ var count: u32 = 0;
+ for (0..input.h) |y| for (0..input.w) |x| {
+ if (input.at(cast(x), cast(y)) != 'A') continue;
+ if (!isOther(input.at(cast(x) - 1, cast(y) - 1), input.at(cast(x) + 1, cast(y) + 1))) continue;
+ if (!isOther(input.at(cast(x) + 1, cast(y) - 1), input.at(cast(x) - 1, cast(y) + 1))) continue;
+ count += 1;
+ };
+
+ return count;
+}