main.zig (3784B)
1const std = @import("std"); 2const aoc = @import("aoc"); 3 4const Color = enum { BLACK, WHITE }; 5const Dir = enum { E, SE, SW, W, NW, NE }; 6const dirs = [_]aoc.Pos{ 7 aoc.Pos{ .x = 2, .y = 0 }, 8 aoc.Pos{ .x = 1, .y = -1 }, 9 aoc.Pos{ .x = -1, .y = -1 }, 10 aoc.Pos{ .x = -2, .y = 0 }, 11 aoc.Pos{ .x = -1, .y = 1 }, 12 aoc.Pos{ .x = 1, .y = 1 }, 13}; 14const tokens = [_][]const u8{ 15 "e", 16 "se", 17 "sw", 18 "w", 19 "nw", 20 "ne", 21}; 22const Tile = struct { 23 color: Color, 24}; 25 26fn parseInput(tiles: *std.AutoHashMap(aoc.Pos, Tile), input: []const u8) !void { 27 var lineit = std.mem.tokenize(u8, input, "\n"); 28 while (lineit.next()) |line| { 29 var pos = aoc.Pos{ .x = 0, .y = 0 }; 30 31 var i: usize = 0; 32 while (i < line.len) { 33 var dir = for (tokens) |tok, ti| { 34 if (i + tok.len > line.len) continue; 35 if (std.mem.eql(u8, tok, line[i .. i + tok.len])) { 36 i += tok.len; 37 break @intToEnum(Dir, @intCast(u3, ti)); 38 } 39 } else return aoc.Error.InvalidInput; 40 if (aoc.debug) std.debug.print("{} ", .{dir}); 41 pos = pos.add(dirs[@enumToInt(dir)]); 42 } 43 if (aoc.debug) std.debug.print("=> {} {}\n", .{ pos.x, pos.y }); 44 45 var tile = tiles.getEntry(pos); 46 if (tile != null) { 47 tile.?.value_ptr.color = if (tile.?.value_ptr.color == Color.WHITE) Color.BLACK else Color.WHITE; 48 } else { 49 try tiles.put(pos, Tile{ .color = Color.BLACK }); 50 } 51 } 52} 53 54fn applyRule(pos: aoc.Pos, before: *std.AutoHashMap(aoc.Pos, Tile), after: *std.AutoHashMap(aoc.Pos, Tile)) !void { 55 if (after.contains(pos)) return; 56 const old_tile = before.get(pos); 57 const old_color = if (old_tile == null) Color.WHITE else old_tile.?.color; 58 59 var adj: u32 = 0; 60 for (dirs) |d| { 61 const tile = before.get(pos.add(d)); 62 if (tile != null and tile.?.color == Color.BLACK) adj += 1; 63 } 64 65 if (adj == 2 and old_color == Color.WHITE) { 66 try after.put(pos, Tile{ .color = Color.BLACK }); 67 } else if ((adj == 0 or adj > 2) and old_color == Color.BLACK) { 68 try after.put(pos, Tile{ .color = Color.WHITE }); 69 } else { 70 try after.put(pos, Tile{ .color = old_color }); 71 } 72} 73 74fn doRound(allocator: std.mem.Allocator, tiles: *std.AutoHashMap(aoc.Pos, Tile)) !void { 75 var result = std.AutoHashMap(aoc.Pos, Tile).init(allocator); 76 defer result.deinit(); 77 78 var mapit = tiles.iterator(); 79 while (mapit.next()) |kv| { 80 for (dirs) |d| { 81 try applyRule(kv.key_ptr.add(d), tiles, &result); 82 } 83 try applyRule(kv.key_ptr.*, tiles, &result); 84 } 85 86 std.mem.swap(std.AutoHashMap(aoc.Pos, Tile), &result, tiles); 87} 88 89fn countBlack(tiles: *std.AutoHashMap(aoc.Pos, Tile)) u32 { 90 var count: u32 = 0; 91 var mapit = tiles.iterator(); 92 while (mapit.next()) |kv| { 93 if (kv.value_ptr.color == Color.BLACK) count += 1; 94 } 95 return count; 96} 97 98fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 99 _ = args; 100 101 var tiles = std.AutoHashMap(aoc.Pos, Tile).init(allocator); 102 defer tiles.deinit(); 103 104 try parseInput(&tiles, input); 105 106 return try std.fmt.allocPrint(allocator, "{}", .{countBlack(&tiles)}); 107} 108 109fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 110 _ = args; 111 112 var tiles = std.AutoHashMap(aoc.Pos, Tile).init(allocator); 113 defer tiles.deinit(); 114 115 try parseInput(&tiles, input); 116 117 var round: usize = 0; 118 while (round < 100) : (round += 1) { 119 try doRound(allocator, &tiles); 120 } 121 122 return try std.fmt.allocPrint(allocator, "{}", .{countBlack(&tiles)}); 123} 124 125pub const main = aoc.main(part1, part2, .{ "317", "3804" });