adventofcode

git clone https://git.ce9e.org/adventofcode.git

commit
fa87a81b2c714d0d9eb99132531cacc174815c74
parent
f80c19893b91751bcf41bc558da0f9a8bd9f6814
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2021-12-22 08:17
refactor and optimize

Diffstat

M 2021/22/part2.rs 165 +++++++++++++++++++++++++++++++++----------------------------

1 files changed, 89 insertions, 76 deletions


diff --git a/2021/22/part2.rs b/2021/22/part2.rs

@@ -3,7 +3,6 @@ use std::fs::File;
    3     3 use std::io::BufRead;
    4     4 use std::io::BufReader;
    5     5 
    6    -1 #[derive(Copy, Clone)]
    7     6 struct Area {
    8     7     x1: i64,
    9     8     x2: i64,
@@ -13,64 +12,79 @@ struct Area {
   13    12     z2: i64,
   14    13 }
   15    14 
   16    -1 fn get_ranges(s: &str) -> Area {
   17    -1     let parsed = s
   18    -1         .split(",")
   19    -1         .map(|r| match r[2..]
   20    -1             .split("..")
   21    -1             .collect::<Vec<&str>>()[..] {
   22    -1                 [left, right] => (
   23    -1                     left.parse::<i64>().unwrap(),
   24    -1                     right.parse::<i64>().unwrap(),
   25    -1                 ),
   26    -1                 _ => unreachable!(),
   27    -1             }
   28    -1         )
   29    -1         .collect::<Vec<(i64, i64)>>();
   30    -1 
   31    -1     return match parsed[..] {
   32    -1         [x, y, z] => Area {
   33    -1             x1: x.0,
   34    -1             x2: x.1,
   35    -1             y1: y.0,
   36    -1             y2: y.1,
   37    -1             z1: z.0,
   38    -1             z2: z.1,
   39    -1         },
   40    -1         _ => unreachable!(),
   41    -1     };
   42    -1 }
   -1    15 impl Area {
   -1    16     fn parse(s: &str) -> Self {
   -1    17         let parsed = s
   -1    18             .split(",")
   -1    19             .map(|r| match r[2..]
   -1    20                 .split("..")
   -1    21                 .collect::<Vec<&str>>()[..] {
   -1    22                     [left, right] => (
   -1    23                         left.parse::<i64>().unwrap(),
   -1    24                         right.parse::<i64>().unwrap(),
   -1    25                     ),
   -1    26                     _ => unreachable!(),
   -1    27                 }
   -1    28             )
   -1    29             .collect::<Vec<(i64, i64)>>();
   43    30 
   44    -1 fn area_difference(a: Area, b: Area) -> Vec<Area> {
   45    -1     let mut shards = vec![];
   -1    31         return match parsed[..] {
   -1    32             [x, y, z] => Self {
   -1    33                 x1: x.0,
   -1    34                 x2: x.1,
   -1    35                 y1: y.0,
   -1    36                 y2: y.1,
   -1    37                 z1: z.0,
   -1    38                 z2: z.1,
   -1    39             },
   -1    40             _ => unreachable!(),
   -1    41         };
   -1    42     }
   46    43 
   47    -1     let x1 = if a.x1 > b.x1 {a.x1} else {b.x1};
   48    -1     let x2 = if a.x2 < b.x2 {a.x2} else {b.x2};
   49    -1     let y1 = if a.y1 > b.y1 {a.y1} else {b.y1};
   50    -1     let y2 = if a.y2 < b.y2 {a.y2} else {b.y2};
   51    -1     let z1 = if a.z1 > b.z1 {a.z1} else {b.z1};
   52    -1     let z2 = if a.z2 < b.z2 {a.z2} else {b.z2};
   -1    44     fn diff(&self, other: &Self) -> Vec<Self> {
   -1    45         // break down self into shards that do not overlap with other
   -1    46         let mut shards = vec![];
   53    47 
   54    -1     if a.x1 <= x1 - 1 {
   55    -1         shards.push(Area { x1: a.x1,   x2: x1 - 1, y1: a.y1,   y2: a.y2,   z1: a.z1,   z2: a.z2   });
   56    -1     }
   57    -1     if a.y1 <= y1 - 1 {
   58    -1         shards.push(Area { x1: x1,     x2: x2,     y1: a.y1,   y2: y1 - 1, z1: a.z1,   z2: a.z2   });
   59    -1     }
   60    -1     if a.z1 <= z1 - 1 {
   61    -1         shards.push(Area { x1: x1,     x2: x2,     y1: y1,     y2: y2,     z1: a.z1,   z2: z1 - 1 });
   62    -1     }
   63    -1     if z2 + 1 <= a.z2 {
   64    -1         shards.push(Area { x1: x1,     x2: x2,     y1: y1,     y2: y2,     z1: z2 + 1, z2: a.z2   });
   65    -1     }
   66    -1     if y2 + 1 <= a.y2 {
   67    -1         shards.push(Area { x1: x1,     x2: x2,     y1: y2 + 1, y2: a.y2,   z1: a.z1,   z2: a.z2   });
   -1    48         let x1 = if self.x1 > other.x1 {self.x1} else {other.x1};
   -1    49         let x2 = if self.x2 < other.x2 {self.x2} else {other.x2};
   -1    50         let y1 = if self.y1 > other.y1 {self.y1} else {other.y1};
   -1    51         let y2 = if self.y2 < other.y2 {self.y2} else {other.y2};
   -1    52         let z1 = if self.z1 > other.z1 {self.z1} else {other.z1};
   -1    53         let z2 = if self.z2 < other.z2 {self.z2} else {other.z2};
   -1    54 
   -1    55         if self.x1 < x1 {
   -1    56             shards.push(Area { x1: self.x1, x2: x1 - 1, y1: self.y1, y2: self.y2, z1: self.z1, z2: self.z2 });
   -1    57         }
   -1    58         if self.y1 < y1 {
   -1    59             shards.push(Area { x1, x2, y1: self.y1, y2: y1 - 1, z1: self.z1, z2: self.z2 });
   -1    60         }
   -1    61         if self.z1 < z1 {
   -1    62             shards.push(Area { x1, x2, y1, y2, z1: self.z1, z2: z1 - 1 });
   -1    63         }
   -1    64         if z2 < self.z2 {
   -1    65             shards.push(Area { x1, x2, y1, y2, z1: z2 + 1, z2: self.z2 });
   -1    66         }
   -1    67         if y2 < self.y2 {
   -1    68             shards.push(Area { x1, x2, y1: y2 + 1, y2: self.y2, z1: self.z1, z2: self.z2 });
   -1    69         }
   -1    70         if x2 < self.x2 {
   -1    71             shards.push(Area { x1: x2 + 1, x2: self.x2, y1: self.y1, y2: self.y2, z1: self.z1, z2: self.z2 });
   -1    72         }
   -1    73 
   -1    74         return shards;
   68    75     }
   69    -1     if x2 + 1 <= a.x2 {
   70    -1         shards.push(Area { x1: x2 + 1, x2: a.x2,   y1: a.y1,   y2: a.y2,   z1: a.z1,   z2: a.z2   });
   -1    76 
   -1    77     fn overlap(&self, other: &Self) -> bool {
   -1    78         return self.x1 <= other.x2 && other.x1 <= self.x2
   -1    79             && self.y1 <= other.y2 && other.y1 <= self.y2
   -1    80             && self.z1 <= other.z2 && other.z1 <= self.z2;
   71    81     }
   72    82 
   73    -1     return shards;
   -1    83     fn count(&self) -> i64 {
   -1    84         return (self.x2 - self.x1 + 1)
   -1    85             * (self.y2 - self.y1 + 1)
   -1    86             * (self.z2 - self.z1 + 1);
   -1    87     }
   74    88 }
   75    89 
   76    90 fn add_area(area: Area, mut areas: &mut Vec<Area>) {
@@ -80,16 +94,25 @@ fn add_area(area: Area, mut areas: &mut Vec<Area>) {
   80    94 
   81    95     let mut i = 0;
   82    96     while i < areas.len() {
   83    -1         let other = areas[i];
   84    -1         if area.x1 <= other.x2 && other.x1 <= area.x2
   85    -1             && area.y1 <= other.y2 && other.y1 <= area.y2
   86    -1             && area.z1 <= other.z2 && other.z1 <= area.z2 {
   87    -1             for shard in area_difference(area, other) {
   88    -1                 add_area(shard, &mut areas);
   -1    97         let other = &areas[i];
   -1    98         if area.overlap(other) {
   -1    99             let shards1 = area.diff(other);
   -1   100             let shards2 = other.diff(&area);
   -1   101             // PERF: optimize for a smaller areas.len()
   -1   102             if shards1.len() < shards2.len() {
   -1   103                 for shard in shards1 {
   -1   104                     add_area(shard, &mut areas);
   -1   105                 }
   -1   106                 return;
   -1   107             } else {
   -1   108                 areas.remove(i);
   -1   109                 for shard in shards2 {
   -1   110                     areas.push(shard);
   -1   111                 }
   89   112             }
   90    -1             return;
   -1   113         } else {
   -1   114             i += 1;
   91   115         }
   92    -1         i += 1;
   93   116     }
   94   117     areas.push(area);
   95   118 }
@@ -97,12 +120,9 @@ fn add_area(area: Area, mut areas: &mut Vec<Area>) {
   97   120 fn remove_area(area: Area, areas: &mut Vec<Area>) {
   98   121     let mut i = 0;
   99   122     while i < areas.len() {
  100    -1         let other = areas[i];
  101    -1         if area.x1 <= other.x2 && other.x1 <= area.x2
  102    -1             && area.y1 <= other.y2 && other.y1 <= area.y2
  103    -1             && area.z1 <= other.z2 && other.z1 <= area.z2 {
  104    -1             areas.remove(i);
  105    -1             for shard in area_difference(other, area) {
   -1   123         if area.overlap(&areas[i]) {
   -1   124             let other = areas.remove(i);
   -1   125             for shard in other.diff(&area) {
  106   126                 areas.push(shard);
  107   127             }
  108   128         } else {
@@ -111,13 +131,6 @@ fn remove_area(area: Area, areas: &mut Vec<Area>) {
  111   131     }
  112   132 }
  113   133 
  114    -1 fn count(areas: &Vec<Area>) -> i64 {
  115    -1     return areas
  116    -1         .iter()
  117    -1         .map(|area| (area.x2 - area.x1 + 1) * (area.y2 - area.y1 + 1) * (area.z2 - area.z1 + 1))
  118    -1         .sum();
  119    -1 }
  120    -1 
  121   134 fn main() {
  122   135     let path = args().nth(1).unwrap();
  123   136     let file = File::open(path).unwrap();
@@ -128,7 +141,7 @@ fn main() {
  128   141         match line.unwrap().split(" ").collect::<Vec<&str>>()[..] {
  129   142             [a, b] => {
  130   143                 let on = a == "on";
  131    -1                 let area = get_ranges(b);
   -1   144                 let area = Area::parse(b);
  132   145                 if on {
  133   146                     add_area(area, &mut areas);
  134   147                 } else {
@@ -139,5 +152,5 @@ fn main() {
  139   152         }
  140   153     }
  141   154 
  142    -1     println!("{}", count(&areas));
   -1   155     println!("{}", areas.iter().map(|area| area.count()).sum::<i64>());
  143   156 }