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