/*
Hurry Curry! - a game about cooking
Copyright (C) 2025 Hurry Curry! Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
use anyhow::Result;
use hurrycurry_protocol::{
book::Diagram,
glam::{Vec2, vec2},
};
use std::collections::{BTreeMap, BTreeSet};
pub struct Layout {
pub nodes: BTreeMap,
pub edges: Vec<(usize, usize)>,
}
pub fn diagram_layout(diagram: &mut Diagram) -> Result<()> {
let mut graph = Graph {
vertices: (0..diagram.nodes.len())
.map(|i| vec2(i as f32, i as f32) * 30.)
.collect(),
edges: diagram.edges.iter().map(|e| (e.src, e.dst)).collect(),
};
graph.layout();
diagram
.nodes
.iter_mut()
.zip(graph.vertices.iter())
.for_each(|(n, v)| n.position = *v);
Ok(())
}
pub struct Graph {
pub vertices: Vec,
pub edges: Vec<(usize, usize)>,
}
impl Graph {
pub fn layout(&mut self) {
let mut layers = Vec::new();
let mut previous_layers = BTreeSet::new();
let mut to_insert = Vec::new();
to_insert.extend(0..self.vertices.len());
while !to_insert.is_empty() {
let mut next_layer = Vec::new();
to_insert.retain(|&vi| {
for &(src, dst) in &self.edges {
if src == vi && !previous_layers.contains(&dst) {
return true;
}
}
next_layer.push(vi);
false
});
previous_layers.extend(next_layer.iter().copied());
layers.push(next_layer);
}
#[allow(clippy::needless_range_loop)]
for y in 0..layers.iter().len() {
let mut layer = layers[y].clone();
layer.sort_by_cached_key(|&vi| {
self.edges
.iter()
.find(|&&(src, _)| src == vi)
.map_or(0, |&(_, dst)| (self.vertices[dst].x * 100.) as i64)
});
for (x, &vi) in layer.iter().enumerate() {
self.vertices[vi] = vec2(x as f32 - layer.len() as f32 / 2., y as f32) * 100.;
}
}
}
}