advent-of-code

Solutions for Advent of Code.
git clone git://git.amin.space/advent-of-code.git
Log | Files | Refs | LICENSE

day_11.zig (8027B)


      1 const std = @import("std");
      2 const debug = std.debug;
      3 const mem = std.mem;
      4 
      5 const grid_serial_number: u32 = 5791;
      6 const grid_side_len = 300;
      7 
      8 pub fn main() void {
      9     const result1 = regionOfHighestTotalPower(grid_serial_number);
     10     debug.assert(V2.eq(V2.init(20, 68), result1));
     11     debug.warn("11-1: {}\n", result1);
     12 
     13     const result2 = regionOfHighestTotalPowerOfAnySize(grid_serial_number);
     14     debug.assert(V2.eq(V2.init(231, 273), result2.region));
     15     debug.assert(16 == result2.square_side_len);
     16     debug.warn("11-2: {},{}\n", result2.region, result2.square_side_len);
     17 }
     18 
     19 fn regionOfHighestTotalPowerOfAnySize(gsn: u32) RegionInfo {
     20     var grid = []i32{0} ** (grid_side_len * grid_side_len);
     21 
     22     for (grid) |*cell, i| {
     23         var coord = point_from_index(i, grid_side_len);
     24 
     25         // grid is 1 based, though array is 0 based
     26         cell.* = getFuelCellPower(coord.x + 1, coord.y + 1, gsn);
     27     }
     28     // https://en.wikipedia.org/wiki/Summed-area_table
     29     var sat = []i32{0} ** grid.len;
     30     for (grid) |cell, i| {
     31         const c = point_from_index(i, grid_side_len);
     32 
     33         sat[i] = grid[index_from_point(c.x, c.y, grid_side_len)];
     34 
     35         if (c.x > 0) {
     36             sat[i] += sat[index_from_point(c.x - 1, c.y, grid_side_len)];
     37         }
     38         if (c.y > 0) {
     39             sat[i] += sat[index_from_point(c.x, c.y - 1, grid_side_len)];
     40         }
     41         if (c.x > 0 and c.y > 0) {
     42             sat[i] -= sat[index_from_point(c.x - 1, c.y - 1, grid_side_len)];
     43         }
     44     }
     45 
     46     var highest_highest_power: i32 = grid[0];
     47     var highest_highest_power_region = V2.init(0, 0);
     48     var highest_square_side_len: u32 = 1;
     49 
     50     var square_side_len: u32 = 1;
     51     while (square_side_len <= grid_side_len) : (square_side_len += 1) {
     52         var highest_power: i32 = @minValue(i32);
     53         var highest_power_region = V2.init(1, 1);
     54 
     55         for (grid) |cell, i| {
     56             const array_coord = point_from_index(i, grid_side_len);
     57 
     58             // cells start at (1, 1)
     59             const cell_coord = V2.init(array_coord.x + 1, array_coord.y + 1);
     60 
     61             const search_threshold = (grid_side_len - square_side_len) + 1;
     62             if (cell_coord.x > search_threshold or cell_coord.y > search_threshold) {
     63                 continue;
     64             }
     65 
     66             const ssl = square_side_len - 1;
     67 
     68             // +----------------------+
     69             // |      |           |   |
     70             // |     A|          B|   |
     71             // |------+-----------+   |
     72             // |      |           |   |
     73             // |      |           |   |
     74             // |      |           |   |
     75             // |     C|          D|   |
     76             // |------+-----------+   |
     77             // |                      |
     78             // +----------------------+
     79             // sum = D - B - C + A
     80 
     81             // D
     82             var sum: i32 = sat[index_from_point(array_coord.x + ssl, array_coord.y + ssl, grid_side_len)];
     83 
     84             if (array_coord.x > 0) {
     85                 // - C
     86                 sum -= sat[index_from_point(array_coord.x - 1, array_coord.y + ssl, grid_side_len)];
     87             }
     88             if (array_coord.y > 0) {
     89                 // - B
     90                 sum -= sat[index_from_point(array_coord.x + ssl, array_coord.y - 1, grid_side_len)];
     91             }
     92             if (array_coord.x > 0 and array_coord.y > 0) {
     93                 // + A
     94                 sum += sat[index_from_point(array_coord.x - 1, array_coord.y - 1, grid_side_len)];
     95             }
     96 
     97             if (sum > highest_power) {
     98                 highest_power = sum;
     99                 highest_power_region = cell_coord;
    100             }
    101         }
    102 
    103         if (highest_power > highest_highest_power) {
    104             highest_highest_power = highest_power;
    105             highest_highest_power_region = highest_power_region;
    106             highest_square_side_len = square_side_len;
    107         }
    108     }
    109 
    110     return RegionInfo {
    111         .region = highest_highest_power_region,
    112         .square_side_len = highest_square_side_len,
    113     };
    114 }
    115 
    116 const RegionInfo = struct {
    117     region: V2,
    118     square_side_len: u32,
    119 };
    120 
    121 test "region of highest total power of any size" {
    122     const r18 = regionOfHighestTotalPowerOfAnySize(18);
    123     debug.assert(V2.eq(V2.init(90, 269), r18.region));
    124     debug.assert(16 == r18.square_side_len);
    125 
    126     const r42 = regionOfHighestTotalPowerOfAnySize(42);
    127     debug.assert(V2.eq(V2.init(232, 251), r42.region));
    128     debug.assert(12 == r42.square_side_len);
    129 }
    130 
    131 fn regionOfHighestTotalPower(gsn: u32) V2{
    132     var grid = []i32{0} ** (grid_side_len * grid_side_len);
    133 
    134     for (grid) |*cell, i| {
    135         var coord = point_from_index(i, grid_side_len);
    136 
    137         // grid is 1 based, though array is 0 based
    138         coord.x += 1;
    139         coord.y += 1;
    140 
    141         cell.* = getFuelCellPower(coord.x, coord.y, gsn);
    142     }
    143 
    144     var square_side_len: u32 = 3;
    145     var highest_power: i32 = 0;
    146     var highest_power_region = V2.init(1, 1);
    147 
    148     for (grid) |cell, i| {
    149         const array_coord = point_from_index(i, grid_side_len);
    150         const cell_coord = V2.init(array_coord.x + 1, array_coord.y + 1);
    151 
    152         const search_threshold = grid_side_len - square_side_len;
    153         if (cell_coord.x >= search_threshold or cell_coord.y >= search_threshold) {
    154             continue;
    155         }
    156 
    157         var sum: i32 = 0;
    158         var square_x: u32 = 0;
    159         while (square_x < square_side_len) : (square_x += 1) {
    160             var square_y: u32 = 0;
    161             while (square_y < square_side_len) : (square_y += 1) {
    162                 sum += grid[index_from_point(array_coord.x + square_x, array_coord.y + square_y, grid_side_len)];
    163             }
    164         }
    165 
    166         if (sum > highest_power) {
    167             highest_power = sum;
    168             highest_power_region = cell_coord;
    169         }
    170     }
    171     return highest_power_region;
    172 }
    173 
    174 test "region of highest total power" {
    175     debug.assert(V2.eq(V2.init(33, 45), regionOfHighestTotalPower(18)));
    176     debug.assert(V2.eq(V2.init(21, 61), regionOfHighestTotalPower(42)));
    177 }
    178 
    179 fn getFuelCellPower(cell_x: u32, cell_y: u32, gsn: u32) i32 {
    180     const rack_id = cell_x + 10;
    181     var power_level: i32 = @intCast(i32, rack_id * cell_y);
    182     power_level += @intCast(i32, gsn);
    183     power_level *= @intCast(i32, rack_id);
    184     power_level = hundredsDigit(power_level);
    185     power_level -= 5;
    186     return power_level;
    187 }
    188 
    189 test "get fuel cell power" {
    190     debug.assert(4 == getFuelCellPower(3, 5, 8));
    191     debug.assert(-5 == getFuelCellPower(122, 79, 57));
    192     debug.assert(0 == getFuelCellPower(217, 196, 39));
    193     debug.assert(4 == getFuelCellPower(101, 153, 71));
    194 }
    195 
    196 inline fn hundredsDigit(n: i32) i32 {
    197     return @mod(@divTrunc(n, 100), 10);
    198 }
    199 
    200 test "hundreds digit" {
    201     debug.assert(0 == hundredsDigit(0));
    202     debug.assert(0 == hundredsDigit(10));
    203     debug.assert(1 == hundredsDigit(100));
    204     debug.assert(0 == hundredsDigit(1000));
    205     debug.assert(3 == hundredsDigit(12345));
    206 }
    207 
    208 fn point_from_index(i: usize, stride: usize) V2 {
    209     var x: u32 = @intCast(u32, i % stride);
    210     var y: u32 = @intCast(u32, @divTrunc(i, stride));
    211     return V2.init(x, y);
    212 }
    213 
    214 test "point from index" {
    215     debug.assert(V2.eq(V2.init(0, 0), point_from_index(0, 5)));
    216     debug.assert(V2.eq(V2.init(1, 1), point_from_index(6, 5)));
    217     debug.assert(V2.eq(V2.init(2, 1), point_from_index(7, 5)));
    218     debug.assert(V2.eq(V2.init(4, 2), point_from_index(14, 5)));
    219     debug.assert(V2.eq(V2.init(4, 4), point_from_index(24, 5)));
    220 }
    221 
    222 inline fn index_from_point(x: u32, y: u32, stride: usize) usize {
    223     return y * stride + x;
    224 }
    225 
    226 test "index from point" {
    227     debug.assert(0 == index_from_point(0, 0, 5));
    228     debug.assert(6 == index_from_point(1, 1, 5));
    229     debug.assert(7 == index_from_point(2, 1, 5));
    230     debug.assert(14 == index_from_point(4, 2, 5));
    231     debug.assert(24 == index_from_point(4, 4, 5));
    232 }
    233 
    234 const V2 = struct {
    235     x: u32,
    236     y: u32,
    237 
    238     pub fn init(x: u32, y: u32) V2 {
    239         return V2 {
    240             .x = x,
    241             .y = y,
    242         };
    243     }
    244 
    245     pub fn eq(vec1: V2, vec2: V2) bool {
    246         return vec1.x == vec2.x and vec1.y == vec2.y;
    247     }
    248 };