main.zig (3218B)
1const std = @import("std"); 2const aoc = @import("aoc"); 3 4fn gcd(a: u64, b: u64) u64 { 5 var ac = a; 6 var bc = b; 7 while (true) { 8 if (ac > bc) { 9 ac = ac % bc; 10 if (ac == 0) return bc; 11 } else { 12 bc = bc % ac; 13 if (bc == 0) return ac; 14 } 15 } 16} 17 18fn lcm(a: u64, b: u64) u64 { 19 return @divExact(a * b, gcd(a, b)); 20} 21 22fn waittime(start: u32, busid: u32) u32 { 23 return (busid - (start % busid)) % busid; 24} 25 26fn printRegion(buses: []u32, start: u64, end: u64) void { 27 aoc.debugfmt(" ", .{}); 28 for (buses) |bus| { 29 aoc.debugfmt(" {:^5}", .{bus}); 30 } 31 aoc.debugfmt("\n", .{}); 32 33 var i = start; 34 while (i < end) : (i += 1) { 35 aoc.debugfmt("{:<10}", .{i}); 36 for (buses) |bus| { 37 var c: u8 = '.'; 38 if (bus > 0 and i % bus == 0) c = 'D'; 39 aoc.debugfmt(" {c} ", .{c}); 40 } 41 aoc.debugfmt("\n", .{}); 42 } 43 aoc.debugfmt("\n", .{}); 44} 45 46fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 47 _ = args; 48 49 var lineit = std.mem.tokenize(u8, input, "\n"); 50 var start = try std.fmt.parseInt(u32, lineit.next().?, 10); 51 52 var bestbus: ?u32 = null; 53 var busit = std.mem.tokenize(u8, lineit.next().?, ","); 54 while (busit.next()) |bus| { 55 if (bus[0] == 'x') continue; 56 const val = try std.fmt.parseInt(u32, bus, 10); 57 if (bestbus == null or waittime(start, val) < waittime(start, bestbus.?)) { 58 bestbus = val; 59 } 60 } 61 62 const answer = bestbus.? * waittime(start, bestbus.?); 63 64 return try std.fmt.allocPrint(allocator, "{d}", .{answer}); 65} 66 67fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 68 _ = args; 69 70 var lineit = std.mem.tokenize(u8, input, "\n"); 71 _ = try std.fmt.parseInt(u32, lineit.next().?, 10); 72 73 var busses = std.ArrayList(u32).init(allocator); 74 defer busses.deinit(); 75 76 var busit = std.mem.tokenize(u8, lineit.next().?, ","); 77 78 const first = try std.fmt.parseInt(u32, busit.next().?, 10); 79 try busses.append(first); 80 81 var offset: u64 = 0; 82 var cycle: u64 = first; 83 var delay: u32 = 1; 84 while (busit.next()) |bus| : (delay += 1) { 85 if (bus[0] == 'x') { 86 try busses.append(0); 87 continue; 88 } 89 const val = try std.fmt.parseInt(u32, bus, 10); 90 try busses.append(val); 91 92 var mult: u64 = @divFloor(offset + delay, val); 93 if ((offset + delay) % val != 0) mult += 1; 94 while ((mult * val - offset - delay) % cycle != 0) { 95 mult += std.math.max(1, @divFloor(cycle - (mult * val - offset - delay) % cycle, val)); 96 } 97 offset = mult * val - delay; 98 99 cycle = lcm(cycle, val); 100 if (aoc.debug) { 101 printRegion(busses.items, offset, offset + delay + 1); 102 printRegion(busses.items, offset + cycle, offset + cycle + delay + 1); 103 aoc.debugfmt("{}\n", .{offset}); 104 } 105 } 106 107 printRegion(busses.items, offset, offset + busses.items.len); 108 109 return try std.fmt.allocPrint(allocator, "{}", .{offset}); 110} 111 112pub const main = aoc.main(part1, part2, .{ "6568", "554865447501099" });