aboutsummaryrefslogtreecommitdiff
path: root/day10.zig
diff options
context:
space:
mode:
authorMartin Ashby <martin@ashbysoft.com>2023-12-10 23:45:05 +0000
committerMartin Ashby <martin@ashbysoft.com>2023-12-10 23:45:05 +0000
commit4067d244bbde3e8013b11b2c2fe207a72285572d (patch)
tree420b5639e16199189047ce4306ed0de31f7d8ffc /day10.zig
parent328fbedc757756f1e8c8d4a45d3c3e391e77875c (diff)
downloadaoc2023-4067d244bbde3e8013b11b2c2fe207a72285572d.tar.gz
aoc2023-4067d244bbde3e8013b11b2c2fe207a72285572d.tar.bz2
aoc2023-4067d244bbde3e8013b11b2c2fe207a72285572d.tar.xz
aoc2023-4067d244bbde3e8013b11b2c2fe207a72285572d.zip
day 10 pt1
Diffstat (limited to 'day10.zig')
-rw-r--r--day10.zig190
1 files changed, 190 insertions, 0 deletions
diff --git a/day10.zig b/day10.zig
new file mode 100644
index 0000000..3d52a1f
--- /dev/null
+++ b/day10.zig
@@ -0,0 +1,190 @@
+const std = @import("std");
+
+pub fn main() !void {
+ try std.fmt.format(std.io.getStdOut().writer(), "day 10 pt1: {}\n", .{try solve_pt1(std.heap.page_allocator, puzzle_input)});
+}
+
+const Direction = enum { north, east, south, west,
+ fn opp(self: Direction) Direction {
+ return switch (self) {
+ .north => .south,
+ .east => .west,
+ .south => .north,
+ .west => .east,
+ };
+ }
+};
+
+const Cell = enum(u8) {
+ NS = '|',
+ WE = '-',
+ NE = 'L',
+ NW = 'J',
+ SW = '7',
+ SE = 'F',
+ Ground = '.',
+ Start = 'S',
+ _,
+
+ fn next(self: Cell, whence: Direction) ?Direction {
+ // return switch (self) {
+ // .NS => switch (whence) {
+ // .north => .South,
+ // .south => .North,
+ // else => null,
+ // },
+ // else => null,
+ // };
+ // std.log.warn("whence {} cell {}", .{whence, self});
+ return switch (whence) {
+ .north => switch (self) {
+ .NS => .south,
+ .NE => .east,
+ .NW => .west,
+ else => null,
+ },
+ .east => switch (self) {
+ .WE => .west,
+ .NE => .north,
+ .SE => .south,
+ else => null,
+ },
+ .south => switch (self) {
+ .NS => .north,
+ .SW => .west,
+ .SE => .east,
+ else => null,
+ },
+ .west => switch (self) {
+ .WE => .east,
+ .NW => .north,
+ .SW => .south,
+ else => null,
+ },
+ };
+ }
+};
+
+const Coord = struct {
+ x: i64,
+ y: i64,
+
+ fn move(self: Coord, dir: Direction) Coord {
+ return switch (dir) {
+ .north => .{ .x = self.x, .y = self.y - 1 },
+ .south => .{ .x = self.x, .y = self.y + 1 },
+ .east => .{ .x = self.x + 1, .y = self.y },
+ .west => .{ .x = self.x - 1, .y = self.y },
+ };
+ }
+};
+
+const Path = struct {
+ grid: *const Grid,
+ current: Coord,
+ // Doesn't include .current
+ trail: std.ArrayList(Coord),
+ // direction we travelled to get to .current
+ whence: Direction,
+};
+
+const Grid = struct {
+ data: []const u8,
+ width: usize,
+ height: usize,
+
+ fn parse(input: []const u8) !Grid {
+ return .{
+ .data = input,
+ .width = std.mem.indexOfScalar(u8, input, '\n') orelse return error.Foo,
+ .height = std.mem.count(u8, input, "\n") + 1,
+ };
+ }
+
+ fn get(self: Grid, c: Coord) ?Cell {
+ if (c.x < 0) return null;
+ if (c.y < 0) return null;
+ if (c.x >= self.width) return null;
+ if (c.y >= self.height) return null;
+ return @enumFromInt(self.data[@intCast(c.x + (c.y * (@as(i64, @intCast(self.width)) + 1)))]); // skip the newline
+ }
+
+ fn findStart(self: Grid) ?Coord {
+ for (0..self.width) |x| {
+ for (0..self.height) |y| {
+ const coord: Coord = .{ .x = @intCast(x), .y = @intCast(y) };
+ //std.log.warn("checking {any} for start", .{coord});
+ if (self.get(coord) == .Start) {
+ return coord;
+ }
+ }
+ }
+ return null;
+ }
+};
+
+fn solve_pt1(a: std.mem.Allocator, input: []const u8) !u64 {
+ // read the Grid
+ // find the start pos
+ // setup 4 Paths on each NESW from S and follow them through, one of them
+ // will link up back to S.
+ // half the trail length gives the answer.
+ const grid = try Grid.parse(input);
+ // std.log.warn("grid width {} height {}", .{ grid.width, grid.height });
+
+ const start: Coord = grid.findStart() orelse return error.NoStart;
+
+ const loop: Path = lp1: for (std.enums.values(Direction)) |dir| {
+ const st = start.move(dir);
+ // std.log.warn("st {any}", .{st});
+ _ = grid.get(st) orelse continue :lp1;
+ var trail = std.ArrayList(Coord).init(a);
+ defer trail.deinit();
+ try trail.append(start);
+ var path: Path = .{
+ .current = st,
+ .grid = &grid,
+ .trail = trail,
+ .whence = dir.opp(),
+ };
+ while (true) {
+ const cell: Cell = grid.get(path.current) orelse {
+ // std.log.warn("out of bounds", .{});
+ continue :lp1;
+ }; // out of bounds
+ if (cell == .Start) break :lp1 Path{
+ .current = path.current,
+ .grid = path.grid,
+ .trail = try trail.clone(),
+ .whence = path.whence,
+ }; // we found it yay
+ const dirn = cell.next(path.whence) orelse {
+ // std.log.warn("pipe mismatch", .{});
+ continue :lp1;
+ }; // pipes don't match up
+ const newpos = path.current.move(dirn);
+ path.whence = dirn.opp();
+ try trail.append(path.current);
+ path.current = newpos;
+ }
+ } else {
+ return error.NoLoop;
+ };
+ defer loop.trail.deinit();
+ // std.log.warn("loop {any}", .{loop});
+ return loop.trail.items.len / 2;
+}
+
+test "pt1_1" {
+ try std.testing.expectEqual(@as(u64, 4), try solve_pt1(std.testing.allocator, test_input1));
+}
+
+const test_input1 =
+ \\.....
+ \\.S-7.
+ \\.|.|.
+ \\.L-J.
+ \\.....
+;
+
+const puzzle_input = @embedFile("day10.in");