diff --git a/Cargo.toml b/Cargo.toml index 66083da..0ac2e0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -derive_more = "1.0.0" +derive_more = { version = "1.0.0", features = ["deref"] } disjoint-set = "0.0.2" eyre = "0.6.8" fastnbt = "2" diff --git a/src/graph/logic/mod.rs b/src/graph/logic/mod.rs index bf7b939..53132f5 100644 --- a/src/graph/logic/mod.rs +++ b/src/graph/logic/mod.rs @@ -1,11 +1,20 @@ -use std::ops::Deref; +use crate::transform::logic::LogicGraphTransformer; use super::Graph; pub mod builder; -#[derive(Debug, Clone, Deref)] +#[derive(Debug, Clone, derive_more::Deref)] pub struct LogicGraph { #[deref] pub graph: Graph, } + +impl LogicGraph { + pub fn prepare_place(self) -> eyre::Result { + let mut transform = LogicGraphTransformer::new(self); + transform.decompose_and()?; + transform.remove_double_neg_expression(); + Ok(transform.finish()) + } +} diff --git a/src/graph/mod.rs b/src/graph/mod.rs index 4b8138b..e1e8df5 100644 --- a/src/graph/mod.rs +++ b/src/graph/mod.rs @@ -72,6 +72,25 @@ impl GraphNodeKind { _ => unreachable!(), } } + + pub fn is_input(&self) -> bool { + matches!(self, GraphNodeKind::Input(_)) + } + + pub fn is_output(&self) -> bool { + matches!(self, GraphNodeKind::Output(_)) + } + + pub fn is_logic(&self) -> bool { + matches!(self, GraphNodeKind::Logic(_)) + } + + pub fn as_logic(&self) -> Option<&Logic> { + match self { + GraphNodeKind::Logic(inner) => Some(inner), + _ => None, + } + } } #[derive(Default, Debug, Clone)] @@ -182,7 +201,7 @@ impl Graph { .collect(); for (from, to) in replace_targets { - let mut node = other.nodes.iter_mut().find(|node| node.id == from).unwrap(); + let node = other.nodes.iter_mut().find(|node| node.id == from).unwrap(); self.find_node_by_id_mut(to) .unwrap() diff --git a/src/logic/mod.rs b/src/logic/mod.rs index e0e3612..ed04005 100644 --- a/src/logic/mod.rs +++ b/src/logic/mod.rs @@ -15,9 +15,18 @@ impl LogicType { LogicType::Xor => "Xor".to_owned(), } } + + pub fn is_not(&self) -> bool { + matches!(self, LogicType::Not) + } + + pub fn is_or(&self) -> bool { + matches!(self, LogicType::Or) + } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, derive_more::Deref)] pub struct Logic { + #[deref] pub logic_type: LogicType, } diff --git a/src/transform/component/mod.rs b/src/transform/component/mod.rs deleted file mode 100644 index 64d6d26..0000000 --- a/src/transform/component/mod.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Generate general World3D Component from LogicGraph - -use crate::{ - graph::logic::LogicGraph, - world::{position::DimSize, world::World3D}, -}; - -// struct IOTemplate {} - -struct Template { - dim: DimSize, -} - -// pub fn generate_template(graph: &LogicGraph, dim: DimSize) -> Vec { -// todo!() -// } - -// 가능한 모든 경우의 수를 생성하는 것을 목표로한다. -pub fn generate(graph: &LogicGraph) -> World3D { - let inputs = graph.inputs(); - todo!() -} - -#[cfg(test)] -mod tests { - - use crate::{ - graph::{ - graphviz::ToGraphvizGraph, - logic::{builder::LogicGraphBuilder, LogicGraph}, - }, - nbt::{NBTRoot, ToNBT}, - transform::{component::generate, logic::LogicGraphTransformer}, - }; - - fn build_graph_from_stmt(stmt: &str, output: &str) -> eyre::Result { - LogicGraphBuilder::new(stmt.to_string()).build(output.to_string()) - } - - #[test] - fn test_generate_component_and() -> eyre::Result<()> { - let logic_graph = build_graph_from_stmt("a&b", "c")?; - - let mut transform = LogicGraphTransformer::new(logic_graph); - transform.decompose_and()?; - transform.remove_double_neg_expression(); - let logic_graph = transform.finish(); - println!("{}", logic_graph.to_graphviz()); - - let world3d = generate(&logic_graph); - - let nbt: NBTRoot = world3d.to_nbt(); - nbt.save("test/and-gate-new.nbt"); - - Ok(()) - } -} diff --git a/src/transform/mod.rs b/src/transform/mod.rs index 2ac865e..8b82f8d 100644 --- a/src/transform/mod.rs +++ b/src/transform/mod.rs @@ -1,4 +1,3 @@ -pub mod component; pub mod logic; pub mod placer; pub mod router; diff --git a/src/transform/placer/mod.rs b/src/transform/placer/mod.rs index 39c93b4..242b159 100644 --- a/src/transform/placer/mod.rs +++ b/src/transform/placer/mod.rs @@ -1,14 +1,14 @@ use std::{collections::HashSet, iter::repeat_with}; -use petgraph::stable_graph::NodeIndex; +use eyre::ensure; use crate::{ graph::{ + logic::LogicGraph, world::{ builder::{PlaceBound, PropagateType}, WorldGraph, }, - GraphNodeId, GraphNodeKind, SubGraphWithGraph, }, world::{block::Block, position::Position, world::World3D}, }; @@ -35,61 +35,56 @@ impl PlacedNode { .into_iter() .collect() } + + pub fn has_conflict_with(&self, other: &Self) -> bool { + todo!() + } + + // pub fn } -pub struct LocalPlacer<'a> { - graph: SubGraphWithGraph<'a>, - try_count: usize, - max_width_size: usize, - max_height_size: usize, +pub struct LocalPlacer { + graph: LogicGraph, } pub const K_MAX_LOCAL_PLACE_NODE_COUNT: usize = 25; -impl<'a> LocalPlacer<'a> { - // you should not pass side effected sub-graph - pub fn new( - graph: SubGraphWithGraph<'a>, - try_count: usize, - max_width_size: Option, - max_height_size: Option, - ) -> eyre::Result { - assert!(try_count > 0); - - Self::verify(&graph); - - Ok(Self { - graph, - try_count, - max_width_size: max_width_size.unwrap_or(usize::MAX), - max_height_size: max_height_size.unwrap_or(usize::MAX), - }) +impl LocalPlacer { + pub fn new(graph: LogicGraph) -> eyre::Result { + let result = Self { graph }; + result.verify()?; + Ok(result) } - pub fn verify(graph: &SubGraphWithGraph<'a>) { - assert!(graph.nodes.len() > 0); - assert!(graph.nodes.len() <= K_MAX_LOCAL_PLACE_NODE_COUNT); - - for node_id in &graph.nodes { - assert!(matches!( - graph.graph.find_node_by_id(*node_id).unwrap().kind, - GraphNodeKind::Logic { .. } - )); + fn verify(&self) -> eyre::Result<()> { + ensure!(self.graph.nodes.len() > 0, ""); + ensure!( + self.graph.nodes.len() <= K_MAX_LOCAL_PLACE_NODE_COUNT, + "too large graph" + ); + + for node_id in &self.graph.nodes { + let kind = &self.graph.find_node_by_id(node_id.id).unwrap().kind; + ensure!( + kind.is_input() || kind.is_output() || kind.is_logic(), + "cannot place" + ); + if let Some(logic) = kind.as_logic() { + ensure!(logic.is_not() || logic.is_or(), "cannot place"); + } } - } - pub fn generate(&mut self) -> WorldGraph { - let try_count = self.try_count; + Ok(()) + } - // TODO: make parallel + pub fn generate(&mut self) -> World3D { repeat_with(|| self.next_place()) - .take(try_count) .min_by_key(|(_, c)| *c) .unwrap() .0 } - fn next_place(&mut self) -> (WorldGraph, usize) { + fn next_place(&mut self) -> (World3D, usize) { todo!() } } @@ -109,3 +104,35 @@ impl<'a> LocalPlacerCostEstimator<'a> { todo!() } } + +#[cfg(test)] +mod tests { + + use crate::{ + graph::{ + graphviz::ToGraphvizGraph, + logic::{builder::LogicGraphBuilder, LogicGraph}, + }, + nbt::{NBTRoot, ToNBT}, + transform::placer::LocalPlacer, + }; + + fn build_graph_from_stmt(stmt: &str, output: &str) -> eyre::Result { + LogicGraphBuilder::new(stmt.to_string()).build(output.to_string()) + } + + #[test] + fn test_generate_component_and() -> eyre::Result<()> { + let logic_graph = build_graph_from_stmt("a&b", "c")?.prepare_place()?; + dbg!(&logic_graph); + println!("{}", logic_graph.to_graphviz()); + + let mut placer = LocalPlacer::new(logic_graph)?; + let world3d = placer.generate(); + + let nbt: NBTRoot = world3d.to_nbt(); + nbt.save("test/and-gate-new.nbt"); + + Ok(()) + } +}