aboutsummaryrefslogtreecommitdiff
path: root/server/data/src/book/diagram_layout.rs
diff options
context:
space:
mode:
Diffstat (limited to 'server/data/src/book/diagram_layout.rs')
-rw-r--r--server/data/src/book/diagram_layout.rs78
1 files changed, 78 insertions, 0 deletions
diff --git a/server/data/src/book/diagram_layout.rs b/server/data/src/book/diagram_layout.rs
new file mode 100644
index 00000000..0ea26a69
--- /dev/null
+++ b/server/data/src/book/diagram_layout.rs
@@ -0,0 +1,78 @@
+/*
+ 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 <https://www.gnu.org/licenses/>.
+
+*/
+
+use anyhow::{Result, anyhow};
+use hurrycurry_protocol::{book::Diagram, glam::Vec2};
+use serde::Deserialize;
+use std::{
+ collections::BTreeMap,
+ fmt::Write as W2,
+ io::Write,
+ process::{Command, Stdio},
+};
+
+pub struct Layout {
+ pub nodes: BTreeMap<String, Vec2>,
+ pub edges: Vec<(usize, usize)>,
+}
+
+pub fn diagram_layout(diagram: &mut Diagram) -> Result<()> {
+ let mut child = Command::new("dot")
+ .arg("-Tjson")
+ .arg("-Kdot")
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .spawn()?;
+
+ let mut out = String::new();
+ writeln!(out, "digraph {{")?;
+ for (i, _) in diagram.nodes.iter().enumerate() {
+ writeln!(out, "k{i} [width=1, height=1]")?;
+ }
+ for edge in &diagram.edges {
+ writeln!(out, "k{} -> k{}", edge.src, edge.dst)?;
+ }
+ writeln!(out, "}}")?;
+
+ child.stdin.as_mut().unwrap().write_all(out.as_bytes())?;
+ let output = child.wait_with_output()?;
+
+ #[derive(Deserialize)]
+ struct Out {
+ objects: Vec<Object>,
+ }
+ #[derive(Deserialize)]
+ struct Object {
+ name: String,
+ pos: String,
+ }
+ let graph: Out = serde_json::from_slice(&output.stdout)?;
+ for o in graph.objects {
+ let pos = o.pos.split_once(",").ok_or(anyhow!("malformed position"))?;
+ let pos = Vec2::new(pos.0.parse()?, pos.1.parse()?);
+
+ let index = o
+ .name
+ .strip_prefix("k")
+ .ok_or(anyhow!("invalid node name"))?
+ .parse::<usize>()?;
+ diagram.nodes[index].position = pos
+ }
+
+ Ok(())
+}