diff options
Diffstat (limited to 'src/24/main.zig')
| -rw-r--r-- | src/24/main.zig | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/src/24/main.zig b/src/24/main.zig new file mode 100644 index 0000000..d32abfb --- /dev/null +++ b/src/24/main.zig @@ -0,0 +1,125 @@ +const std = @import("std"); +const aoc = @import("aoc"); + +const Color = enum { BLACK, WHITE }; +const Dir = enum { E, SE, SW, W, NW, NE }; +const dirs = [_]aoc.Pos{ + aoc.Pos{ .x = 2, .y = 0 }, + aoc.Pos{ .x = 1, .y = -1 }, + aoc.Pos{ .x = -1, .y = -1 }, + aoc.Pos{ .x = -2, .y = 0 }, + aoc.Pos{ .x = -1, .y = 1 }, + aoc.Pos{ .x = 1, .y = 1 }, +}; +const tokens = [_][]const u8{ + "e", + "se", + "sw", + "w", + "nw", + "ne", +}; +const Tile = struct { + color: Color, +}; + +fn parseInput(tiles: *std.AutoHashMap(aoc.Pos, Tile), input: []const u8) !void { + var lineit = std.mem.tokenize(u8, input, "\n"); + while (lineit.next()) |line| { + var pos = aoc.Pos{ .x = 0, .y = 0 }; + + var i: usize = 0; + while (i < line.len) { + var dir = for (tokens) |tok, ti| { + if (i + tok.len > line.len) continue; + if (std.mem.eql(u8, tok, line[i .. i + tok.len])) { + i += tok.len; + break @intToEnum(Dir, @intCast(u3, ti)); + } + } else return aoc.Error.InvalidInput; + if (aoc.debug) std.debug.print("{} ", .{dir}); + pos = pos.add(dirs[@enumToInt(dir)]); + } + if (aoc.debug) std.debug.print("=> {} {}\n", .{ pos.x, pos.y }); + + var tile = tiles.getEntry(pos); + if (tile != null) { + tile.?.value_ptr.color = if (tile.?.value_ptr.color == Color.WHITE) Color.BLACK else Color.WHITE; + } else { + try tiles.put(pos, Tile{ .color = Color.BLACK }); + } + } +} + +fn applyRule(pos: aoc.Pos, before: *std.AutoHashMap(aoc.Pos, Tile), after: *std.AutoHashMap(aoc.Pos, Tile)) !void { + if (after.contains(pos)) return; + const old_tile = before.get(pos); + const old_color = if (old_tile == null) Color.WHITE else old_tile.?.color; + + var adj: u32 = 0; + for (dirs) |d| { + const tile = before.get(pos.add(d)); + if (tile != null and tile.?.color == Color.BLACK) adj += 1; + } + + if (adj == 2 and old_color == Color.WHITE) { + try after.put(pos, Tile{ .color = Color.BLACK }); + } else if ((adj == 0 or adj > 2) and old_color == Color.BLACK) { + try after.put(pos, Tile{ .color = Color.WHITE }); + } else { + try after.put(pos, Tile{ .color = old_color }); + } +} + +fn doRound(allocator: std.mem.Allocator, tiles: *std.AutoHashMap(aoc.Pos, Tile)) !void { + var result = std.AutoHashMap(aoc.Pos, Tile).init(allocator); + defer result.deinit(); + + var mapit = tiles.iterator(); + while (mapit.next()) |kv| { + for (dirs) |d| { + try applyRule(kv.key_ptr.add(d), tiles, &result); + } + try applyRule(kv.key_ptr.*, tiles, &result); + } + + std.mem.swap(std.AutoHashMap(aoc.Pos, Tile), &result, tiles); +} + +fn countBlack(tiles: *std.AutoHashMap(aoc.Pos, Tile)) u32 { + var count: u32 = 0; + var mapit = tiles.iterator(); + while (mapit.next()) |kv| { + if (kv.value_ptr.color == Color.BLACK) count += 1; + } + return count; +} + +fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { + _ = args; + + var tiles = std.AutoHashMap(aoc.Pos, Tile).init(allocator); + defer tiles.deinit(); + + try parseInput(&tiles, input); + + return try std.fmt.allocPrint(allocator, "{}", .{countBlack(&tiles)}); +} + +fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { + _ = args; + + var tiles = std.AutoHashMap(aoc.Pos, Tile).init(allocator); + defer tiles.deinit(); + + try parseInput(&tiles, input); + + var round: usize = 0; + while (round < 100) : (round += 1) { + try doRound(allocator, &tiles); + } + + return try std.fmt.allocPrint(allocator, "{}", .{countBlack(&tiles)}); +} + +pub const main = aoc.main(part1, part2, .{ "317", "3804" }); |
