This commit is contained in:
sepia 2024-12-06 11:59:10 -06:00
parent 41383492f5
commit 7a0c38afb0
2 changed files with 184 additions and 1 deletions

182
src/day6.rs Normal file
View File

@ -0,0 +1,182 @@
pub fn day6() {
let input = crate::input(6);
let (world, cursor_location) = World::from_string(&input);
let start = Transform::new(
cursor_location.0,
cursor_location.1,
Direction::North,
&world,
);
let mut path = traverse(start).unwrap();
path.sort_by(|a, b| {
if a.x == b.x {
a.y.cmp(&b.y)
} else {
a.x.cmp(&b.x)
}
});
path.dedup_by(|a, b| a.x == b.x && a.y == b.y);
let total_traveled = path.len();
let loops = path
.iter()
.filter(|p| {
let mut new_world = world.clone();
new_world.map[p.y][p.x] = Terrain::Blocked;
let start = Transform::new(start.x, start.y, start.direction, &new_world);
traverse(start).is_none()
})
.count();
println!("Total Travelled: {}", total_traveled);
println!("Total Loopable Positions: {}", loops);
}
#[derive(Copy, Clone)]
struct Transform<'a> {
x: usize,
y: usize,
direction: Direction,
world: &'a World,
}
impl<'a> Transform<'a> {
fn new(x: usize, y: usize, direction: Direction, world: &'a World) -> Self {
Self {
x,
y,
direction,
world,
}
}
fn turn(&self) -> Self {
Self {
x: self.x,
y: self.y,
direction: self.direction.turn(),
world: self.world,
}
}
fn travel(&self) -> Option<Self> {
let t = match self.direction {
Direction::North => Some(Self {
x: self.x,
y: self.y.checked_sub(1)?,
direction: self.direction,
world: self.world,
}),
Direction::South => Some(Self {
x: self.x,
y: self.y.checked_add(1)?,
direction: self.direction,
world: self.world,
}),
Direction::East => Some(Self {
x: self.x.checked_add(1)?,
y: self.y,
direction: self.direction,
world: self.world,
}),
Direction::West => Some(Self {
x: self.x.checked_sub(1)?,
y: self.y,
direction: self.direction,
world: self.world,
}),
}?;
if t.y >= t.world.map.len() || t.x >= t.world.map[0].len() {
return None;
};
if self.world.terrain_at(&t) == Terrain::Blocked {
Some(self.turn())
} else {
Some(t)
}
}
}
#[derive(Clone)]
struct World {
map: Vec<Vec<Terrain>>,
}
impl World {
fn from_string(input: &str) -> (Self, (usize, usize)) {
let mut map: Vec<Vec<Terrain>> = Vec::new();
let mut cursor: (usize, usize) = (0, 0);
for (y, line) in input.lines().enumerate() {
let row: Vec<Terrain> = line
.chars()
.map(|c| match c {
'#' => Terrain::Blocked,
_ => Terrain::Free,
})
.collect();
map.push(row);
if let Some(x) = line.find('^') {
cursor = (x, y);
};
}
(Self { map }, cursor)
}
fn terrain_at(&self, at: &Transform) -> Terrain {
self.map[at.y][at.x]
}
}
fn traverse<'a>(start: Transform<'a>) -> Option<Vec<Transform<'a>>> {
let mut cursor = start;
let mut traversed: Vec<Transform> = vec![cursor];
while let Some(new_cursor) = cursor.travel() {
if traversed.contains(&new_cursor) {
return None;
}
cursor = new_cursor;
traversed.push(cursor);
}
Some(traversed)
}
#[derive(PartialEq, Eq, Copy, Clone)]
enum Terrain {
Free,
Blocked,
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
enum Direction {
North,
South,
East,
West,
}
impl Direction {
fn turn(&self) -> Self {
match self {
Self::North => Self::East,
Self::East => Self::South,
Self::South => Self::West,
Self::West => Self::North,
}
}
}
impl<'a> PartialEq for Transform<'a> {
fn eq(&self, other: &Self) -> bool {
self.x == other.x
&& self.y == other.y
&& self.direction == other.direction
&& std::ptr::eq(self.world, other.world)
}
}
impl<'a> Eq for Transform<'a> {}

View File

@ -3,9 +3,10 @@ mod day2;
mod day3;
mod day4;
mod day5;
mod day6;
fn main() {
day5::day5();
day6::day6();
}
pub fn input(day: u8) -> String {