Made my initial solution work
This commit is contained in:
parent
7734633c9f
commit
058653a3d9
|
@ -1,6 +1,6 @@
|
|||
#![feature(test)]
|
||||
use core::panic;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
use anyhow::Result;
|
||||
use aoc::Solver;
|
||||
|
@ -180,46 +180,51 @@ impl Maze {
|
|||
}
|
||||
}
|
||||
|
||||
// #[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
// enum Loop {
|
||||
// North,
|
||||
// East,
|
||||
// South,
|
||||
// West,
|
||||
// Inner,
|
||||
// }
|
||||
//
|
||||
// impl Loop {
|
||||
// fn from(direction: (isize, isize)) -> Self {
|
||||
// match direction {
|
||||
// (0, -1) => Self::North,
|
||||
// (1, 0) => Self::East,
|
||||
// (0, 1) => Self::South,
|
||||
// (-1, 0) => Self::West,
|
||||
// _ => unreachable!("Invalid direction"),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fn offset(&self) -> (isize, isize) {
|
||||
// match self {
|
||||
// Loop::North => (0, -1),
|
||||
// Loop::East => (1, 0),
|
||||
// Loop::South => (0, 1),
|
||||
// Loop::West => (-1, 0),
|
||||
// Loop::Inner => (0, 0),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fn flood_fill(position: (isize, isize), map: &mut HashMap<(isize, isize), Loop>) {
|
||||
// if map.get(&position).is_none() {
|
||||
// map.insert(position, Loop::Inner);
|
||||
//
|
||||
// for direction in DIRECTIONS {
|
||||
// flood_fill((position.0 + direction.0, position.1 + direction.1), map)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
enum Loop {
|
||||
North,
|
||||
East,
|
||||
South,
|
||||
West,
|
||||
Inner,
|
||||
}
|
||||
|
||||
impl Loop {
|
||||
fn from(direction: (isize, isize)) -> Self {
|
||||
match direction {
|
||||
(0, -1) => Self::North,
|
||||
(1, 0) => Self::East,
|
||||
(0, 1) => Self::South,
|
||||
(-1, 0) => Self::West,
|
||||
_ => unreachable!("Invalid direction"),
|
||||
}
|
||||
}
|
||||
|
||||
fn offset(&self) -> (isize, isize) {
|
||||
match self {
|
||||
Loop::North => (0, -1),
|
||||
Loop::East => (1, 0),
|
||||
Loop::South => (0, 1),
|
||||
Loop::West => (-1, 0),
|
||||
Loop::Inner => (0, 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flood_fill(position: (isize, isize), map: &mut HashMap<(isize, isize), Loop>) {
|
||||
let mut queue = VecDeque::new();
|
||||
queue.push_back(position);
|
||||
|
||||
while let Some(position) = queue.pop_front() {
|
||||
if map.get(&position).is_none() {
|
||||
map.insert(position, Loop::Inner);
|
||||
|
||||
for direction in DIRECTIONS {
|
||||
queue.push_back((position.0 + direction.0, position.1 + direction.1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static DIRECTIONS: [(isize, isize); 4] = [(0, -1), (1, 0), (0, 1), (-1, 0)];
|
||||
|
||||
|
@ -292,10 +297,11 @@ impl aoc::Solver for Day {
|
|||
}
|
||||
}
|
||||
|
||||
// Alternate solution that works for the examples and is off-by-one for the actual input
|
||||
fn part2(input: &str) -> Self::Output2 {
|
||||
let mut position_start = (-1, -1);
|
||||
|
||||
let maze: HashMap<(isize, isize), Maze> = input
|
||||
let end_direction;
|
||||
let mut maze: HashMap<(isize, isize), Maze> = input
|
||||
.lines()
|
||||
.enumerate()
|
||||
.flat_map(|(y, line)| {
|
||||
|
@ -311,11 +317,13 @@ impl aoc::Solver for Day {
|
|||
})
|
||||
.collect();
|
||||
|
||||
let mut map = HashMap::new();
|
||||
|
||||
if position_start == (-1, -1) {
|
||||
panic!("No valid start in input");
|
||||
}
|
||||
|
||||
let mut map = HashMap::<(isize, isize), Maze>::new();
|
||||
let mut sides = (0, 0);
|
||||
|
||||
let mut position_current = position_start;
|
||||
let mut position_previous = position_start;
|
||||
|
@ -335,12 +343,17 @@ impl aoc::Solver for Day {
|
|||
|
||||
if let Some(tile_next) = maze.get(&position_next) {
|
||||
if tile_current.connects(tile_next, direction) {
|
||||
map.insert(position_current, *tile_current);
|
||||
map.insert(position_current, Loop::from(direction));
|
||||
|
||||
position_previous = position_current;
|
||||
position_current = position_next;
|
||||
|
||||
let s = tile_current.sides(direction);
|
||||
sides.0 += s.0;
|
||||
sides.1 += s.1;
|
||||
|
||||
if position_current == position_start {
|
||||
end_direction = Loop::from(direction);
|
||||
break 'outer;
|
||||
}
|
||||
|
||||
|
@ -352,165 +365,151 @@ impl aoc::Solver for Day {
|
|||
unreachable!("Unable to move forward...");
|
||||
}
|
||||
|
||||
// It appears that the start can always be replaced with an F
|
||||
// Atleast in all the examples and my input
|
||||
map.insert(position_start, Maze::SouthEast);
|
||||
// Replace the start with the correct piece
|
||||
let start = match (end_direction, map.get(&position_start).unwrap()) {
|
||||
(Loop::North, Loop::North) | (Loop::South, Loop::South) => Maze::Vertical,
|
||||
(Loop::East, Loop::East) | (Loop::West, Loop::West) => Maze::Horizontal,
|
||||
(Loop::South, Loop::East) | (Loop::West, Loop::North) => Maze::NorthEast,
|
||||
(Loop::South, Loop::West) | (Loop::East, Loop::North) => Maze::NorthWest,
|
||||
(Loop::East, Loop::South) | (Loop::North, Loop::West) => Maze::SouthWest,
|
||||
(Loop::North, Loop::East) | (Loop::West, Loop::South) => Maze::SouthEast,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
maze.insert(position_start, start);
|
||||
|
||||
let bounds = (
|
||||
input.lines().map(|line| line.len()).max().unwrap(),
|
||||
input.lines().count(),
|
||||
);
|
||||
// Add the sides of the start
|
||||
let start_sides = start.sides(map.get(&position_start).unwrap().offset());
|
||||
sides.0 += start_sides.0;
|
||||
sides.1 += start_sides.1;
|
||||
|
||||
let mut count = 0;
|
||||
let mut in_loop = false;
|
||||
let mut maybe = None;
|
||||
for y in 0..bounds.1 {
|
||||
for x in 0..bounds.0 {
|
||||
if let Some(entry) = map.get(&(x as isize, y as isize)) {
|
||||
match entry {
|
||||
Maze::Vertical => in_loop = !in_loop,
|
||||
Maze::Horizontal => {}
|
||||
dir @ (Maze::NorthEast | Maze::SouthEast) => maybe = Some(*dir),
|
||||
// Determine if the loop was travelled clockwise or anti clockwise
|
||||
let clockwise = sides.0 > sides.1;
|
||||
|
||||
let mut position_current = position_start;
|
||||
loop {
|
||||
let &direction = map.get(&position_current).unwrap();
|
||||
let tile = maze.get(&position_current).unwrap();
|
||||
|
||||
// Get neighbouring tiles that are inside of the loop
|
||||
let checks = match direction {
|
||||
Loop::North => match tile {
|
||||
Maze::Vertical => {
|
||||
if clockwise {
|
||||
vec![(1, 0)]
|
||||
} else {
|
||||
vec![(-1, 0)]
|
||||
}
|
||||
}
|
||||
Maze::NorthEast => {
|
||||
if clockwise {
|
||||
vec![]
|
||||
} else {
|
||||
vec![(-1, 0), (0, 1)]
|
||||
}
|
||||
}
|
||||
Maze::NorthWest => {
|
||||
if maybe == Some(Maze::SouthEast) {
|
||||
in_loop = !in_loop
|
||||
if clockwise {
|
||||
vec![(1, 0), (0, 1)]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Loop::East => match tile {
|
||||
Maze::Horizontal => {
|
||||
if clockwise {
|
||||
vec![(0, 1)]
|
||||
} else {
|
||||
vec![(0, -1)]
|
||||
}
|
||||
}
|
||||
Maze::NorthEast => {
|
||||
if clockwise {
|
||||
vec![(-1, 0), (0, 1)]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
Maze::SouthEast => {
|
||||
if clockwise {
|
||||
vec![]
|
||||
} else {
|
||||
vec![(-1, 0), (0, -1)]
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Loop::South => match tile {
|
||||
Maze::Vertical => {
|
||||
if clockwise {
|
||||
vec![(-1, 0)]
|
||||
} else {
|
||||
vec![(1, 0)]
|
||||
}
|
||||
}
|
||||
Maze::SouthWest => {
|
||||
if maybe == Some(Maze::NorthEast) {
|
||||
in_loop = !in_loop
|
||||
if clockwise {
|
||||
vec![]
|
||||
} else {
|
||||
vec![(0, -1), (1, 0)]
|
||||
}
|
||||
}
|
||||
Maze::Start => unreachable!("Start should have been replaced"),
|
||||
Maze::SouthEast => {
|
||||
if clockwise {
|
||||
vec![(0, -1), (-1, 0)]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
} else if in_loop {
|
||||
count += 1;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Loop::West => match tile {
|
||||
Maze::Horizontal => {
|
||||
if clockwise {
|
||||
vec![(0, -1)]
|
||||
} else {
|
||||
vec![(0, 1)]
|
||||
}
|
||||
}
|
||||
Maze::NorthWest => {
|
||||
if clockwise {
|
||||
vec![]
|
||||
} else {
|
||||
vec![(1, 0), (0, 1)]
|
||||
}
|
||||
}
|
||||
Maze::SouthWest => {
|
||||
if clockwise {
|
||||
vec![(1, 0), (0, -1)]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Loop::Inner => unreachable!("Loop should not contain Inner"),
|
||||
};
|
||||
|
||||
// Perform a floodfill from those neighbouring tiles
|
||||
for check in checks {
|
||||
let check = (position_current.0 + check.0, position_current.1 + check.1);
|
||||
flood_fill(check, &mut map);
|
||||
}
|
||||
|
||||
let direction = direction.offset();
|
||||
|
||||
position_current.0 += direction.0;
|
||||
position_current.1 += direction.1;
|
||||
|
||||
if position_current == position_start {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
count
|
||||
// Count how many tiles are marked as inner
|
||||
map.iter()
|
||||
.filter(|(_, &value)| value == Loop::Inner)
|
||||
.count()
|
||||
}
|
||||
|
||||
// Alternate solution that works for the examples and is off-by-one for the actual input
|
||||
// fn part2(input: &str) -> Self::Output2 {
|
||||
// let mut position_start = (-1, -1);
|
||||
// let maze: HashMap<(isize, isize), Maze> = input
|
||||
// .lines()
|
||||
// .enumerate()
|
||||
// .flat_map(|(y, line)| {
|
||||
// line.chars()
|
||||
// .enumerate()
|
||||
// .filter_map(|(x, c)| Maze::from(c).map(|maze| ((x as isize, y as isize), maze)))
|
||||
// .inspect(|(position, maze)| {
|
||||
// if *maze == Maze::Start {
|
||||
// position_start = *position
|
||||
// }
|
||||
// })
|
||||
// .collect::<Vec<_>>()
|
||||
// })
|
||||
// .collect();
|
||||
//
|
||||
// let mut map = HashMap::<(isize, isize), Loop>::new();
|
||||
//
|
||||
// if position_start == (-1, -1) {
|
||||
// panic!("No valid start in input");
|
||||
// }
|
||||
//
|
||||
// let mut sides = (0, 0);
|
||||
//
|
||||
// let mut position_current = position_start;
|
||||
// let mut position_previous = position_start;
|
||||
// 'outer: loop {
|
||||
// let tile_current = maze.get(&position_current).unwrap();
|
||||
//
|
||||
// for direction in DIRECTIONS {
|
||||
// let position_next = (
|
||||
// position_current.0 + direction.0,
|
||||
// position_current.1 + direction.1,
|
||||
// );
|
||||
//
|
||||
// // We are now allowed to go back to the previous position
|
||||
// if position_next == position_previous {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// if let Some(tile_next) = maze.get(&position_next) {
|
||||
// if tile_current.connects(tile_next, direction) {
|
||||
// map.insert(position_current, Loop::from(direction));
|
||||
//
|
||||
// position_previous = position_current;
|
||||
// position_current = position_next;
|
||||
//
|
||||
// let s = tile_current.sides(direction);
|
||||
// sides.0 += s.0;
|
||||
// sides.1 += s.1;
|
||||
//
|
||||
// if position_current == position_start {
|
||||
// break 'outer;
|
||||
// }
|
||||
//
|
||||
// continue 'outer;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// unreachable!("Unable to move forward...");
|
||||
// }
|
||||
//
|
||||
// let clockwise = sides.0 > sides.1;
|
||||
//
|
||||
// let mut position_current = position_start;
|
||||
// loop {
|
||||
// let &direction = map.get(&position_current).unwrap();
|
||||
//
|
||||
// let check = match direction {
|
||||
// Loop::North => {
|
||||
// if clockwise {
|
||||
// (1, 0)
|
||||
// } else {
|
||||
// (-1, 0)
|
||||
// }
|
||||
// }
|
||||
// Loop::East => {
|
||||
// if clockwise {
|
||||
// (0, 1)
|
||||
// } else {
|
||||
// (0, -1)
|
||||
// }
|
||||
// }
|
||||
// Loop::South => {
|
||||
// if clockwise {
|
||||
// (-1, 0)
|
||||
// } else {
|
||||
// (1, 0)
|
||||
// }
|
||||
// }
|
||||
// Loop::West => {
|
||||
// if clockwise {
|
||||
// (0, -1)
|
||||
// } else {
|
||||
// (0, 1)
|
||||
// }
|
||||
// }
|
||||
// Loop::Inner => unreachable!("Loop should not contain Inner"),
|
||||
// };
|
||||
// let check = (position_current.0 + check.0, position_current.1 + check.1);
|
||||
//
|
||||
// flood_fill(check, &mut map);
|
||||
//
|
||||
// let direction = direction.offset();
|
||||
//
|
||||
// position_current.0 += direction.0;
|
||||
// position_current.1 += direction.1;
|
||||
//
|
||||
// if position_current == position_start {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// map.iter()
|
||||
// .filter(|(_, &value)| value == Loop::Inner)
|
||||
// .count()
|
||||
// }
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user