159
									
								
								src/day16.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								src/day16.zig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,159 @@ | ||||
| const std = @import("std"); | ||||
| const util = @import("util.zig"); | ||||
| const mem = std.mem; | ||||
|  | ||||
| pub fn main() !void { | ||||
|     const input = @embedFile("data/day16.txt"); | ||||
|     const sln = try solve(util.gpa, input); | ||||
|     std.debug.print("{d}\n", .{sln.a}); | ||||
|     std.debug.print("{d}\n", .{sln.b}); | ||||
| } | ||||
|  | ||||
| const Solution = struct { | ||||
|     a: usize, | ||||
|     b: usize, | ||||
| }; | ||||
|  | ||||
| const Direction = enum { | ||||
|     up, | ||||
|     right, | ||||
|     down, | ||||
|     left, | ||||
|  | ||||
|     fn x(self: @This()) isize { | ||||
|         return switch (self) { | ||||
|             .up, .down => 0, | ||||
|             .left => -1, | ||||
|             .right => 1, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     fn y(self: @This()) isize { | ||||
|         return switch (self) { | ||||
|             .left, .right => 0, | ||||
|             .up => -1, | ||||
|             .down => 1, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     fn rotate(self: @This(), nineties: usize) Direction { | ||||
|         return @enumFromInt((@intFromEnum(self) + nineties) % std.enums.values(@This()).len); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| const Point = struct { | ||||
|     x: isize, | ||||
|     y: isize, | ||||
|     dir: Direction, | ||||
| }; | ||||
|  | ||||
| var states: std.AutoArrayHashMap(Point, void) = undefined; | ||||
|  | ||||
| fn run(alloc: mem.Allocator, grid: [][]u8, visited: [][]bool, init_x: isize, init_y: isize, init_dir: Direction) !void { | ||||
|     var x = init_x; | ||||
|     var y = init_y; | ||||
|     var dir = init_dir; | ||||
|  | ||||
|     while (0 <= x and x < grid[0].len - 1 and 0 <= y and y < grid.len - 1) { | ||||
|         visited[@intCast(y)][@intCast(x)] = true; | ||||
|         var looped = try states.getOrPut(.{ .x = x, .y = y, .dir = dir }); | ||||
|         if (looped.found_existing) break; | ||||
|         // std.debug.print("-----\n", .{}); | ||||
|         // std.debug.print("{} {} {}\n", .{ x, y, dir }); | ||||
|         // std.time.sleep(1_000_000_000); | ||||
|         switch (grid[@intCast(y)][@intCast(x)]) { | ||||
|             '.' => { | ||||
|                 x += dir.x(); | ||||
|                 y += dir.y(); | ||||
|             }, | ||||
|             '|' => { | ||||
|                 switch (dir) { | ||||
|                     .up, .down => y += dir.y(), | ||||
|                     .left, .right => { | ||||
|                         try run(alloc, grid, visited, x, y - 1, .up); | ||||
|                         try run(alloc, grid, visited, x, y + 1, .down); | ||||
|                     }, | ||||
|                 } | ||||
|             }, | ||||
|             '-' => { | ||||
|                 switch (dir) { | ||||
|                     .left, .right => x += dir.x(), | ||||
|                     .up, .down => { | ||||
|                         try run(alloc, grid, visited, x - 1, y, .left); | ||||
|                         try run(alloc, grid, visited, x + 1, y, .right); | ||||
|                     }, | ||||
|                 } | ||||
|             }, | ||||
|             '/' => { | ||||
|                 switch (dir) { | ||||
|                     .left, .right => dir = dir.rotate(3), | ||||
|                     .up, .down => dir = dir.rotate(1), | ||||
|                 } | ||||
|                 x += dir.x(); | ||||
|                 y += dir.y(); | ||||
|             }, | ||||
|             '\\' => { | ||||
|                 switch (dir) { | ||||
|                     .left, .right => dir = dir.rotate(1), | ||||
|                     .up, .down => dir = dir.rotate(3), | ||||
|                 } | ||||
|                 x += dir.x(); | ||||
|                 y += dir.y(); | ||||
|             }, | ||||
|             else => unreachable, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn solve(alloc: mem.Allocator, comptime input: []const u8) !Solution { | ||||
|     const trimmed = mem.trimRight(u8, input, "\n\r"); | ||||
|     const w = mem.indexOfScalar(u8, trimmed, '\n') orelse unreachable; | ||||
|     const h = mem.count(u8, trimmed, "\n"); | ||||
|  | ||||
|     var visited = try util.allocGrid(bool, alloc, w, h, false); | ||||
|     const grid = try util.toGridOwned(alloc, trimmed, '\n'); | ||||
|  | ||||
|     states = std.AutoArrayHashMap(Point, void).init(alloc); | ||||
|     defer states.deinit(); | ||||
|     try run(alloc, grid, visited, 0, 0, .right); | ||||
|  | ||||
|     var energized: usize = 0; | ||||
|     for (visited) |row| { | ||||
|         for (row) |cell| { | ||||
|             if (cell) energized += 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (grid) |row| { | ||||
|         alloc.free(row); | ||||
|     } | ||||
|     for (visited) |row| { | ||||
|         alloc.free(row); | ||||
|     } | ||||
|     alloc.free(grid); | ||||
|     alloc.free(visited); | ||||
|     return .{ .a = energized, .b = 0 }; | ||||
| } | ||||
|  | ||||
| const sample = | ||||
|     \\.|...\.... | ||||
|     \\|.-.\..... | ||||
|     \\.....|-... | ||||
|     \\........|. | ||||
|     \\.......... | ||||
|     \\.........\ | ||||
|     \\..../.\\.. | ||||
|     \\.-.-/..|.. | ||||
|     \\.|....-|.\ | ||||
|     \\..//.|.... | ||||
| ; | ||||
|  | ||||
| test "silver" { | ||||
|     const sln = try solve(std.testing.allocator, sample); | ||||
|     try std.testing.expectEqual(@as(usize, 46), sln.a); | ||||
| } | ||||
|  | ||||
| test "gold" { | ||||
|     // const sln = try solve(std.testing.allocator, input); | ||||
|     // try std.testing.expectEqual(@as(usize, 0), sln.b); | ||||
| } | ||||
							
								
								
									
										28
									
								
								src/util.zig
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								src/util.zig
									
									
									
									
									
								
							| @@ -35,3 +35,31 @@ pub fn splitLines(buffer: []const u8) mem.SplitIterator(u8, .scalar) { | ||||
| pub fn splitSpace(buffer: []const u8) mem.SplitIterator(u8, .scalar) { | ||||
|     return split(buffer, ' '); | ||||
| } | ||||
|  | ||||
| pub fn allocGrid(comptime T: type, alloc: mem.Allocator, w: usize, h: usize, init: T) ![][]T { | ||||
|     var grid = try alloc.alloc([]T, h); | ||||
|     for (0..h) |i| { | ||||
|         grid[i] = try alloc.alloc(T, w); | ||||
|         @memset(grid[i], init); | ||||
|     } | ||||
|     return grid; | ||||
| } | ||||
|  | ||||
| pub fn toGridOwned(alloc: mem.Allocator, buffer: []const u8, sep: u8) ![][]u8 { | ||||
|     if (buffer.len == 0) return error.Empty; | ||||
|     const w = mem.indexOfScalar(u8, buffer, sep) orelse unreachable; | ||||
|     var h = mem.count(u8, buffer, &[_]u8{sep}); | ||||
|     if (buffer[buffer.len - 1] != sep) h += 1; | ||||
|  | ||||
|     var grid = try alloc.alloc([]u8, h); | ||||
|  | ||||
|     var it = split(buffer, sep); | ||||
|     var i: usize = 0; | ||||
|     while (it.next()) |line| { | ||||
|         grid[i] = try alloc.alloc(u8, w); | ||||
|         @memcpy(grid[i], line); | ||||
|         i += 1; | ||||
|     } | ||||
|  | ||||
|     return grid; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user