Skip to content

Commit

Permalink
2024 day 4
Browse files Browse the repository at this point in the history
  • Loading branch information
agagniere committed Dec 4, 2024
1 parent 5e0a963 commit d5c374f
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 0 deletions.
41 changes: 41 additions & 0 deletions 2024/04/build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const std = @import("std");

pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

const utils = b.dependency("utils", .{ .target = target, .optimize = optimize }).module("utils");

const exe = b.addExecutable(.{
.name = "day4",
.root_source_file = b.path("solve.zig"),
.target = target,
.optimize = optimize,
});

exe.root_module.addImport("utils", utils);
b.installArtifact(exe);

{ // Run
const run_step = b.step("run", "Run the app");
const run_cmd = b.addRunArtifact(exe);

run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
run_step.dependOn(&run_cmd.step);
}
{ // Test
const test_step = b.step("test", "Run unit tests");
const unit_tests = b.addTest(.{
.root_source_file = b.path("solve.zig"),
.target = target,
.optimize = optimize,
});
const run_unit_tests = b.addRunArtifact(unit_tests);

unit_tests.root_module.addImport("utils", utils);
test_step.dependOn(&run_unit_tests.step);
}
}
11 changes: 11 additions & 0 deletions 2024/04/build.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.{
.name = "day04",
.version = "0.1.0",
.dependencies = .{
.utils = .{
.url = "../utils/",
.hash = "122059863bba3b73097c2905eacfa772e5c9ad7cd6616270b08dfdf41e3d81900420",
},
},
.paths = .{ "build.zig", "build.zig.zon", "solve.zig" },
}
167 changes: 167 additions & 0 deletions 2024/04/solve.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
const std = @import("std");
const utils = @import("utils");

const PositionedLetter = std.AutoHashMap(Point, u8);
const Allocator = std.mem.Allocator;

const Point = struct {
x: i32,
y: i32,

pub fn add(self: Point, other: Point) Point {
return .{ .x = self.x + other.x, .y = self.y + other.y };
}

pub fn corners(self: Point) CornerIterator {
return .{ .center = self };
}
};

/// Loop over the 8 possible directions
const DirectionIterator = struct {
index: i32 = 0,

pub fn next(self: *DirectionIterator) ?Point {
if (self.index == 9)
return null;
if (self.index == 4)
self.index += 1;
const result: Point = .{ .x = @mod(self.index, 3) - 1, .y = @divFloor(self.index, 3) - 1 };
self.index += 1;
return result;
}
};

/// Infinite iteration from a point in a given direction
const RayIterator = struct {
current: Point,
move: Point,

pub fn next(self: *RayIterator) ?Point {
self.current = self.current.add(self.move);
return self.current;
}
};

/// Iterate over the 4 corners of a given point
const CornerIterator = struct {
center: Point,
index: u8 = 0,

const corners: [4]Point = .{
.{ .x = -1, .y = -1 },
.{ .x = 1, .y = -1 },
.{ .x = 1, .y = 1 },
.{ .x = -1, .y = 1 },
};

pub fn next(self: *CornerIterator) ?Point {
if (self.index == 4)
return null;
const current = self.center.add(corners[self.index]);
self.index += 1;
return current;
}
};

/// Build the hashmap from an iterator of lines
pub fn parse(allocator: Allocator, input: anytype) !PositionedLetter {
var result = PositionedLetter.init(allocator);
var lines = utils.lineIterator(input);
var y: i32 = 0;

while (lines.next()) |line| {
for (line, 0..line.len) |c, x| {
try result.put(.{ .x = @intCast(x), .y = y }, c);
}
y += 1;
}
return result;
}

pub fn part1(input: PositionedLetter) u32 {
var iter = input.iterator();
var result: u32 = 0;

while (iter.next()) |letter| {
if (letter.value_ptr.* == 'X') {
var directions: DirectionIterator = .{};

while (directions.next()) |direction| {
var ray: RayIterator = .{ .current = letter.key_ptr.*, .move = direction };
var i: u32 = 0;

while (ray.next()) |p| {
if (input.get(p) orelse break != "MAS"[i])
break;
i += 1;
if (i > 2) {
result += 1;
break;
}
}
}
}
}
return result;
}

pub fn part2(input: PositionedLetter) u32 {
var iter = input.iterator();
var result: u32 = 0;

outer: while (iter.next()) |letter| {
if (letter.value_ptr.* == 'A') {
var corners = letter.key_ptr.corners();
var surroundings: [4]u8 = undefined;
var i: u32 = 0;

while (corners.next()) |corner| {
const c = input.get(corner) orelse continue :outer;
surroundings[i] = c;
i += 1;
}
if (std.mem.indexOf(u8, "MSSMMSS", &surroundings) != null) {
result += 1;
}
}
}
return result;
}

pub fn main() !void {
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .{};
defer _ = gpa.deinit();
const allocator = gpa.allocator();

var stdin = std.io.bufferedReader(std.io.getStdIn().reader());

var input = try parse(allocator, stdin.reader());
defer input.deinit();

std.debug.print("Number of 'XMAS' : {:5}\n", .{part1(input)});
std.debug.print("Number of X 'MAS': {:5}\n", .{part2(input)});
}

// -------------------- Tests --------------------

test part1 {
const sample =
\\MMMSXXMASM
\\MSAMXMSMSA
\\AMXSXMAAMM
\\MSAMASMSMX
\\XMASAMXAMM
\\XXAMMXXAMA
\\SMSMSASXSS
\\SAXAMASAAA
\\MAMMMXMMMM
\\MXMXAXMASX
;
var stream = std.io.fixedBufferStream(sample);
var input = try parse(std.testing.allocator, stream.reader());
defer input.deinit();

try std.testing.expectEqual(18, part1(input));
try std.testing.expectEqual(9, part2(input));
}

0 comments on commit d5c374f

Please sign in to comment.