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 (5607B)


      1const std = @import("std");
      2const aoc = @import("aoc");
      3
      4const SeatState = enum { EMPTY, FLOOR, TAKEN };
      5const MapDims = struct { width: usize, height: usize };
      6const Dir = struct { x: i8, y: i8 };
      7const Pos = struct { x: i128, y: i128 };
      8
      9const adjacent = [_]Dir{
     10    Dir{ .x = -1, .y = -1 },
     11    Dir{ .x = -0, .y = -1 },
     12    Dir{ .x = 1, .y = -1 },
     13    Dir{ .x = -1, .y = 0 },
     14    Dir{ .x = 1, .y = 0 },
     15    Dir{ .x = -1, .y = 1 },
     16    Dir{ .x = 0, .y = 1 },
     17    Dir{ .x = 1, .y = 1 },
     18};
     19
     20fn parseMap(mapitems: *[]SeatState, dims: *MapDims, input: []const u8, allocator: std.mem.Allocator) !void {
     21    var lineit = std.mem.tokenize(u8, input, "\n");
     22    var map = std.ArrayList(SeatState).init(allocator);
     23    errdefer map.deinit();
     24    while (lineit.next()) |line| {
     25        if (dims.width == 0) {
     26            dims.width = line.len;
     27        } else if (dims.width != line.len) {
     28            return aoc.Error.InvalidInput;
     29        }
     30        for (line) |c| {
     31            try map.append(switch (c) {
     32                '#' => SeatState.TAKEN,
     33                'L' => SeatState.EMPTY,
     34                '.' => SeatState.FLOOR,
     35                else => {
     36                    return aoc.Error.InvalidInput;
     37                },
     38            });
     39        }
     40        dims.height += 1;
     41    }
     42    mapitems.* = map.toOwnedSlice();
     43}
     44
     45fn printMap(mapitems: []SeatState, dims: MapDims) void {
     46    for (mapitems) |state, i| {
     47        const c: u8 = switch (state) {
     48            SeatState.EMPTY => 'L',
     49            SeatState.TAKEN => '#',
     50            SeatState.FLOOR => '.',
     51        };
     52        if (i % dims.width == 0) {
     53            aoc.debugfmt("\n", .{});
     54        }
     55        aoc.debugfmt("{c}", .{c});
     56    }
     57}
     58
     59fn simulateStrategyOne(before: []SeatState, after: []SeatState, dims: MapDims) u32 {
     60    var seat_changes: u32 = 0;
     61    for (before) |state, i| {
     62        const p = Pos{ .x = i % dims.width, .y = i / dims.width };
     63        var count: u32 = 0;
     64        for (adjacent) |ap| {
     65            if (p.x + ap.x >= dims.width or p.x + ap.x < 0 or p.y + ap.y >= dims.height or p.y + ap.y < 0) continue;
     66            const ni = @intCast(u64, @intCast(i64, i) + ap.x + ap.y * @intCast(i64, dims.width));
     67            count += @boolToInt(before[ni] == SeatState.TAKEN);
     68        }
     69        if (state == SeatState.EMPTY and count == 0) {
     70            after[i] = SeatState.TAKEN;
     71            seat_changes += 1;
     72        } else if (state == SeatState.TAKEN and count >= 4) {
     73            after[i] = SeatState.EMPTY;
     74            seat_changes += 1;
     75        } else {
     76            after[i] = before[i];
     77        }
     78    }
     79    return seat_changes;
     80}
     81
     82fn simulateStrategyTwo(before: []SeatState, after: []SeatState, dims: MapDims) u32 {
     83    var seat_changes: u32 = 0;
     84    for (before) |state, i| {
     85        const p = Pos{ .x = i % dims.width, .y = i / dims.width };
     86        var count: u32 = 0;
     87        for (adjacent) |ap| {
     88            var iterp = Pos{ .x = p.x + ap.x, .y = p.y + ap.y };
     89            while (iterp.x < dims.width and iterp.x >= 0 and iterp.y < dims.height and iterp.y >= 0) {
     90                const ni = @intCast(u64, iterp.x + iterp.y * @intCast(i64, dims.width));
     91                if (before[ni] == SeatState.TAKEN) {
     92                    count += 1;
     93                    break;
     94                } else if (before[ni] == SeatState.EMPTY) {
     95                    break;
     96                } else {
     97                    iterp.x += ap.x;
     98                    iterp.y += ap.y;
     99                }
    100            }
    101        }
    102        if (state == SeatState.EMPTY and count == 0) {
    103            after[i] = SeatState.TAKEN;
    104            seat_changes += 1;
    105        } else if (state == SeatState.TAKEN and count >= 5) {
    106            after[i] = SeatState.EMPTY;
    107            seat_changes += 1;
    108        } else {
    109            after[i] = before[i];
    110        }
    111    }
    112    return seat_changes;
    113}
    114
    115fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
    116    _ = args;
    117
    118    var mapdims = MapDims{ .width = 0, .height = 0 };
    119    var mapitems: []SeatState = undefined;
    120    try parseMap(&mapitems, &mapdims, input, allocator);
    121    defer allocator.free(mapitems);
    122
    123    var mapresult = try allocator.alloc(SeatState, mapitems.len);
    124    defer allocator.free(mapresult);
    125
    126    var round: u32 = 0;
    127    while (simulateStrategyOne(mapitems, mapresult, mapdims) > 0) : (round += 1) {
    128        aoc.debugfmt("\rRound: {}", .{round});
    129        std.mem.copy(SeatState, mapitems, mapresult);
    130    }
    131
    132    var taken_count: u64 = 0;
    133    for (mapresult) |state| {
    134        taken_count += @boolToInt(state == SeatState.TAKEN);
    135    }
    136
    137    aoc.debugfmt("\nSeats Occupied: {}\n", .{taken_count});
    138
    139    return try std.fmt.allocPrint(allocator, "{d}", .{taken_count});
    140}
    141
    142fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
    143    _ = args;
    144
    145    var mapdims = MapDims{ .width = 0, .height = 0 };
    146    var mapitems: []SeatState = undefined;
    147    try parseMap(&mapitems, &mapdims, input, allocator);
    148    defer allocator.free(mapitems);
    149
    150    var mapresult = try allocator.alloc(SeatState, mapitems.len);
    151    defer allocator.free(mapresult);
    152
    153    var round: u32 = 0;
    154    while (simulateStrategyTwo(mapitems, mapresult, mapdims) > 0) : (round += 1) {
    155        aoc.debugfmt("\rRound: {}", .{round});
    156        std.mem.copy(SeatState, mapitems, mapresult);
    157    }
    158
    159    var taken_count: u64 = 0;
    160    for (mapresult) |state| {
    161        taken_count += @boolToInt(state == SeatState.TAKEN);
    162    }
    163
    164    aoc.debugfmt("\nSeats Occupied: {}\n", .{taken_count});
    165
    166    return try std.fmt.allocPrint(allocator, "{d}", .{taken_count});
    167}
    168
    169pub const main = aoc.main(part1, part2, .{ "2126", "1914" });