day 22, in Rust, not mine

This commit is contained in:
setop 2022-12-29 12:36:44 +01:00
parent 5d4d2f9f38
commit 6ff32e169a
2 changed files with 343 additions and 0 deletions

146
d22/part1.rs Normal file
View File

@ -0,0 +1,146 @@
use std::iter::repeat;
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct Instruction {
dist: Option<isize>,
rotation: Option<isize>,
}
pub fn main() {
let s = include_bytes!("./input");
let mut pos = (s.iter().position(|b| *b == b'.').unwrap() as isize, 0);
let mut facing: (isize, isize) = (1, 0);
let w = s
.split(|b| *b == b'\n')
.take_while(|l| !l.is_empty())
.map(|l| l.len())
.max()
.unwrap();
let map = s
.split(|b| *b == b'\n')
.take_while(|l| !l.is_empty())
.map(|l| {
l.iter()
.take(l.len())
.chain(repeat(&b' ').take(w - l.len()))
.copied()
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
let h = map.len();
let mut path: Vec<Instruction> = Vec::new();
let mut acc = 0;
s.split(|b| *b == b'\n')
.rev()
.nth(1)
.unwrap()
.iter()
.for_each(|b| match b {
b'0'..=b'9' => {
acc = acc * 10 + (b - b'0') as isize;
}
b'R' => {
path.push(Instruction {
dist: Some(acc),
rotation: None,
});
path.push(Instruction {
dist: None,
rotation: Some(1),
});
acc = 0;
}
b'L' => {
path.push(Instruction {
dist: Some(acc),
rotation: None,
});
path.push(Instruction {
dist: None,
rotation: Some(-1),
});
acc = 0;
}
_ => unreachable!(),
});
path.push(Instruction {
dist: Some(acc),
rotation: None,
});
#[cfg(debug_assertions)]
println!("{} {}", map.len(), map[0].len());
#[cfg(debug_assertions)]
println!(
"pos: ({}, {}), facing ({} {})",
pos.0, pos.1, facing.0, facing.1
);
for ins in path.iter() {
#[cfg(debug_assertions)]
println!("{:?}", ins);
match (ins.dist, ins.rotation) {
(Some(dist), None) => {
for step in 0..dist {
let mut next_pos = (pos.0 + facing.0, pos.1 + facing.1);
#[cfg(debug_assertions)]
println!("next_pos: {} {}", next_pos.0, next_pos.1);
let next_char = if next_pos.0 >= 0
&& next_pos.0 < w as isize
&& next_pos.1 >= 0
&& next_pos.1 < h as isize
{
Some(map[next_pos.1 as usize][next_pos.0 as usize])
} else {
None
};
if next_char == Some(b'.') {
pos = next_pos;
} else if next_char.is_none() || next_char == Some(b' ') {
next_pos = (pos.0 - facing.0, pos.1 - facing.1);
while next_pos.0 >= 0
&& next_pos.0 < w as isize
&& next_pos.1 >= 0
&& next_pos.1 < h as isize
&& map[next_pos.1 as usize][next_pos.0 as usize] != b' '
{
next_pos = (next_pos.0 - facing.0, next_pos.1 - facing.1);
}
next_pos = (next_pos.0 + facing.0, next_pos.1 + facing.1);
if map[next_pos.1 as usize][next_pos.0 as usize] != b'#' {
pos = next_pos;
} else {
#[cfg(debug_assertions)]
println!("pos: {} {}", pos.0, pos.1);
break;
}
} else {
#[cfg(debug_assertions)]
println!("pos: {} {}", pos.0, pos.1);
break;
}
}
}
(None, Some(rot)) => match rot {
1 => (facing.0, facing.1) = (-facing.1, facing.0),
-1 => (facing.0, facing.1) = (facing.1, -facing.0),
_ => unreachable!(),
},
_ => unreachable!(),
}
#[cfg(debug_assertions)]
println!(
"pos: ({}, {}), facing ({} {})",
pos.0, pos.1, facing.0, facing.1
);
}
let facing_dir = facing.0.abs() * (1 - facing.0) + facing.1.abs() * (1 - facing.1);
#[cfg(debug_assertions)]
println!(
"pos: ({}, {}), facing ({} {}) = {}",
pos.0 + 1,
pos.1 + 1,
facing.0,
facing.1,
facing_dir
);
print!("{} ", 1000 * (pos.1 + 1) + 4 * (pos.0 + 1) + facing_dir);
}

197
d22/part2.rs Normal file
View File

@ -0,0 +1,197 @@
use std::iter::repeat;
type Pos = (isize, isize);
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
struct Instruction {
dist: Option<isize>,
rotation: Option<isize>,
}
fn rotate(facing: Pos, by: isize) -> Pos {
match by.rem_euclid(4) {
0 => facing,
1 => (-facing.1, facing.0),
2 => (-facing.0, -facing.1),
3 => (facing.1, -facing.0),
_ => unreachable!(),
}
}
fn facing_angle_to_axes(facing: isize) -> Pos {
match facing.rem_euclid(4) {
0 => (1, 0),
1 => (0, 1),
2 => (-1, 0),
3 => (0, -1),
_ => unreachable!(),
}
}
fn next_pos_facing(
pos: Pos,
facing: Pos,
map: &Vec<Vec<u8>>,
edges: &Vec<(Vec<Pos>, Vec<Pos>, isize, isize)>,
) -> (Pos, Pos) {
let mut next_pos = (pos.0 + facing.0, pos.1 + facing.1);
let mut next_facing = facing;
for edge in edges.iter() {
if let Some(i) = edge.0.iter().position(|p| *p == pos) {
if facing_angle_to_axes(edge.2) == facing {
(next_pos, next_facing) = (edge.1[i], rotate(facing, (edge.3 + 2) - edge.2));
#[cfg(debug_assertions)]
println!(
"cross edge: {} {} ({} {}) -> {} {} ({} {})",
pos.0,
pos.1,
facing.0,
facing.1,
next_pos.0,
next_pos.1,
next_facing.0,
next_facing.1
);
}
} else if let Some(i) = edge.1.iter().position(|p| *p == pos) {
if facing_angle_to_axes(edge.3) == facing {
(next_pos, next_facing) = (edge.0[i], rotate(facing, (edge.2 + 2) - edge.3));
#[cfg(debug_assertions)]
println!(
"cross edge: {} {} ({} {}) -> {} {} ({} {})",
pos.0,
pos.1,
facing.0,
facing.1,
next_pos.0,
next_pos.1,
next_facing.0,
next_facing.1
);
}
}
}
(next_pos, next_facing)
}
pub fn main() {
let s = include_bytes!("./input");
let mut pos = (s.iter().position(|b| *b == b'.').unwrap() as isize, 0);
let mut facing: (isize, isize) = (1, 0);
let w = s
.split(|b| *b == b'\n')
.take_while(|l| !l.is_empty())
.map(|l| l.len())
.max()
.unwrap();
let map = s
.split(|b| *b == b'\n')
.take_while(|l| !l.is_empty())
.map(|l| {
l.iter()
.take(l.len())
.chain(repeat(&b' ').take(w - l.len()))
.copied()
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
let l = 50isize;
#[rustfmt::skip]
let edges: Vec<(Vec<Pos>, Vec<Pos>, isize, isize)> = vec![
((0..l).zip(repeat(l*2).take(l as usize)).collect(), repeat(l).take(l as usize).zip(l..l*2).collect(), 3, 2),
(repeat(0).take(l as usize).zip(l*2..l*3).collect(), repeat(l).take(l as usize).zip((0..l).rev()).collect(), 2, 2),
(repeat(0).take(l as usize).zip(l*3..l*4).collect(), (l..l*2).zip(repeat(0).take(l as usize)).collect(), 2, 3),
((0..l).zip(repeat(l*4-1).take(l as usize)).collect(), (l*2..l*3).zip(repeat(0).take(l as usize)).collect(), 1, 3),
(repeat(l-1).take(l as usize).zip(l*3..l*4).collect(), (l..l*2).zip(repeat(l*3-1).take(l as usize)).collect(), 0, 1),
(repeat(l*2-1).take(l as usize).zip(l*2..l*3).collect(), repeat(l*3-1).take(l as usize).zip((0..l).rev()).collect(), 0, 0),
(repeat(l*2-1).take(l as usize).zip(l..l*2).collect(), (l*2..l*3).zip(repeat(l-1).take(l as usize)).collect(), 0, 1),
];
let mut path: Vec<Instruction> = Vec::new();
let mut acc = 0;
s.split(|b| *b == b'\n')
.rev()
.nth(1)
.unwrap()
.iter()
.for_each(|b| match b {
b'0'..=b'9' => {
acc = acc * 10 + (b - b'0') as isize;
}
b'R' => {
path.push(Instruction {
dist: Some(acc),
rotation: None,
});
path.push(Instruction {
dist: None,
rotation: Some(1),
});
acc = 0;
}
b'L' => {
path.push(Instruction {
dist: Some(acc),
rotation: None,
});
path.push(Instruction {
dist: None,
rotation: Some(-1),
});
acc = 0;
}
_ => unreachable!(),
});
path.push(Instruction {
dist: Some(acc),
rotation: None,
});
#[cfg(debug_assertions)]
println!("{} {}", map.len(), map[0].len());
#[cfg(debug_assertions)]
println!(
"pos: ({}, {}), facing ({} {})",
pos.0, pos.1, facing.0, facing.1
);
for ins in path.iter() {
#[cfg(debug_assertions)]
println!("{:?}", ins);
match (ins.dist, ins.rotation) {
(Some(dist), None) => {
for _step in 0..dist {
let (next_pos, next_facing) = next_pos_facing(pos, facing, &map, &edges);
match map[next_pos.1 as usize][next_pos.0 as usize] {
b'#' => {
break;
}
b'.' => {
(pos, facing) = (next_pos, next_facing);
}
_ => {
panic!("unexpected wall as next character");
}
}
}
}
(None, Some(rot)) => {
(facing.0, facing.1) = rotate((facing.0, facing.1), rot);
}
_ => unreachable!(),
}
#[cfg(debug_assertions)]
println!(
"pos: ({}, {}), facing ({} {})",
pos.0, pos.1, facing.0, facing.1
);
}
let facing_dir = facing.0.abs() * (1 - facing.0) + facing.1.abs() * (2 - facing.1);
#[cfg(debug_assertions)]
println!(
"pos: ({}, {}), facing ({} {}) = {}",
pos.0 + 1,
pos.1 + 1,
facing.0,
facing.1,
facing_dir
);
print!("{} ", 1000 * (pos.1 + 1) + 4 * (pos.0 + 1) + facing_dir);
}