From 6869a0fc1d55bc67245d98769dbda4204ed532fd Mon Sep 17 00:00:00 2001 From: Simon Martin Date: Fri, 22 Dec 2023 08:51:03 +0000 Subject: [PATCH 1/3] Day 23 init --- Cargo.toml | 2 +- day23/Cargo.toml | 16 +++++++++++++ day23/src/lib.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++ day23/src/main.rs | 8 +++++++ 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 day23/Cargo.toml create mode 100644 day23/src/lib.rs create mode 100644 day23/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 91ba807..cb3a1f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ members = [ "template", "xtask", "day1" -, "day2", "day3", "day4", "day5", "day6", "day7", "day8", "day9", "day10", "day11", "day12", "day13", "day14", "day15", "day16", "day17", "day18", "day19", "day20", "day21", "day22"] +, "day2", "day3", "day4", "day5", "day6", "day7", "day8", "day9", "day10", "day11", "day12", "day13", "day14", "day15", "day16", "day17", "day18", "day19", "day20", "day21", "day22", "day23"] [workspace.dependencies] # Flexible concrete Error type built on std::error::Error diff --git a/day23/Cargo.toml b/day23/Cargo.toml new file mode 100644 index 0000000..3f024cf --- /dev/null +++ b/day23/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "day23" +version = "0.1.0" +edition = "2021" + +[dependencies] +tracing = {workspace = true} +tracing-test = {workspace = true} +anyhow = {workspace = true} +regex = {workspace = true} +lazy_static = {workspace = true} +pathfinding = {workspace = true} +itertools = {workspace = true} + +[dependencies.utils] +path = "../utils" \ No newline at end of file diff --git a/day23/src/lib.rs b/day23/src/lib.rs new file mode 100644 index 0000000..f7c6172 --- /dev/null +++ b/day23/src/lib.rs @@ -0,0 +1,57 @@ +use std::io::{BufRead, BufReader}; +use tracing::{debug, event_enabled, info, Level}; + +pub type ResultType = u64; + +#[derive(Debug, Default)] +pub struct Solution { + +} +impl Solution { + +} + +impl TryFrom> for Solution { + type Error = std::io::Error; + + fn try_from(reader: BufReader) -> Result { + let mut solution = Self::default(); + for (id, line) in reader.lines().map_while(Result::ok).enumerate() { + // Implement for problem + + } + Ok(solution) + } +} +impl utils::Solution for Solution { + type Result = anyhow::Result; + fn analyse(&mut self, _is_full: bool) {} + + fn answer_part1(&self, _is_full: bool) -> Self::Result { + // Implement for problem + Ok(0) + } + + fn answer_part2(&self, _is_full: bool) -> Self::Result { + // Implement for problem + Ok(0) + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::io::BufReader; + + use tracing_test::traced_test; + use utils::Solution; + + #[test] + #[traced_test] + fn read() { + let input = "replace for problem"; + let r = BufReader::new(input.as_bytes()); + let s = crate::Solution::try_from(r).unwrap(); + assert_eq!(0 as ResultType, s.answer_part1(false).unwrap()); + } +} diff --git a/day23/src/main.rs b/day23/src/main.rs new file mode 100644 index 0000000..da1a3c9 --- /dev/null +++ b/day23/src/main.rs @@ -0,0 +1,8 @@ +use anyhow::Result; +use day23::{ResultType, Solution}; + +fn main() -> Result<()> { + utils::log_init(); + + utils::run::(&["sample"], &["full"]) +} From 0f53fc3b8ce4b0c3b5ae73c723bd115e184a75dd Mon Sep 17 00:00:00 2001 From: Simon Martin Date: Sat, 23 Dec 2023 07:12:01 +0000 Subject: [PATCH 2/3] Day 23 complete (non halting) --- day23/src/lib.rs | 173 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 165 insertions(+), 8 deletions(-) diff --git a/day23/src/lib.rs b/day23/src/lib.rs index f7c6172..61b83f5 100644 --- a/day23/src/lib.rs +++ b/day23/src/lib.rs @@ -1,14 +1,20 @@ -use std::io::{BufRead, BufReader}; -use tracing::{debug, event_enabled, info, Level}; +use std::{ + collections::{HashMap, HashSet}, + io::{BufRead, BufReader}, +}; +use tracing::{debug, info}; +use utils::Matrix; pub type ResultType = u64; #[derive(Debug, Default)] pub struct Solution { - + tiles: Matrix, } impl Solution { - + fn set_tile(&mut self, x: usize, y: usize, c: char) { + self.tiles.set(x as isize, y as isize, c); + } } impl TryFrom> for Solution { @@ -16,25 +22,176 @@ impl TryFrom> for Solution { fn try_from(reader: BufReader) -> Result { let mut solution = Self::default(); - for (id, line) in reader.lines().map_while(Result::ok).enumerate() { + for (y, line) in reader.lines().map_while(Result::ok).enumerate() { // Implement for problem - + for (x, c) in line.chars().enumerate() { + solution.set_tile(x, y, c); + } } Ok(solution) } } +impl Solution { + fn longest_path( + &self, + sx: isize, + sy: isize, + ex: isize, + ey: isize, + ignore_slopes: bool, + ) -> ResultType { + let mut max = 0; + let mut remaining = Vec::new(); + remaining.push((sx, sy, 0, HashSet::new())); + while let Some((x, y, d, visited)) = remaining.pop() { + if x == ex && y == ey { + max = std::cmp::max(max, d); + debug!(max, d, "end"); + continue; + } + // Which directions can walk? + let directions = if ignore_slopes { + vec![(0, 1), (0, -1), (1, 0), (-1, 0)] + } else { + match self.tiles.get(x, y).unwrap_or(&'#') { + '.' => vec![(0, 1), (0, -1), (1, 0), (-1, 0)], + '>' => vec![(1, 0)], + '<' => vec![(-1, 0)], + '^' => vec![(0, -1)], + 'v' => vec![(0, 1)], + '#' => panic!("standing in a tree"), + c => panic!("unexpected {c}"), + } + }; + for (dx, dy) in directions { + if !visited.contains(&(x + dx, y + dy)) { + match self.tiles.get(x + dx, y + dy).unwrap_or(&'#') { + '#' => {} + '.' | '>' | 'v' | '<' | '^' => { + let mut n_visited = visited.clone(); + n_visited.insert((x + dx, y + dy)); + remaining.push((x + dx, y + dy, d + 1, n_visited)); + } + c => panic!("unexpected {c}"), + } + } + } + } + max + } + + fn longest_path_part2(&self, sx: isize, sy: isize, ex: isize, ey: isize) -> ResultType { + let mut adjacency = HashMap::new(); + let (max_x, max_y) = self.tiles.dimensions(); + for y in 0..=max_y { + for x in 0..=max_x { + if !matches!(self.tiles.get(x, y).unwrap_or(&'#'), '#') { + let r = adjacency.entry((x, y)).or_insert_with(HashMap::new); + for (dx, dy) in [(0, 1), (0, -1), (1, 0), (-1, 0)] { + if !matches!(self.tiles.get(x + dx, y + dy).unwrap_or(&'#'), '#') { + r.insert((x + dx, y + dy), 1); + } + } + } + } + } + let mut num_compact = 0; + let keys = adjacency.keys().cloned().collect::>(); + for node in keys { + let neighbours: HashMap<(isize, isize), i32> = adjacency.get(&node).unwrap().clone(); + if neighbours.len() != 2 { + continue; + } + num_compact += 1; + // remove 'node' from both neighbours + for (neigh, d) in neighbours.iter() { + let other = neighbours + .iter() + .find(|(other, _)| other.0 != neigh.0 || other.1 != neigh.1) + .unwrap(); + let n: &mut HashMap<(isize, isize), i32> = + adjacency.get_mut(&(neigh.0, neigh.1)).unwrap(); + n.remove(&node); + n.insert(*other.0, other.1 + d); + } + adjacency.remove(&node); + } + debug!(adjacency = debug(&adjacency), num_compact, "adj"); + + let mut max = 0; + let mut remaining = Vec::new(); + remaining.push(((sx, sy), 0, HashSet::new())); + while let Some(((x, y), d, visited)) = remaining.pop() { + if x == ex && y == ey { + if max < d { + info!(max, d, "end"); + max = d; + } + continue; + } + // Which directions can walk? + let neighbours = adjacency.get(&(x, y)).unwrap(); + for (neighbour, len) in neighbours { + if !visited.contains(&neighbour) { + let mut n_visited = visited.clone(); + n_visited.insert(neighbour); + remaining.push((*neighbour, d + len, n_visited)); + } + } + } + max as ResultType + } +} impl utils::Solution for Solution { type Result = anyhow::Result; fn analyse(&mut self, _is_full: bool) {} fn answer_part1(&self, _is_full: bool) -> Self::Result { + // Find start & end + let (max_x, max_y) = self.tiles.dimensions(); + let start = (0..=max_x) + .map(|x| (x, self.tiles.get(x, 0).unwrap_or(&'#'))) + .find(|(_, c)| *c == &'.') + .unwrap() + .0; + let end = (0..=max_x) + .map(|x| (x, self.tiles.get(x, max_y).unwrap_or(&'#'))) + .find(|(_, c)| *c == &'.') + .unwrap() + .0; + + debug!(start, end, "s"); + + let r = self.longest_path(start, 0, end, max_y, false); + debug!(r, "done?"); // Implement for problem - Ok(0) + Ok(r) } fn answer_part2(&self, _is_full: bool) -> Self::Result { + // Find start & end + let (max_x, max_y) = self.tiles.dimensions(); + let start = (0..=max_x) + .map(|x| (x, self.tiles.get(x, 0).unwrap_or(&'#'))) + .find(|(_, c)| *c == &'.') + .unwrap() + .0; + let end = (0..=max_x) + .map(|x| (x, self.tiles.get(x, max_y).unwrap_or(&'#'))) + .find(|(_, c)| *c == &'.') + .unwrap() + .0; + + debug!(start, end, "s"); + + let r = self.longest_path_part2(start, 0, end, max_y); + debug!(r, "done?"); + let r = self.longest_path(start, 0, end, max_y, true); + debug!(r, "done?"); // Implement for problem - Ok(0) + // TOO Low: 6282 + // Did not end, but answer = 6574 + Ok(r) } } From 8d19d637de5eaf4b8f2dfac16cb98fd6220c15c2 Mon Sep 17 00:00:00 2001 From: Simon Martin Date: Sat, 23 Dec 2023 07:16:33 +0000 Subject: [PATCH 3/3] Code cleanup --- day23/src/lib.rs | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/day23/src/lib.rs b/day23/src/lib.rs index 61b83f5..e0e72d7 100644 --- a/day23/src/lib.rs +++ b/day23/src/lib.rs @@ -2,7 +2,7 @@ use std::{ collections::{HashMap, HashSet}, io::{BufRead, BufReader}, }; -use tracing::{debug, info}; +use tracing::debug; use utils::Matrix; pub type ResultType = u64; @@ -124,7 +124,7 @@ impl Solution { while let Some(((x, y), d, visited)) = remaining.pop() { if x == ex && y == ey { if max < d { - info!(max, d, "end"); + debug!(max, d, "end"); max = d; } continue; @@ -133,9 +133,9 @@ impl Solution { let neighbours = adjacency.get(&(x, y)).unwrap(); for (neighbour, len) in neighbours { if !visited.contains(&neighbour) { - let mut n_visited = visited.clone(); - n_visited.insert(neighbour); - remaining.push((*neighbour, d + len, n_visited)); + let mut n_visited = visited.clone(); + n_visited.insert(neighbour); + remaining.push((*neighbour, d + len, n_visited)); } } } @@ -186,29 +186,9 @@ impl utils::Solution for Solution { let r = self.longest_path_part2(start, 0, end, max_y); debug!(r, "done?"); - let r = self.longest_path(start, 0, end, max_y, true); - debug!(r, "done?"); // Implement for problem // TOO Low: 6282 // Did not end, but answer = 6574 Ok(r) } } - -#[cfg(test)] -mod test { - use super::*; - use std::io::BufReader; - - use tracing_test::traced_test; - use utils::Solution; - - #[test] - #[traced_test] - fn read() { - let input = "replace for problem"; - let r = BufReader::new(input.as_bytes()); - let s = crate::Solution::try_from(r).unwrap(); - assert_eq!(0 as ResultType, s.answer_part1(false).unwrap()); - } -}