1
0
Fork 0

2022 day 17

This commit is contained in:
Terrana Ninetailed 2022-12-23 23:01:34 +00:00
parent 0f12151a23
commit 756cc390e1
Signed by: terrana
GPG key ID: 93EB761F8AB88151
4 changed files with 303 additions and 0 deletions

1
2022/src/day17/input Normal file

File diff suppressed because one or more lines are too long

75
2022/src/day17/part1.rs Normal file
View file

@ -0,0 +1,75 @@
mod shape;
use shape::*;
use std::fs;
fn main() {
//let input = String::from(">>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>");
let input = String::from_utf8_lossy(&fs::read("input").unwrap()).into_owned();
let mut grid = vec![[false;FIELD_WIDTH];4];
let mut chars = input.trim().chars().cycle();
let mut top = 0;
for (i,shape) in SHAPES.iter().cycle().enumerate() {
if i >= 2022 { break; }
let mut x = 2;
let mut y = top + 2 + shape.height();
if grid.len() <= y {
grid.resize(y + 1, [false;FIELD_WIDTH]);
}
while let Some(c) = chars.next() {
// for (y2,line) in grid.iter().enumerate().rev() {
// if y2 > y && *line == [false;FIELD_WIDTH] {continue;}
// print!("|");
// for (x2,tile) in line.iter().enumerate() {
// if *tile {
// print!("#");
// } else if x2 >= x && y >= y2 && shape.mask().any(|[xo,yo]| *xo == x2 - x && *yo == y - y2) {
// print!("@");
// } else {
// print!(".");
// }
// }
// println!("|");
// }
// println!("+-------+\n");
match c {
'<' => {if !shape.collide_left(x, y, &grid) {
x -= 1;
}},
'>' => {if !shape.collide_right(x, y, &grid) {
x += 1;
}},
_ => { panic!("Bad character '{:?}' in input", c); }
}
if shape.collide_down(x, y, &grid) {
shape.place(x, y, &mut grid);
if y >= top {
top = y + 1;
}
break;
} else {
y -= 1;
}
}
// for line in grid.iter().rev() {
// if *line == [false;FIELD_WIDTH] {continue;}
// print!("|");
// for tile in line {
// if *tile {
// print!("#");
// } else {
// print!(".");
// }
// }
// println!("|");
// }
// println!("+-------+\n{top}\n");
}
println!("{top}");
}

131
2022/src/day17/part2.rs Normal file
View file

@ -0,0 +1,131 @@
mod shape;
use shape::*;
use std::fs;
const CYCLE_ATTEMPTS: usize = 10;
fn main() {
let input = String::from_utf8_lossy(&fs::read("input").unwrap()).into_owned();
let cycle = find_cycle_length(&input);
println!("{cycle:?}");
for i in 1..=10 {
let target = 1000 * i;
assert_eq!(find_height_after(&input, target) as u64, calc_height_after(&cycle, &input, target as u64));
}
println!("{}", calc_height_after(&cycle, &input, 1000000000000));
}
fn calc_height_after(cycle: &Cycle, input: &String, n_shapes: u64) -> u64 {
if n_shapes < cycle.cycle_start_shapes {
return find_height_after(input, n_shapes as usize) as u64;
}
let n_minus_start = n_shapes - cycle.cycle_start_shapes;
let n_cycles = n_minus_start / cycle.cycle_shapes;
let offset = n_minus_start % cycle.cycle_shapes;
n_cycles * cycle.cycle_height + find_height_after(input, (offset + cycle.cycle_start_shapes) as usize) as u64
}
fn find_height_after(input: &String, n_shapes: usize) -> usize {
let mut chars = input.trim().chars().cycle();
let mut grid = vec![[false;FIELD_WIDTH];4];
let mut top = 0;
for (i,shape) in SHAPES.iter().cycle().enumerate() {
if i >= n_shapes { break; }
let mut x = 2;
let mut y = top + 2 + shape.height();
if grid.len() <= y {
grid.resize(y + 1, [false;FIELD_WIDTH]);
}
while let Some(c) = chars.next() {
match c {
'<' => {if !shape.collide_left(x, y, &grid) {
x -= 1;
}},
'>' => {if !shape.collide_right(x, y, &grid) {
x += 1;
}},
_ => { panic!("Bad character '{:?}' in input", c); }
}
if shape.collide_down(x, y, &grid) {
shape.place(x, y, &mut grid);
if y >= top {
top = y + 1;
}
break;
} else {
y -= 1;
}
}
}
top
}
fn find_cycle_length(input: &String) -> Cycle {
let limit = CYCLE_ATTEMPTS * input.trim().len();
let mut chars = input.trim().chars().cycle().enumerate();
let mut grid = vec![[false;FIELD_WIDTH];4];
let mut top = 0;
let mut last_i = 0;
let mut last_i2 = 0;
let mut last_top = 0;
let mut last_top2 = 0;
for (i,shape) in SHAPES.iter().cycle().enumerate() {
let mut x = 2;
let mut y = top + 2 + shape.height();
if grid.len() <= y {
grid.resize(y + 1, [false;FIELD_WIDTH]);
}
while let Some((j,c)) = chars.next() {
if j > limit {
panic!("Couldn't find a cycle length after {} cycles.", CYCLE_ATTEMPTS);
}
if i != 0 && j % input.trim().len() == 0 {
let cycle_shapes = i - last_i;
let cycle_height = top - last_top;
// println!("{i:5} {:4} {top:5} {:4}", i - last_i, top - last_top);
if cycle_shapes == last_i - last_i2 && cycle_height == last_top - last_top2 {
return Cycle {
cycle_start_shapes: last_i2 as u64,
cycle_shapes: cycle_shapes as u64,
cycle_height: cycle_height as u64
};
}
last_i2 = last_i;
last_i = i;
last_top2 = last_top;
last_top = top;
}
match c {
'<' => {if !shape.collide_left(x, y, &grid) {
x -= 1;
}},
'>' => {if !shape.collide_right(x, y, &grid) {
x += 1;
}},
_ => { panic!("Bad character '{}' in input", c); }
}
if shape.collide_down(x, y, &grid) {
shape.place(x, y, &mut grid);
if y >= top {
top = y + 1;
}
break;
} else {
y -= 1;
}
}
}
panic!("Cycle loop ended unexpectedly");
}
#[derive(Debug)]
struct Cycle {
cycle_start_shapes: u64,
cycle_shapes: u64,
cycle_height: u64
}

96
2022/src/day17/shape.rs Normal file
View file

@ -0,0 +1,96 @@
use Shape::*;
pub const FIELD_WIDTH: usize = 7;
pub const SHAPES: [Shape;5] = [Line, Cross, L, Column, Square];
#[derive(Clone, Copy, Debug)]
pub enum Shape {
// ####
Line,
// .#.
// ###
// .#.
Cross,
// ..#
// ..#
// ###
L,
// #
// #
// #
// #
Column,
// ##
// ##
Square
}
impl Shape {
pub fn collide_down(&self, x: usize, y: usize, grid: &Vec<[bool;FIELD_WIDTH]>) -> bool {
y < self.height() || match *self {
Line => grid[y-1][x ] || grid[y-1][x+1] || grid[y-1][x+2] || grid[y-1][x+3],
Cross => grid[y-3][x+1] || grid[y-2][x ] || grid[y-2][x+2],
L => grid[y-3][x ] || grid[y-3][x+1] || grid[y-3][x+2],
Column => grid[y-4][x ],
Square => grid[y-2][x ] || grid[y-2][x+1]
}
}
pub fn collide_left(&self, x: usize, y: usize, grid: &Vec<[bool;FIELD_WIDTH]>) -> bool {
x == 0 || match *self {
Line => grid[y][x-1],
Cross => grid[y-2][x ] || grid[y-1][x-1] || grid[y ][x ],
L => grid[y-2][x-1] || grid[y-1][x+1] || grid[y ][x+1],
Column => grid[y-3][x-1] || grid[y-2][x-1] || grid[y-1][x-1] || grid[y ][x-1],
Square => grid[y-1][x-1] || grid[y ][x-1]
}
}
pub fn collide_right(&self, x: usize, y: usize, grid: &Vec<[bool;FIELD_WIDTH]>) -> bool {
x + self.width() >= FIELD_WIDTH || match *self {
Line => grid[y ][x+4],
Cross => grid[y-2][x+2] || grid[y-1][x+3] || grid[y ][x+2],
L => grid[y-2][x+3] || grid[y-1][x+3] || grid[y ][x+3],
Column => grid[y-3][x+1] || grid[y-2][x+1] || grid[y-1][x+1] || grid[y ][x+1],
Square => grid[y-1][x+2] || grid[y ][x+2]
}
}
pub fn place(&self, x: usize, y: usize, grid: &mut Vec<[bool;FIELD_WIDTH]>) {
for [xo,yo] in self.mask() {
grid[y-yo][x+xo] = true;
}
}
pub fn mask(&self) -> std::slice::Iter<[usize;2]> {
match *self {
Line => [[0,0],[1,0],[2,0],[3,0]].iter(),
Cross => [[1,0],[0,1],[1,1],[2,1],[1,2]].iter(),
L => [[2,0],[2,1],[0,2],[1,2],[2,2]].iter(),
Column => [[0,0],[0,1],[0,2],[0,3]].iter(),
Square => [[0,0],[1,0],[0,1],[1,1]].iter()
}
}
pub fn height(&self) -> usize {
match *self {
Line => 1,
Cross => 3,
L => 3,
Column => 4,
Square => 2
}
}
pub fn width(&self) -> usize {
match *self {
Line => 4,
Cross => 3,
L => 3,
Column => 1,
Square => 2
}
}
}