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 day3;
|
||||||
mod day4;
|
mod day4;
|
||||||
mod day5;
|
mod day5;
|
||||||
|
mod day6;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
day5::day5();
|
day6::day6();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(day: u8) -> String {
|
pub fn input(day: u8) -> String {
|
||||||
|
|
Loading…
Reference in New Issue