aboutsummaryrefslogtreecommitdiffstats
path: root/src/24/main.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/24/main.zig')
-rw-r--r--src/24/main.zig125
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" });