day 22
This commit is contained in:
202
inputs/day22.txt
Normal file
202
inputs/day22.txt
Normal file
File diff suppressed because one or more lines are too long
8
src/bin/day22_1.rs
Normal file
8
src/bin/day22_1.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use aoc2022::day22::process_part_1;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let file = fs::read_to_string("./inputs/day22.txt").unwrap();
|
||||||
|
println!("{}", process_part_1(&file));
|
||||||
|
}
|
||||||
8
src/bin/day22_2.rs
Normal file
8
src/bin/day22_2.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use aoc2022::day22::process_part_2;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let file = fs::read_to_string("./inputs/day22.txt").unwrap();
|
||||||
|
println!("{}", process_part_2(&file, 50));
|
||||||
|
}
|
||||||
434
src/day22.rs
Normal file
434
src/day22.rs
Normal file
@@ -0,0 +1,434 @@
|
|||||||
|
use itertools::Itertools;
|
||||||
|
use nom::branch::alt;
|
||||||
|
use nom::bytes::complete::tag;
|
||||||
|
use nom::character::complete::{digit1, newline, one_of};
|
||||||
|
use nom::combinator::map;
|
||||||
|
use nom::multi::{many1, separated_list1};
|
||||||
|
use nom::sequence::separated_pair;
|
||||||
|
use nom::IResult;
|
||||||
|
|
||||||
|
pub fn process_part_1(input: &str) -> usize {
|
||||||
|
let (grid, instructions) = parse_input(input).unwrap().1;
|
||||||
|
let mut player = Player {
|
||||||
|
x: grid[0]
|
||||||
|
.iter()
|
||||||
|
.position(|t| matches!(t, Tile::Free))
|
||||||
|
.unwrap(),
|
||||||
|
y: 0,
|
||||||
|
dir: Dir::R,
|
||||||
|
};
|
||||||
|
for i in instructions {
|
||||||
|
player.walk1(&i, &grid);
|
||||||
|
}
|
||||||
|
1000 * (player.y + 1) + (4 * (player.x + 1)) + isize::from(&player.dir) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_part_2(input: &str, cube_size: usize) -> usize {
|
||||||
|
let (grid, instructions) = parse_input(input).unwrap().1;
|
||||||
|
let mut player = Player {
|
||||||
|
x: grid[0]
|
||||||
|
.iter()
|
||||||
|
.position(|t| matches!(t, Tile::Free))
|
||||||
|
.unwrap(),
|
||||||
|
y: 0,
|
||||||
|
dir: Dir::R,
|
||||||
|
};
|
||||||
|
for i in instructions {
|
||||||
|
player.walk2(&i, &grid, cube_size);
|
||||||
|
}
|
||||||
|
1000 * (player.y + 1) + (4 * (player.x + 1)) + isize::from(&player.dir) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Player {
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
dir: Dir,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Player {
|
||||||
|
fn walk1(&mut self, instr: &Instruction, grid: &[Vec<Tile>]) {
|
||||||
|
match instr {
|
||||||
|
Instruction::Left => {
|
||||||
|
self.dir = (isize::from(&self.dir) - 1).rem_euclid(4).into();
|
||||||
|
}
|
||||||
|
Instruction::Right => {
|
||||||
|
self.dir = (isize::from(&self.dir) + 1).rem_euclid(4).into();
|
||||||
|
}
|
||||||
|
Instruction::Walk(dist) => {
|
||||||
|
for _ in 0..*dist {
|
||||||
|
let (next_x, next_y, next_tile) = match &self.dir {
|
||||||
|
Dir::R => {
|
||||||
|
let row = &grid[self.y];
|
||||||
|
let (next_x, next_tile) = row
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.cycle()
|
||||||
|
.skip(self.x + 1)
|
||||||
|
.find(|(_, t)| !matches!(t, Tile::None))
|
||||||
|
.unwrap();
|
||||||
|
(next_x, self.y, next_tile)
|
||||||
|
}
|
||||||
|
Dir::D => {
|
||||||
|
let col = grid.iter().map_while(|row| row.get(self.x));
|
||||||
|
let (next_y, next_tile) = col
|
||||||
|
.enumerate()
|
||||||
|
.cycle()
|
||||||
|
.skip(self.y + 1)
|
||||||
|
.find(|(_, t)| !matches!(t, Tile::None))
|
||||||
|
.unwrap();
|
||||||
|
(self.x, next_y, next_tile)
|
||||||
|
}
|
||||||
|
Dir::L => {
|
||||||
|
let row = &grid[self.y];
|
||||||
|
let (next_x, next_tile) = row
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.rev()
|
||||||
|
.cycle()
|
||||||
|
.skip(row.len() - self.x)
|
||||||
|
.find(|(_, t)| !matches!(t, Tile::None))
|
||||||
|
.unwrap();
|
||||||
|
(next_x, self.y, next_tile)
|
||||||
|
}
|
||||||
|
Dir::U => {
|
||||||
|
let col = grid.iter().map_while(|row| row.get(self.x)).collect_vec();
|
||||||
|
let (next_y, next_tile) = col
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.rev()
|
||||||
|
.cycle()
|
||||||
|
.skip(col.len() - self.y)
|
||||||
|
.find(|(_, t)| !matches!(t, Tile::None))
|
||||||
|
.unwrap();
|
||||||
|
(self.x, next_y, *next_tile)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match next_tile {
|
||||||
|
Tile::Free => (self.x, self.y) = (next_x, next_y),
|
||||||
|
Tile::Wall => break,
|
||||||
|
Tile::None => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk2(&mut self, instr: &Instruction, grid: &[Vec<Tile>], size: usize) {
|
||||||
|
match instr {
|
||||||
|
Instruction::Left => {
|
||||||
|
self.dir = (isize::from(&self.dir) - 1).rem_euclid(4).into();
|
||||||
|
}
|
||||||
|
Instruction::Right => {
|
||||||
|
self.dir = (isize::from(&self.dir) + 1).rem_euclid(4).into();
|
||||||
|
}
|
||||||
|
Instruction::Walk(dist) => {
|
||||||
|
for _ in 0..*dist {
|
||||||
|
let (next_x, next_y, next_dir) = self.next_coord(size);
|
||||||
|
let next_tile = &grid[next_y][next_x];
|
||||||
|
match next_tile {
|
||||||
|
Tile::Free => {
|
||||||
|
self.x = next_x;
|
||||||
|
self.y = next_y;
|
||||||
|
self.dir = next_dir
|
||||||
|
}
|
||||||
|
Tile::Wall => break,
|
||||||
|
Tile::None => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_coord(&self, size: usize) -> (usize, usize, Dir) {
|
||||||
|
let face = get_face(self.x, self.y, size);
|
||||||
|
let (xl, yl) = global_to_local(self.x, self.y, size);
|
||||||
|
match face {
|
||||||
|
1 => match self.dir {
|
||||||
|
Dir::R => (self.x + 1, self.y, Dir::R),
|
||||||
|
Dir::L => {
|
||||||
|
if xl == 0 {
|
||||||
|
let (nx, ny) = local_to_global(xl, size - yl - 1, 4, size);
|
||||||
|
(nx, ny, Dir::R)
|
||||||
|
} else {
|
||||||
|
(self.x - 1, self.y, Dir::L)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::U => {
|
||||||
|
if yl == 0 {
|
||||||
|
let (nx, ny) = local_to_global(yl, xl, 6, size);
|
||||||
|
(nx, ny, Dir::R)
|
||||||
|
} else {
|
||||||
|
(self.x, self.y - 1, Dir::U)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::D => (self.x, self.y + 1, Dir::D),
|
||||||
|
},
|
||||||
|
2 => match self.dir {
|
||||||
|
Dir::R => {
|
||||||
|
if xl == size - 1 {
|
||||||
|
let (nx, ny) = local_to_global(xl, size - yl - 1, 5, size);
|
||||||
|
(nx, ny, Dir::L)
|
||||||
|
} else {
|
||||||
|
(self.x + 1, self.y, Dir::R)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::L => (self.x - 1, self.y, Dir::L),
|
||||||
|
Dir::U => {
|
||||||
|
if yl == 0 {
|
||||||
|
let (nx, ny) = local_to_global(xl, size - 1, 6, size);
|
||||||
|
(nx, ny, Dir::U)
|
||||||
|
} else {
|
||||||
|
(self.x, self.y - 1, Dir::U)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::D => {
|
||||||
|
if yl == size - 1 {
|
||||||
|
let (nx, ny) = local_to_global(yl, xl, 3, size);
|
||||||
|
(nx, ny, Dir::L)
|
||||||
|
} else {
|
||||||
|
(self.x, self.y + 1, Dir::D)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
3 => match self.dir {
|
||||||
|
Dir::R => {
|
||||||
|
if xl == size - 1 {
|
||||||
|
let (nx, ny) = local_to_global(yl, xl, 2, size);
|
||||||
|
(nx, ny, Dir::U)
|
||||||
|
} else {
|
||||||
|
(self.x + 1, self.y, Dir::R)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::L => {
|
||||||
|
if xl == 0 {
|
||||||
|
let (nx, ny) = local_to_global(yl, xl, 4, size);
|
||||||
|
(nx, ny, Dir::D)
|
||||||
|
} else {
|
||||||
|
(self.x - 1, self.y, Dir::L)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::U => (self.x, self.y - 1, Dir::U),
|
||||||
|
Dir::D => (self.x, self.y + 1, Dir::D),
|
||||||
|
},
|
||||||
|
4 => match self.dir {
|
||||||
|
Dir::R => (self.x + 1, self.y, Dir::R),
|
||||||
|
Dir::L => {
|
||||||
|
if xl == 0 {
|
||||||
|
let (nx, ny) = local_to_global(xl, size - yl - 1, 1, size);
|
||||||
|
(nx, ny, Dir::R)
|
||||||
|
} else {
|
||||||
|
(self.x - 1, self.y, Dir::L)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::U => {
|
||||||
|
if yl == 0 {
|
||||||
|
let (nx, ny) = local_to_global(yl, xl, 3, size);
|
||||||
|
(nx, ny, Dir::R)
|
||||||
|
} else {
|
||||||
|
(self.x, self.y - 1, Dir::U)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::D => (self.x, self.y + 1, Dir::D),
|
||||||
|
},
|
||||||
|
5 => match self.dir {
|
||||||
|
Dir::R => {
|
||||||
|
if xl == size - 1 {
|
||||||
|
let (nx, ny) = local_to_global(xl, size - yl - 1, 2, size);
|
||||||
|
(nx, ny, Dir::L)
|
||||||
|
} else {
|
||||||
|
(self.x + 1, self.y, Dir::R)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::L => (self.x - 1, self.y, Dir::L),
|
||||||
|
Dir::U => (self.x, self.y - 1, Dir::U),
|
||||||
|
Dir::D => {
|
||||||
|
if yl == size - 1 {
|
||||||
|
let (nx, ny) = local_to_global(yl, xl, 6, size);
|
||||||
|
(nx, ny, Dir::L)
|
||||||
|
} else {
|
||||||
|
(self.x, self.y + 1, Dir::D)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => match self.dir {
|
||||||
|
Dir::R => {
|
||||||
|
if xl == size - 1 {
|
||||||
|
let (nx, ny) = local_to_global(yl, xl, 5, size);
|
||||||
|
(nx, ny, Dir::U)
|
||||||
|
} else {
|
||||||
|
(self.x + 1, self.y, Dir::R)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::L => {
|
||||||
|
if xl == 0 {
|
||||||
|
let (nx, ny) = local_to_global(yl, xl, 1, size);
|
||||||
|
(nx, ny, Dir::D)
|
||||||
|
} else {
|
||||||
|
(self.x - 1, self.y, Dir::L)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::U => (self.x, self.y - 1, Dir::U),
|
||||||
|
Dir::D => {
|
||||||
|
if yl == size - 1 {
|
||||||
|
let (nx, ny) = local_to_global(xl, 0, 2, size);
|
||||||
|
(nx, ny, Dir::D)
|
||||||
|
} else {
|
||||||
|
(self.x, self.y + 1, Dir::D)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look, i'm just hardcoding it
|
||||||
|
// _12
|
||||||
|
// _3_
|
||||||
|
// 45_
|
||||||
|
// 6__
|
||||||
|
fn get_face(x: usize, y: usize, size: usize) -> usize {
|
||||||
|
if y < size {
|
||||||
|
if x < 2 * size {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if y < 2 * size {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if y < 3 * size {
|
||||||
|
if x < size {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
6
|
||||||
|
}
|
||||||
|
|
||||||
|
fn global_to_local(x: usize, y: usize, size: usize) -> (usize, usize) {
|
||||||
|
let face = get_face(x, y, size);
|
||||||
|
match face {
|
||||||
|
1 => (x - size, y),
|
||||||
|
2 => (x - 2 * size, y),
|
||||||
|
3 => (x - size, y - size),
|
||||||
|
4 => (x, y - 2 * size),
|
||||||
|
5 => (x - size, y - 2 * size),
|
||||||
|
6 => (x, y - 3 * size),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn local_to_global(x: usize, y: usize, face: usize, size: usize) -> (usize, usize) {
|
||||||
|
match face {
|
||||||
|
1 => (x + size, y),
|
||||||
|
2 => (x + 2 * size, y),
|
||||||
|
3 => (x + size, y + size),
|
||||||
|
4 => (x, y + 2 * size),
|
||||||
|
5 => (x + size, y + 2 * size),
|
||||||
|
6 => (x, y + 3 * size),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Tile {
|
||||||
|
None,
|
||||||
|
Free,
|
||||||
|
Wall,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Instruction {
|
||||||
|
Walk(usize),
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Dir {
|
||||||
|
R,
|
||||||
|
D,
|
||||||
|
L,
|
||||||
|
U,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Dir> for isize {
|
||||||
|
fn from(value: &Dir) -> Self {
|
||||||
|
match value {
|
||||||
|
Dir::R => 0,
|
||||||
|
Dir::D => 1,
|
||||||
|
Dir::L => 2,
|
||||||
|
Dir::U => 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<isize> for Dir {
|
||||||
|
fn from(value: isize) -> Self {
|
||||||
|
match value {
|
||||||
|
0 => Dir::R,
|
||||||
|
1 => Dir::D,
|
||||||
|
2 => Dir::L,
|
||||||
|
3 => Dir::U,
|
||||||
|
_ => panic!("invalid direction"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_input(input: &str) -> IResult<&str, (Vec<Vec<Tile>>, Vec<Instruction>)> {
|
||||||
|
separated_pair(parse_grid, tag("\n\n"), parse_instructions)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_grid(input: &str) -> IResult<&str, Vec<Vec<Tile>>> {
|
||||||
|
separated_list1(
|
||||||
|
newline,
|
||||||
|
many1(map(one_of(" .#"), |c| match c {
|
||||||
|
' ' => Tile::None,
|
||||||
|
'.' => Tile::Free,
|
||||||
|
'#' => Tile::Wall,
|
||||||
|
_ => unreachable!(),
|
||||||
|
})),
|
||||||
|
)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_instructions(input: &str) -> IResult<&str, Vec<Instruction>> {
|
||||||
|
many1(map(alt((digit1, tag("R"), tag("L"))), |c| match c {
|
||||||
|
"R" => Instruction::Right,
|
||||||
|
"L" => Instruction::Left,
|
||||||
|
dist => Instruction::Walk(dist.parse().unwrap()),
|
||||||
|
}))(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const INPUT: &str = " ...#
|
||||||
|
.#..
|
||||||
|
#...
|
||||||
|
....
|
||||||
|
...#.......#
|
||||||
|
........#...
|
||||||
|
..#....#....
|
||||||
|
..........#.
|
||||||
|
...#....
|
||||||
|
.....#..
|
||||||
|
.#......
|
||||||
|
......#.
|
||||||
|
|
||||||
|
10R5L5R10L4R5L5";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn day1() {
|
||||||
|
assert_eq!(process_part_1(INPUT), 6032);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn day2() {
|
||||||
|
// no test, because the test folding is different than the input folding
|
||||||
|
// SO FUCK THAT GARBAGE
|
||||||
|
// assert_eq!(process_part_2(INPUT, 4), 5031);
|
||||||
|
assert_eq!(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,3 +22,4 @@ pub mod day18;
|
|||||||
pub mod day19;
|
pub mod day19;
|
||||||
pub mod day20;
|
pub mod day20;
|
||||||
pub mod day21;
|
pub mod day21;
|
||||||
|
pub mod day22;
|
||||||
|
|||||||
Reference in New Issue
Block a user