Made my initial solution work

This commit is contained in:
Dreaded_X 2023-12-10 21:18:48 +01:00
parent 7734633c9f
commit 058653a3d9
Signed by: Dreaded_X
GPG Key ID: 5A0CBFE3C3377FAA

View File

@ -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),
Maze::NorthWest => {
if maybe == Some(Maze::SouthEast) {
in_loop = !in_loop
}
// 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::SouthWest => {
if maybe == Some(Maze::NorthEast) {
in_loop = !in_loop
}
}
Maze::Start => unreachable!("Start should have been replaced"),
}
} else if in_loop {
count += 1;
}
Maze::NorthEast => {
if clockwise {
vec![]
} else {
vec![(-1, 0), (0, 1)]
}
}
Maze::NorthWest => {
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 clockwise {
vec![]
} else {
vec![(0, -1), (1, 0)]
}
}
Maze::SouthEast => {
if clockwise {
vec![(0, -1), (-1, 0)]
} else {
vec![]
}
}
_ => 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()
// }
}