main.zig (6238B)
1const std = @import("std"); 2const aoc = @import("aoc"); 3 4fn PosVec(comptime N: u32) type { 5 return struct { data: [N]i64 }; 6} 7 8const Active = bool; 9 10fn forNeighbors(comptime dims: u32, map: *std.AutoHashMap(PosVec(dims), Active), p: PosVec(dims), data: anytype, func: fn (map: *std.AutoHashMap(PosVec(dims), Active), p: PosVec(dims), d: @TypeOf(data)) anyerror!void) !void { 11 var i: u32 = 0; 12 while (i < comptime std.math.pow(u32, 3, dims)) : (i += 1) { 13 var np: PosVec(dims) = undefined; 14 var d: u32 = 0; 15 var skip = true; 16 while (d < dims) : (d += 1) { 17 const offset = (i / std.math.pow(u32, 3, d)) % 3; 18 np.data[d] = p.data[d] + @intCast(i64, offset) - 1; 19 if (skip and offset != 1) skip = false; 20 } 21 if (skip) continue; 22 try func(map, np, data); 23 } 24} 25 26fn posStr(comptime dims: u32, p: PosVec(dims)) void { 27 var d: u32 = 0; 28 while (d < dims) : (d += 1) { 29 aoc.debugfmt("{} ", .{p.data[d]}); 30 } 31} 32 33fn countActive(comptime dims: u32) fn (map: *std.AutoHashMap(PosVec(dims), Active), p: PosVec(dims), d: *u32) anyerror!void { 34 const impl = struct { 35 fn func(map: *std.AutoHashMap(PosVec(dims), Active), p: PosVec(dims), d: *u32) anyerror!void { 36 d.* += @boolToInt(map.get(p) != null); 37 } 38 }; 39 return impl.func; 40} 41 42fn addNew(comptime dims: u32) fn (oldmap: *std.AutoHashMap(PosVec(dims), Active), p: PosVec(dims), newmap: *std.AutoHashMap(PosVec(dims), Active)) anyerror!void { 43 const impl = struct { 44 fn func(oldmap: *std.AutoHashMap(PosVec(dims), Active), p: PosVec(dims), newmap: *std.AutoHashMap(PosVec(dims), Active)) anyerror!void { 45 if (newmap.get(p) != null) return; 46 47 var v = oldmap.get(p); 48 var state = (v != null); 49 50 var count: u32 = 0; 51 try forNeighbors(dims, oldmap, p, &count, countActive(dims)); 52 if (state and count >= 2 and count <= 3 or !state and count == 3) { 53 try newmap.put(p, true); 54 } 55 } 56 }; 57 return impl.func; 58} 59 60fn simulateRound(comptime dims: u32, map: *std.AutoHashMap(PosVec(dims), Active), allocator: std.mem.Allocator) !void { 61 var newmap = std.AutoHashMap(PosVec(dims), Active).init(allocator); 62 errdefer newmap.deinit(); 63 64 var mapit = map.iterator(); 65 while (mapit.next()) |kv| { 66 try forNeighbors(dims, map, kv.key_ptr.*, &newmap, addNew(dims)); 67 try addNew(dims)(map, kv.key_ptr.*, &newmap); 68 } 69 70 std.mem.swap(std.AutoHashMap(PosVec(dims), Active), map, &newmap); 71 newmap.deinit(); 72} 73 74fn sliceProduct(data: []i64) i64 { 75 var product: i64 = 1; 76 for (data) |v| { 77 product *= v; 78 } 79 return product; 80} 81 82fn printMap(comptime dims: u32, map: *std.AutoHashMap(PosVec(dims), Active)) void { 83 var min: ?PosVec(dims) = null; 84 var max: ?PosVec(dims) = null; 85 86 var mapit = map.iterator(); 87 while (mapit.next()) |kv| { 88 if (min == null) min = kv.key_ptr.*; 89 if (max == null) max = kv.key_ptr.*; 90 91 var d: u32 = 0; 92 while (d < dims) : (d += 1) { 93 if (min.?.data[d] > kv.key_ptr.data[d]) min.?.data[d] = kv.key_ptr.data[d]; 94 if (max.?.data[d] < kv.key_ptr.data[d]) max.?.data[d] = kv.key_ptr.data[d]; 95 } 96 } 97 98 if (min == null or max == null) return; 99 100 var space: PosVec(dims) = undefined; 101 { 102 var d: u32 = 0; 103 while (d < dims) : (d += 1) { 104 space.data[d] = max.?.data[d] - min.?.data[d]; 105 } 106 } 107 108 var i: usize = 0; 109 while (i < sliceProduct(space.data[0..])) : (i += @intCast(usize, space.data[0] * space.data[1])) { 110 var np: PosVec(dims) = undefined; 111 var d: u32 = 0; 112 while (d < dims) : (d += 1) { 113 np.data[d] = min.?.data[d] + @mod(@divFloor(@intCast(i64, i), sliceProduct(space.data[0..d])), space.data[d]); 114 } 115 116 d = 2; 117 aoc.debugfmt("Slice at: ", .{}); 118 while (d < dims) : (d += 1) { 119 if (d > 2) aoc.debugfmt(",", .{}); 120 aoc.debugfmt("{}.Dim = {} ", .{ d + 1, np.data[d] }); 121 } 122 aoc.debugfmt("\n", .{}); 123 124 var y = min.?.data[1]; 125 while (y <= max.?.data[1]) : (y += 1) { 126 var x = min.?.data[0]; 127 while (x <= max.?.data[0]) : (x += 1) { 128 var v = np; 129 v.data[0] = x; 130 v.data[1] = y; 131 var c: u8 = '.'; 132 if (map.get(v) != null) c = '#'; 133 aoc.debugfmt("{c}", .{c}); 134 } 135 aoc.debugfmt("\n", .{}); 136 } 137 aoc.debugfmt("\n", .{}); 138 } 139} 140 141fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 142 _ = args; 143 144 var map = std.AutoHashMap(PosVec(3), Active).init(allocator); 145 defer map.deinit(); 146 147 var lineit = std.mem.tokenize(u8, input, "\n"); 148 var y: i64 = 0; 149 while (lineit.next()) |line| : (y += 1) { 150 for (line) |c, x| { 151 if (c != '#') continue; 152 try map.put(PosVec(3){ .data = [_]i64{ @intCast(i64, x), y, 0 } }, true); 153 } 154 } 155 156 var i: usize = 0; 157 while (i < 6) : (i += 1) { 158 try simulateRound(3, &map, allocator); 159 if (aoc.debug) { 160 aoc.debugfmt("AFTER ROUND {}:\n", .{i + 1}); 161 printMap(3, &map); 162 } 163 } 164 165 return try std.fmt.allocPrint(allocator, "{}", .{map.count()}); 166} 167 168fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 169 _ = args; 170 171 var map = std.AutoHashMap(PosVec(4), Active).init(allocator); 172 defer map.deinit(); 173 174 var lineit = std.mem.tokenize(u8, input, "\n"); 175 var y: i64 = 0; 176 while (lineit.next()) |line| : (y += 1) { 177 for (line) |c, x| { 178 if (c != '#') continue; 179 try map.put(PosVec(4){ .data = [_]i64{ @intCast(i64, x), y, 0, 0 } }, true); 180 } 181 } 182 183 var i: usize = 0; 184 while (i < 6) : (i += 1) { 185 try simulateRound(4, &map, allocator); 186 if (aoc.debug) { 187 aoc.debugfmt("AFTER ROUND {}:\n", .{i + 1}); 188 printMap(4, &map); 189 } 190 } 191 192 return try std.fmt.allocPrint(allocator, "{}", .{map.count()}); 193} 194 195pub const main = aoc.main(part1, part2, .{ "304", "1868" });