adventofcode

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

commit
df2f786f3fe1f9a876a988ffc74e03554d533983
parent
5b610ea9470197e4aefa6c18b9984f143f9a2e53
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2022-12-17 12:54
2022-12-17 part2

Diffstat

M 2022/17/solution.rs 110 +++++++++++++++++++++++++++++++++++++++++--------------------

1 files changed, 75 insertions, 35 deletions


diff --git a/2022/17/solution.rs b/2022/17/solution.rs

@@ -1,21 +1,33 @@
    1     1 use std::collections::HashSet;
   -1     2 use std::collections::HashMap;
   -1     3 use std::convert::TryInto;
    2     4 
    3     5 #[path = "../lib.rs"] mod lib;
    4     6 
   -1     7 const WIDTH: usize = 7;
   -1     8 
    5     9 struct Shape {
    6    -1     blocks: HashSet<(i64, i64)>,
    7    -1     bottom: HashSet<(i64, i64)>,
    8    -1     left: HashSet<(i64, i64)>,
    9    -1     right: HashSet<(i64, i64)>,
   10    -1     width: i64,
   11    -1     height: i64,
   -1    10     blocks: HashSet<(usize, usize)>,
   -1    11     bottom: HashSet<(usize, usize)>,
   -1    12     left: HashSet<(usize, usize)>,
   -1    13     right: HashSet<(usize, usize)>,
   -1    14     width: usize,
   -1    15     height: usize,
   -1    16 }
   -1    17 
   -1    18 #[derive(Hash, PartialEq, Eq)]
   -1    19 struct CacheKey {
   -1    20     move_i: usize,
   -1    21     shape_i: usize,
   -1    22     // not sure if 4 rows are enough to capture this, but hope it works, but at least its very probable
   -1    23     top_rows: [[bool; WIDTH]; 4],
   12    24 }
   13    25 
   14    -1 fn make_shape(blocks: Vec<(i64, i64)>) -> Shape {
   -1    26 fn make_shape(blocks: Vec<(usize, usize)>) -> Shape {
   15    27     return Shape {
   16    28         blocks: blocks.iter().map(|(x, y)| (*x, *y)).collect(),
   17    -1         bottom: blocks.iter().filter(|(x, y)| !blocks.contains(&(*x, *y - 1))).map(|(x, y)| (*x, *y)).collect(),
   18    -1         left: blocks.iter().filter(|(x, y)| !blocks.contains(&(*x - 1, *y))).map(|(x, y)| (*x, *y)).collect(),
   -1    29         bottom: blocks.iter().filter(|(x, y)| *y == 0 || !blocks.contains(&(*x, *y - 1))).map(|(x, y)| (*x, *y)).collect(),
   -1    30         left: blocks.iter().filter(|(x, y)| *x == 0 || !blocks.contains(&(*x - 1, *y))).map(|(x, y)| (*x, *y)).collect(),
   19    31         right: blocks.iter().filter(|(x, y)| !blocks.contains(&(*x + 1, *y))).map(|(x, y)| (*x, *y)).collect(),
   20    32         width: blocks.iter().map(|(x, _)| *x).max().unwrap() + 1,
   21    33         height: blocks.iter().map(|(_, y)| *y).max().unwrap() + 1,
@@ -36,13 +48,12 @@ fn get_input() -> Vec<bool> {
   36    48     return moves;
   37    49 }
   38    50 
   39    -1 fn render(covered: &HashSet<(i64, i64)>) {
   40    -1     // let width = covered.iter().map(|(x, _)| *x).max().unwrap() + 1;
   41    -1     let width = 7;
   -1    51 #[allow(dead_code)]
   -1    52 fn render(covered: &HashSet<(usize, usize)>) {
   42    53     let height = covered.iter().map(|(_, y)| *y).max().unwrap() + 1;
   43    54 
   44    55     for y in (0..height + 3).rev() {
   45    -1         for x in 0..width {
   -1    56         for x in 0..WIDTH {
   46    57             if covered.contains(&(x, y)) {
   47    58                 print!("#");
   48    59             } else {
@@ -54,33 +65,38 @@ fn render(covered: &HashSet<(i64, i64)>) {
   54    65     print!("\n");
   55    66 }
   56    67 
   57    -1 fn part1(moves: &Vec<bool>, shapes: &[Shape; 5], width: i64, n: usize) -> i64 {
   -1    68 fn part1(moves: &Vec<bool>, shapes: &[Shape; 5], n: usize) -> usize {
   58    69     let mut height = 0;
   59    70     let mut move_i = 0;
   60    -1     let mut covered: HashSet<(i64, i64)> = HashSet::new();
   -1    71     let mut i = 0;
   -1    72     let mut covered: HashSet<(usize, usize)> = HashSet::new();
   61    73 
   62    -1     for i in 0..n {
   -1    74     let mut cache = HashMap::new();
   -1    75     let mut jump_height = 0;
   -1    76 
   -1    77     while i < n {
   63    78         let shape = &shapes[i % shapes.len()];
   64    79         let mut x = 2;
   65    -1         let mut y = height + 3;
   66    -1 
   67    -1         // for _ in 0..3 {
   68    -1         //     if moves[move_i] {
   69    -1         //         if x + shape.width + 1 < width {
   70    -1         //             x += 1;
   71    -1         //         }
   72    -1         //     } else {
   73    -1         //         if x > 0 {
   74    -1         //             x -= 1;
   75    -1         //         }
   76    -1         //     }
   77    -1         //     move_i = (move_i + 1) % moves.len();
   78    -1         // }
   -1    80         let mut y = height;
   -1    81 
   -1    82         // PERF: for the first three steps there can bo no collisions
   -1    83         for _ in 0..3 {
   -1    84             if moves[move_i] {
   -1    85                 if x + shape.width < WIDTH {
   -1    86                     x += 1;
   -1    87                 }
   -1    88             } else {
   -1    89                 if x > 0 {
   -1    90                     x -= 1;
   -1    91                 }
   -1    92             }
   -1    93             move_i = (move_i + 1) % moves.len();
   -1    94         }
   79    95 
   80    96         loop {
   81    97             let move_right = moves[move_i];
   82    98             if move_right {
   83    -1                 if x + shape.width < width && shape.right.iter().all(|(xs, ys)| !covered.contains(&((x + *xs + 1, y + *ys)))) {
   -1    99                 if x + shape.width < WIDTH && shape.right.iter().all(|(xs, ys)| !covered.contains(&((x + *xs + 1, y + *ys)))) {
   84   100                     x += 1;
   85   101                 }
   86   102             } else {
@@ -100,11 +116,35 @@ fn part1(moves: &Vec<bool>, shapes: &[Shape; 5], width: i64, n: usize) -> i64 {
  100   116         covered.extend(shape.blocks.iter().map(|(xs, ys)| (x + xs, y + ys)));
  101   117         height = (y + shape.height).max(height);
  102   118 
   -1   119         if jump_height == 0 {
   -1   120             let cache_key = CacheKey {
   -1   121                 move_i: move_i,
   -1   122                 shape_i: i % shapes.len(),
   -1   123                 top_rows: (0..4).map(|x| {
   -1   124                     return (0..WIDTH).map(|dy| {
   -1   125                         return dy < height && covered.contains(&(x, height - 1 - dy));
   -1   126                     }).collect::<Vec<bool>>().try_into().unwrap();
   -1   127                 }).collect::<Vec<[bool; WIDTH]>>().try_into().unwrap(),
   -1   128             };
   -1   129 
   -1   130             if let Some((prior_i, prior_height)) = cache.get(&cache_key) {
   -1   131                 let di = i - prior_i;
   -1   132                 let dh = height - prior_height;
   -1   133                 let count = (n - i) / di;
   -1   134                 println!("jumped from {} to {} ({}x{})", i, i + di * count, di, count);
   -1   135                 i += di * count;
   -1   136                 jump_height =  dh * count;
   -1   137             } else {
   -1   138                 cache.insert(cache_key, (i, height));
   -1   139             }
   -1   140         }
   -1   141 
  103   142         // render(&covered);
   -1   143 
   -1   144         i += 1;
  104   145     }
  105    -1     // render(&covered);
  106   146 
  107    -1     return height;
   -1   147     return height + jump_height;
  108   148 }
  109   149 
  110   150 fn main() {
@@ -144,6 +184,6 @@ fn main() {
  144   184         ]),
  145   185     ];
  146   186 
  147    -1     println!("part1: {}", part1(&moves, &shapes, 7, 2022));
  148    -1     // println!("part2: {}", part2(&optimized, 26));
   -1   187     println!("part1: {}", part1(&moves, &shapes, 2022));
   -1   188     println!("part2: {}", part1(&moves, &shapes, 1000000000000));
  149   189 }