day23: problem 1 solution
This commit is contained in:
parent
d6d4c0d056
commit
98456ed98d
128
23/Cargo.lock
generated
Normal file
128
23/Cargo.lock
generated
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day23"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"ndarray",
|
||||||
|
"petgraph",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matrixmultiply"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ndarray"
|
||||||
|
version = "0.15.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32"
|
||||||
|
dependencies = [
|
||||||
|
"matrixmultiply",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset",
|
||||||
|
"indexmap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rawpointer"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
11
23/Cargo.toml
Normal file
11
23/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "day23"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itertools = "0.12.0"
|
||||||
|
ndarray = "0.15.6"
|
||||||
|
petgraph = "0.6.4"
|
236
23/src/main.rs
Normal file
236
23/src/main.rs
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
use itertools::Itertools;
|
||||||
|
use ndarray::prelude::*;
|
||||||
|
use petgraph::algo::all_simple_paths;
|
||||||
|
use petgraph::prelude::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::{Debug, Display, Write};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// BOILERPLATE
|
||||||
|
type InputIter = Lines<BufReader<File>>;
|
||||||
|
|
||||||
|
fn get_input() -> InputIter {
|
||||||
|
let f = File::open("input").unwrap();
|
||||||
|
let br = BufReader::new(f);
|
||||||
|
br.lines()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// PARSE
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum EdgeType {
|
||||||
|
FromPath,
|
||||||
|
FromSlope,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Node {
|
||||||
|
c: char,
|
||||||
|
pos: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Position = (usize, usize);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ForestMap {
|
||||||
|
map: Array2<char>,
|
||||||
|
indexes: HashMap<Position, NodeIndex>,
|
||||||
|
graph: DiGraph<Node, EdgeType>,
|
||||||
|
start: Position,
|
||||||
|
end: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
const ADJACENCIES: [(isize, isize); 4] = [(-1, 0), (1, 0), (0, -1), (0, 1)];
|
||||||
|
|
||||||
|
fn offset_pos(map: &Array2<char>, pos: Position, ofs: (isize, isize)) -> Option<Position> {
|
||||||
|
let new_pos = (pos.0 as isize + ofs.0, pos.1 as isize + ofs.1);
|
||||||
|
if new_pos.0 >= 0
|
||||||
|
&& new_pos.0 < map.len_of(Axis(0)) as isize
|
||||||
|
&& new_pos.1 >= 0
|
||||||
|
&& new_pos.1 < map.len_of(Axis(1)) as isize
|
||||||
|
{
|
||||||
|
Some((new_pos.0 as usize, new_pos.1 as usize))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adjacent_to(map: &Array2<char>, pos: Position) -> Vec<Position> {
|
||||||
|
ADJACENCIES
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ofs| offset_pos(map, pos, *ofs))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for ForestMap {
|
||||||
|
fn from(lines: Lines<T>) -> Self {
|
||||||
|
let rows = lines.map(|line| line.unwrap().chars().collect_vec()).collect_vec();
|
||||||
|
let map = Array::from_shape_vec([rows[0].len(), rows.len()], rows.into_iter().flatten().collect_vec())
|
||||||
|
.unwrap()
|
||||||
|
.reversed_axes();
|
||||||
|
let start = (map.slice(s![.., 0]).iter().position(|c| *c == '.').unwrap(), 0);
|
||||||
|
let end = (
|
||||||
|
map.slice(s![.., map.len_of(Axis(1)) - 1])
|
||||||
|
.iter()
|
||||||
|
.position(|c| *c == '.')
|
||||||
|
.unwrap(),
|
||||||
|
map.len_of(Axis(1)) - 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut graph = Graph::default();
|
||||||
|
let mut indexes = HashMap::new();
|
||||||
|
for (pos, c) in map.indexed_iter() {
|
||||||
|
if *c != '#' {
|
||||||
|
indexes.insert(pos, graph.add_node(Node { c: *c, pos }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (pos, c) in map.indexed_iter() {
|
||||||
|
match c {
|
||||||
|
'#' => continue,
|
||||||
|
'.' => {
|
||||||
|
adjacent_to(&map, pos).iter().for_each(|adj| {
|
||||||
|
if indexes.contains_key(&adj) {
|
||||||
|
graph.add_edge(indexes[&pos], indexes[adj], EdgeType::FromPath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
'^' => {
|
||||||
|
if let Some(adj) = offset_pos(&map, pos, (0, -1)) {
|
||||||
|
if indexes.contains_key(&adj) {
|
||||||
|
graph.add_edge(indexes[&pos], indexes[&adj], EdgeType::FromSlope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'>' => {
|
||||||
|
if let Some(adj) = offset_pos(&map, pos, (1, 0)) {
|
||||||
|
if indexes.contains_key(&adj) {
|
||||||
|
graph.add_edge(indexes[&pos], indexes[&adj], EdgeType::FromSlope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'v' => {
|
||||||
|
if let Some(adj) = offset_pos(&map, pos, (0, 1)) {
|
||||||
|
if indexes.contains_key(&adj) {
|
||||||
|
graph.add_edge(indexes[&pos], indexes[&adj], EdgeType::FromSlope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'<' => {
|
||||||
|
if let Some(adj) = offset_pos(&map, pos, (-1, 0)) {
|
||||||
|
if indexes.contains_key(&adj) {
|
||||||
|
graph.add_edge(indexes[&pos], indexes[&adj], EdgeType::FromSlope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c => panic!("invalid map character {}", c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
map,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
graph,
|
||||||
|
indexes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for ForestMap {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
for y in 0..self.map.len_of(Axis(1)) {
|
||||||
|
for c in self.map.index_axis(Axis(1), y) {
|
||||||
|
f.write_char(*c)?;
|
||||||
|
}
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
// println!("start: {:?} end: {:?}", self.start, self.end);
|
||||||
|
// println!("digraph aoc23 {{");
|
||||||
|
// for node in self.graph.node_indices() {
|
||||||
|
// println!(
|
||||||
|
// " \"{},{}\" -> {}",
|
||||||
|
// self.graph[node].pos.0,
|
||||||
|
// self.graph[node].pos.1,
|
||||||
|
// self.graph
|
||||||
|
// .neighbors(node)
|
||||||
|
// .map(|n| format!("\"{},{}\"", self.graph[n].pos.0, self.graph[n].pos.1))
|
||||||
|
// .join(",")
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// println!("}}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let map = ForestMap::from(input);
|
||||||
|
println!("{:?}", map);
|
||||||
|
let paths = all_simple_paths::<Vec<_>, _>(&map.graph, map.indexes[&map.start], map.indexes[&map.end], 0, None)
|
||||||
|
.collect_vec();
|
||||||
|
let longest = paths.iter().max_by_key(|path| path.len()).unwrap();
|
||||||
|
|
||||||
|
longest.len() as u64 - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"#.#####################
|
||||||
|
#.......#########...###
|
||||||
|
#######.#########.#.###
|
||||||
|
###.....#.>.>.###.#.###
|
||||||
|
###v#####.#v#.###.#.###
|
||||||
|
###.>...#.#.#.....#...#
|
||||||
|
###v###.#.#.#########.#
|
||||||
|
###...#.#.#.......#...#
|
||||||
|
#####.#.#.#######.#.###
|
||||||
|
#.....#.#.#.......#...#
|
||||||
|
#.#####.#.#.#########v#
|
||||||
|
#.#...#...#...###...>.#
|
||||||
|
#.#.#v#######v###.###v#
|
||||||
|
#...#.>.#...>.>.#.###.#
|
||||||
|
#####v#.#.###v#.#.###.#
|
||||||
|
#.....#...#...#.#.#...#
|
||||||
|
#.#########.###.#.#.###
|
||||||
|
#...###...#...#...#.###
|
||||||
|
###.###.#.###v#####v###
|
||||||
|
#...#...#.#.>.>.#.>.###
|
||||||
|
#.###.###.#.###.#.#v###
|
||||||
|
#.....###...###...#...#
|
||||||
|
#####################.#";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1(c.lines()), 94);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem2_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem2(c.lines()), 0);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user