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