This commit is contained in:
		
							
								
								
									
										145
									
								
								src/day03.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								src/day03.zig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,145 @@ | |||||||
|  | const std = @import("std"); | ||||||
|  | const util = @import("util.zig"); | ||||||
|  |  | ||||||
|  | pub fn main() !void { | ||||||
|  |     const input = @embedFile("data/day03.txt"); | ||||||
|  |     const sln = try solve(util.gpa, input); | ||||||
|  |     std.debug.print("{d}\n", .{sln.sum}); | ||||||
|  |     std.debug.print("{d}\n", .{sln.gears}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const Part = struct { | ||||||
|  |     value: usize, | ||||||
|  |     line: usize, | ||||||
|  |     start: usize, | ||||||
|  |     end: usize, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const Symbol = struct { char: u8, line: usize, offset: usize }; | ||||||
|  |  | ||||||
|  | const Solution = struct { | ||||||
|  |     sum: usize, | ||||||
|  |     gears: usize, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | fn absDiff(comptime T: type, a: T, b: T) T { | ||||||
|  |     return @max(a, b) - @min(a, b); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn solve(alloc: std.mem.Allocator, input: []const u8) !Solution { | ||||||
|  |     var parts = std.ArrayList(Part).init(alloc); | ||||||
|  |     var symbols = std.ArrayList(Symbol).init(alloc); | ||||||
|  |  | ||||||
|  |     defer parts.deinit(); | ||||||
|  |     defer symbols.deinit(); | ||||||
|  |  | ||||||
|  |     // Accumulate parts and symbols. | ||||||
|  |     var it = std.mem.splitScalar(u8, input, '\n'); | ||||||
|  |     var lnum: usize = 0; | ||||||
|  |     while (it.next()) |line| : (lnum += 1) { | ||||||
|  |         var current: Part = undefined; | ||||||
|  |         var in_part = false; | ||||||
|  |  | ||||||
|  |         var offset: usize = 0; | ||||||
|  |         for (line) |char| { | ||||||
|  |             switch (char) { | ||||||
|  |                 '0'...'9' => { | ||||||
|  |                     if (!in_part) { | ||||||
|  |                         current.line = lnum; | ||||||
|  |                         current.start = offset; | ||||||
|  |                         current.value = 0; | ||||||
|  |                         in_part = true; | ||||||
|  |                     } | ||||||
|  |                     current.value = current.value * 10 + (char - '0'); | ||||||
|  |                 }, | ||||||
|  |                 '.' => { | ||||||
|  |                     if (in_part) { | ||||||
|  |                         current.end = offset - 1; | ||||||
|  |                         try parts.append(current); | ||||||
|  |                     } | ||||||
|  |                     in_part = false; | ||||||
|  |                 }, | ||||||
|  |                 else => { | ||||||
|  |                     if (in_part) { | ||||||
|  |                         current.end = offset - 1; | ||||||
|  |                         try parts.append(current); | ||||||
|  |                     } | ||||||
|  |                     in_part = false; | ||||||
|  |                     try symbols.append(.{ .char = char, .line = lnum, .offset = offset }); | ||||||
|  |                 }, | ||||||
|  |             } | ||||||
|  |             offset += 1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Handle number at the end of a line. | ||||||
|  |         if (in_part) { | ||||||
|  |             current.end = offset - 1; | ||||||
|  |             try parts.append(current); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Locate actual parts. | ||||||
|  |     var sum: usize = 0; | ||||||
|  |     var gear_sum: usize = 0; | ||||||
|  |     var gears = std.AutoHashMap(Symbol, Part).init(alloc); | ||||||
|  |     defer gears.deinit(); | ||||||
|  |  | ||||||
|  |     ploop: for (parts.items) |part| { | ||||||
|  |         // std.debug.print("part {d}x{d}..{d}\n", .{ part.line, part.start, part.end }); | ||||||
|  |         for (symbols.items) |symbol| { | ||||||
|  |             // std.debug.print("symbol {d}x{d}\n", .{ symbol.line, symbol.offset }); | ||||||
|  |             const inOffset = part.start <= symbol.offset + 1 and part.end + 1 >= symbol.offset; | ||||||
|  |             const inLine = absDiff(usize, part.line, symbol.line) <= 1; | ||||||
|  |             if (inOffset and inLine) { | ||||||
|  |                 // std.debug.print("part {d}x({d}..{d})={d}\n", .{ part.line, part.start, part.end, part.value }); | ||||||
|  |                 sum += part.value; | ||||||
|  |  | ||||||
|  |                 // Detect gears. | ||||||
|  |                 if (symbol.char == '*') { | ||||||
|  |                     if (gears.get(symbol)) |other_gear| { | ||||||
|  |                         gear_sum += part.value * other_gear.value; | ||||||
|  |                         _ = gears.remove(symbol); | ||||||
|  |                     } else { | ||||||
|  |                         try gears.put(symbol, part); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 continue :ploop; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return .{ .sum = sum, .gears = gear_sum }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | test "silver" { | ||||||
|  |     const input = | ||||||
|  |         \\467..114.. | ||||||
|  |         \\...*...... | ||||||
|  |         \\..35..633. | ||||||
|  |         \\......#... | ||||||
|  |         \\617*...... | ||||||
|  |         \\.....+.58. | ||||||
|  |         \\..592..... | ||||||
|  |         \\......755. | ||||||
|  |         \\...$.*.... | ||||||
|  |         \\664..598.. | ||||||
|  |     ; | ||||||
|  |     try std.testing.expectEqual(@as(usize, 4361), (try solve(std.testing.allocator, input)).sum); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | test "gold" { | ||||||
|  |     const input = | ||||||
|  |         \\467..114.. | ||||||
|  |         \\...*...... | ||||||
|  |         \\..35..633. | ||||||
|  |         \\......#... | ||||||
|  |         \\617*...... | ||||||
|  |         \\.....+.58. | ||||||
|  |         \\..592..... | ||||||
|  |         \\......755. | ||||||
|  |         \\...$.*.... | ||||||
|  |         \\.664.598.. | ||||||
|  |     ; | ||||||
|  |     try std.testing.expectEqual(@as(usize, 467835), (try solve(std.testing.allocator, input)).gears); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user