Simple Path

This commit is contained in:
hal8174 2023-12-07 14:01:31 +01:00
parent 7d47a10acf
commit 6f6a7f978b
6 changed files with 333 additions and 161 deletions

162
Cargo.lock generated
View file

@ -43,7 +43,7 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [ dependencies = [
"windows-sys", "windows-sys 0.48.0",
] ]
[[package]] [[package]]
@ -53,7 +53,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"windows-sys", "windows-sys 0.48.0",
] ]
[[package]] [[package]]
@ -62,6 +62,12 @@ version = "0.21.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
[[package]]
name = "bitflags"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -114,6 +120,17 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "colored"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6"
dependencies = [
"is-terminal",
"lazy_static",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.3.2" version = "1.3.2"
@ -123,12 +140,23 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "errno"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "factorio_blueprint" name = "factorio_blueprint"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"base64", "base64",
"clap", "clap",
"colored",
"flate2", "flate2",
"serde", "serde",
"serde_json", "serde_json",
@ -150,12 +178,47 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
[[package]]
name = "is-terminal"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"rustix",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.9" version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "linux-raw-sys"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.7.1" version = "0.7.1"
@ -183,6 +246,19 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rustix"
version = "0.38.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.15" version = "1.0.15"
@ -255,7 +331,16 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [ dependencies = [
"windows-targets", "windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.0",
] ]
[[package]] [[package]]
@ -264,13 +349,28 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc", "windows_aarch64_msvc 0.48.5",
"windows_i686_gnu", "windows_i686_gnu 0.48.5",
"windows_i686_msvc", "windows_i686_msvc 0.48.5",
"windows_x86_64_gnu", "windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc", "windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [
"windows_aarch64_gnullvm 0.52.0",
"windows_aarch64_msvc 0.52.0",
"windows_i686_gnu 0.52.0",
"windows_i686_msvc 0.52.0",
"windows_x86_64_gnu 0.52.0",
"windows_x86_64_gnullvm 0.52.0",
"windows_x86_64_msvc 0.52.0",
] ]
[[package]] [[package]]
@ -279,38 +379,80 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.48.5" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.48.5" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.48.5" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.48.5" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.48.5" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.48.5" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"

View file

@ -8,6 +8,7 @@ edition = "2021"
[dependencies] [dependencies]
base64 = "0.21.5" base64 = "0.21.5"
clap = { version = "4.4.8", features = ["derive"] } clap = { version = "4.4.8", features = ["derive"] }
colored = "2.0.4"
flate2 = "1.0.28" flate2 = "1.0.28"
serde = { version = "1.0.192", features = ["derive"] } serde = { version = "1.0.192", features = ["derive"] }
serde_json = "1.0.108" serde_json = "1.0.108"

View file

@ -1,14 +0,0 @@
use factorio_blueprint::{
belt_finding::{find_path, Field, Position, QueueObject},
misc::Map,
priority_queue::BinaryHeap,
};
fn main() {
let mut map: Map<Field> = Map::new(5, 5);
map.get_mut(2, 0).blocked = true;
map.get_mut(2, 1).blocked = true;
map.get_mut(2, 2).blocked = true;
find_path::<BinaryHeap<QueueObject>>(map, Position { x: 0, y: 0 }, Position { x: 4, y: 0 });
}

39
examples/solve_belt.rs Normal file
View file

@ -0,0 +1,39 @@
use factorio_blueprint::belt_finding::{Position, Problem};
fn main() {
let mut p = Problem::new(17, 13, Position::new(3, 8), Position::new(13, 5));
p.set_blocked(0, 3, true);
p.set_blocked(1, 4, true);
p.set_blocked(2, 4, true);
p.set_blocked(1, 5, true);
p.set_blocked(2, 5, true);
p.set_blocked(1, 7, true);
p.set_blocked(2, 7, true);
p.set_blocked(1, 8, true);
p.set_blocked(2, 8, true);
p.set_blocked(0, 9, true);
p.set_blocked(16, 3, true);
p.set_blocked(14, 4, true);
p.set_blocked(15, 4, true);
p.set_blocked(14, 5, true);
p.set_blocked(15, 5, true);
p.set_blocked(14, 7, true);
p.set_blocked(15, 7, true);
p.set_blocked(14, 8, true);
p.set_blocked(15, 8, true);
p.set_blocked(16, 9, true);
println!("{}", p);
p.find_path();
println!("{}", p);
}

View file

@ -1,4 +1,10 @@
use crate::graph::wheighted_graph::shortest_path::dijkstra;
use crate::graph::wheighted_graph::WheightedGraph;
use crate::priority_queue::BinaryHeap;
use crate::{misc::Map, priority_queue::PriorityQueue}; use crate::{misc::Map, priority_queue::PriorityQueue};
use colored::Colorize;
use std::fmt::{write, Display};
use std::io::Write;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum Direction { pub enum Direction {
@ -8,163 +14,163 @@ pub enum Direction {
Left, Left,
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Position { pub struct Position {
pub x: usize, pub x: usize,
pub y: usize, pub y: usize,
} }
impl Position {
pub fn new(x: usize, y: usize) -> Self {
Self { x, y }
}
}
#[derive(Default, Clone, Copy)] #[derive(Default, Clone, Copy)]
pub struct Field { pub struct Field {
pub blocked: bool, pub blocked: bool,
} }
#[derive(Debug, Clone)] pub struct Problem {
pub struct QueueObject { map: Map<Field>,
pos: Position, start: Position,
score: usize, end: Position,
path: Vec<Position>,
} }
impl QueueObject { impl Problem {
fn new(pos: Position, score: usize) -> Self { pub fn new(width: usize, height: usize, start: Position, end: Position) -> Self {
Self { pos, score }
}
}
impl Eq for QueueObject {}
impl Ord for QueueObject {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.score.cmp(&other.score)
}
}
impl PartialOrd for QueueObject {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.score.cmp(&other.score))
}
}
impl PartialEq for QueueObject {
fn eq(&self, other: &Self) -> bool {
self.score == other.score
}
}
struct FieldInternal<K> {
score: usize,
marked: bool,
key: Option<K>,
parent: Option<Direction>,
}
impl<K> Default for FieldInternal<K> {
fn default() -> Self {
Self { Self {
score: usize::MAX, map: Map::new(width, height),
marked: false, start,
key: None, end,
parent: None, path: Vec::new(),
} }
} }
pub fn set_blocked(&mut self, x: usize, y: usize, blocked: bool) {
self.map.get_mut(x, y).blocked = blocked;
}
} }
fn relax<P>( impl Display for Problem {
internal_map: &mut Map<FieldInternal<P::Handle>>, fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
q: &mut P, let width_digits = self.map.width.ilog10() + 1;
x: usize, let height_digits = self.map.height.ilog10() + 1;
y: usize,
score: usize, // print header
parent: Direction, for i in 0..width_digits {
) where let d = width_digits - i - 1;
P: PriorityQueue<QueueObject>, // padding
{ for _ in 0..height_digits {
let f = internal_map.get_mut(x, y); write!(f, " ")?;
if !f.marked {
if let Some(h) = &mut f.key {
if score < f.score {
f.score = score;
f.parent = Some(parent);
q.decrease_key(h, |o| o.score = score);
} }
for x in 0..self.map.width {
let digits = x / (usize::pow(10, d));
if digits == 0 && d > 0 {
write!(f, " ")?;
} else {
write!(f, "{}", char::from_u32((digits % 10) as u32 + 48).unwrap())?;
}
}
writeln!(f)?;
}
// Print body
for y in 0..self.map.height {
write!(f, "{:1$}", y, height_digits as usize)?;
for x in 0..self.map.width {
if self.start == Position::new(x, y) {
write!(f, "{}", "s".blue())?;
} else if self.end == Position::new(x, y) {
write!(f, "{}", "t".blue())?;
} else if let Some(p) = self.path.iter().position(|p| p == &Position::new(x, y)) {
if self.path[p].x < self.path[p + 1].x {
write!(f, "{}", "".blue())?;
} else if self.path[p].x > self.path[p + 1].x {
write!(f, "{}", "".blue())?;
} else if self.path[p].y < self.path[p + 1].y {
write!(f, "{}", "".blue())?;
} else if self.path[p].y > self.path[p + 1].y {
write!(f, "{}", "".blue())?;
}
} else if self.map.get(x, y).blocked {
write!(f, "{}", "#")?;
} else {
write!(f, " ")?;
}
}
writeln!(f)?;
}
Ok(())
}
}
struct MapInternal<'a> {
map: &'a Map<Field>,
}
impl<'a> MapInternal<'a> {
fn get_direction(&self, pos: Position) -> [Option<Position>; 4] {
[
(pos.x > 0)
.then_some((pos.x.saturating_sub(1), pos.y))
.map(|(x, y)| Position::new(x, y)),
(pos.x < self.map.width - 1)
.then_some((pos.x + 1, pos.y))
.map(|(x, y)| Position::new(x, y)),
(pos.y > 0)
.then_some((pos.x, pos.y.saturating_sub(1)))
.map(|(x, y)| Position::new(x, y)),
(pos.y < self.map.height - 1)
.then_some((pos.x, pos.y + 1))
.map(|(x, y)| Position::new(x, y)),
]
}
}
impl<'a> WheightedGraph for MapInternal<'a> {
type Node = Position;
fn num_edges(&self, node: &Self::Node) -> usize {
if self.map.get(node.x, node.y).blocked {
0
} else { } else {
let key = q.insert(QueueObject::new(Position { x, y }, score)); let t = self.get_direction(*node);
internal_map.set(
x, let v = t
y, .iter()
FieldInternal { .flatten()
score, .filter_map(|&p| (!self.map.get(p.x, p.y).blocked).then_some(p));
marked: false,
key: Some(key), v.count()
parent: Some(parent),
},
)
} }
} }
fn edge(&self, node: &Self::Node, num: usize) -> Option<(Self::Node, f64)> {
let t = self.get_direction(*node);
t.iter()
.flatten()
.filter_map(|&p| (!self.map.get(p.x, p.y).blocked).then_some(p))
.nth(num)
.map(|p| (p, 1.0))
}
} }
pub fn find_path<P>(map: Map<Field>, start: Position, end: Position) -> Option<Vec<Position>> impl Problem {
where pub fn find_path(&mut self) {
P: PriorityQueue<QueueObject> + std::fmt::Debug, let m = MapInternal { map: &self.map };
{
let mut q = P::new();
let mut internal_map: Map<FieldInternal<P::Handle>> = Map::new(map.width, map.height); let p = dijkstra::<MapInternal, BinaryHeap<_>>(&m, self.start, self.end);
q.insert(QueueObject::new(start, 0)); if let Some(p) = p {
internal_map.get_mut(start.x, start.y).score = 0; self.path = p;
while let Some(o) = q.pop_min() {
dbg!(&o);
if o.pos.x > 0 && !map.get(o.pos.x - 1, o.pos.y).blocked {
relax::<P>(
&mut internal_map,
&mut q,
o.pos.x - 1,
o.pos.y,
o.score + 1,
Direction::Right,
);
} }
if o.pos.x < map.width - 1 && !map.get(o.pos.x + 1, o.pos.y).blocked {
relax::<P>(
&mut internal_map,
&mut q,
o.pos.x + 1,
o.pos.y,
o.score + 1,
Direction::Left,
);
}
if o.pos.y > 0 && !map.get(o.pos.x, o.pos.y - 1).blocked {
relax::<P>(
&mut internal_map,
&mut q,
o.pos.x,
o.pos.y - 1,
o.score + 1,
Direction::Down,
);
}
if o.pos.y < map.height - 1 && !map.get(o.pos.x, o.pos.y + 1).blocked {
relax::<P>(
&mut internal_map,
&mut q,
o.pos.x,
o.pos.y + 1,
o.score + 1,
Direction::Up,
);
}
// dbg!(&q);
if o.pos == end {
break;
}
internal_map.get_mut(o.pos.x, o.pos.y).marked = true;
} }
None
} }

View file

@ -95,16 +95,14 @@ where
map.insert(node, MapObject::new(o.node.clone(), o.score + wheight, h)); map.insert(node, MapObject::new(o.node.clone(), o.score + wheight, h));
} }
} }
dbg!(&q); // dbg!(&q);
} }
if map.get(&end).is_none() { map.get(&end)?;
return None;
}
let mut result = vec![end]; let mut result = vec![end];
dbg!(&map); // dbg!(&map);
loop { loop {
let parent = map.get(result.last().expect("last")).expect("get"); let parent = map.get(result.last().expect("last")).expect("get");