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