Day 6
This commit is contained in:
parent
41383492f5
commit
7a0c38afb0
|
@ -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> {}
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue