diff options
Diffstat (limited to 'day10.zig')
-rw-r--r-- | day10.zig | 190 |
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"); |