feat: day 17 (literally several hours, part 2 doesn't work)

This commit is contained in:
Ashhhleyyy 2022-12-18 21:28:35 +00:00
parent a788ddaa44
commit cb0c259251
Signed by: ash
GPG key ID: 83B789081A0878FB
3 changed files with 223 additions and 0 deletions

1
.aoc-cache/17.txt Normal file

File diff suppressed because one or more lines are too long

221
src/bin/day_17.rs Normal file
View file

@ -0,0 +1,221 @@
#![feature(hash_drain_filter)]
use std::collections::HashSet;
use aoc_2022::prelude::*;
#[derive(Clone, Copy)]
struct RockShape {
shape: [[bool; 4]; 4],
width: usize,
height: usize,
}
const ROCK_SHAPES: &[RockShape] = &[
RockShape {
shape: [
[true, true, true, true ],
[false, false, false, false],
[false, false, false, false],
[false, false, false, false],
],
width: 4,
height: 1,
},
RockShape {
shape: [
[false, true , false, false],
[true , true , true , false],
[false, true , false, false],
[false, false, false, false],
],
width: 3,
height: 3,
},
RockShape {
shape: [
[true , true , true , false],
[false, false, true , false],
[false, false, true , false],
[false, false, false, false],
],
width: 3,
height: 3,
},
RockShape {
shape: [
[true , false, false, false],
[true , false, false, false],
[true , false, false, false],
[true , false, false, false],
],
width: 1,
height: 4,
},
RockShape {
shape: [
[true , true , false, false],
[true , true , false, false],
[false, false, false, false],
[false, false, false, false],
],
width: 2,
height: 2,
},
];
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Direction {
Left,
Right,
Down,
}
impl Direction {
fn offset(&self, pos: (usize, usize), width: usize) -> Option<(usize, usize)> {
match self {
Direction::Left if pos.0 > 0 => Some((pos.0 - 1, pos.1)),
Direction::Right if pos.0 + width < 7 => Some((pos.0 + 1, pos.1)),
Direction::Down if pos.1 > 0 => Some((pos.0, pos.1 - 1)),
Direction::Down => None,
_ => Some(pos),
}
}
}
type Input = Vec<Direction>;
fn parse(s: &str) -> Result<Input> {
Ok(
s.chars()
.filter_map(|c| match c {
'<' => Some(Direction::Left),
'>' => Some(Direction::Right),
_ => None,
})
.flat_map(|i| [i, Direction::Down].into_iter())
.collect::<Vec<_>>()
)
}
#[aoc(day = 17, parse = parse, test_cases = ["day_17.txt"])]
fn day_17(input: Input) -> Result<()> {
// Part 1
let mut instruction = 0;
let mut map = HashSet::new();
// we need 2022 rocks
for rock in 0..2022 {
let rock = rock % ROCK_SHAPES.len();
instruction %= input.len();
simulate_rock(ROCK_SHAPES[rock], &input, &mut map, &mut instruction);
}
let part_one = highest_point_in_map(&map).unwrap_or((0, 0)).1 + 1;
println!("Part one: {part_one}");
// Part 2
Ok(())
}
fn display_map(map: &HashSet<(usize, usize)>, falling: Option<((usize, usize), RockShape)>) {
let max_y = highest_point_in_map(&map).unwrap_or((0, 0)).1 + 1;
let max_y = if let Some((pos, rock)) = falling {
max_y.max(pos.1 + rock.height)
} else {
max_y
};
for y in 0..max_y {
let y = max_y - 1 - y;
print!("|");
for x in 0..7 {
if map.contains(&(x, y)) {
print!("#");
} else {
let mut is_falling_rock = false;
if let Some((pos, rock)) = falling {
for (ry, row) in rock.shape.iter().enumerate() {
for (rx, is_solid) in row.iter().enumerate() {
if *is_solid {
let pos = (pos.0 + rx, pos.1 + ry);
if pos.0 == x && pos.1 == y {
print!("@");
is_falling_rock = true;
}
}
}
}
}
if !is_falling_rock {
print!(".");
}
}
}
println!("|");
}
println!("+-------+");
println!();
}
fn highest_point_in_map(map: &HashSet<(usize, usize)>) -> Option<(usize, usize)> {
map.iter().max_by_key(|c| c.1).map(|c| *c)
}
fn lowest_high_point(map: &HashSet<(usize, usize)>) -> Option<usize> {
(0..7).into_iter()
.filter_map(|x| map.iter().filter(|c| c.0 == x).map(|c| c.1).max())
.min()
}
fn simulate_rock(rock: RockShape, input: &Input, map: &mut HashSet<(usize, usize)>, instruction: &mut usize) {
let mut position = if let Some(max_pos) = highest_point_in_map(map) {
(2, max_pos.1 + 4)
} else {
(2, 3)
};
// display_map(&map, Some((position, rock)));
loop {
let direction = input[*instruction];
*instruction += 1;
*instruction %= input.len();
if let Some(new_pos) = direction.offset(position, rock.width) {
let would_be_stuck = rock.shape.iter()
.enumerate()
.flat_map(|(y, row)| row.iter()
.enumerate()
.filter_map(move |(x, present)| if *present { Some((x, y)) } else { None })
)
.map(|c| (c.0 + new_pos.0, c.1 + new_pos.1))
.any(|c| map.contains(&c));
if would_be_stuck {
if direction == Direction::Down {
break;
}
} else {
position = new_pos;
}
} else {
break;
}
}
// println!("Came to rest at {position:?}");
for (y, row) in rock.shape.iter().enumerate() {
for (x, is_solid) in row.iter().enumerate() {
if *is_solid {
let pos = (position.0 + x, position.1 + y);
map.insert(pos);
}
}
}
}

1
test_cases/day_17.txt Normal file
View file

@ -0,0 +1 @@
>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>