aoc-2020-zig

Advent of Code 2020 Solutions in Zig
git clone https://git.sinitax.com/sinitax/aoc-2020-zig
Log | Files | Refs | README | sfeed.txt

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" });