diff options
| -rw-r--r-- | src/gate.rs | 401 | ||||
| -rw-r--r-- | src/main.rs | 72 |
2 files changed, 326 insertions, 147 deletions
diff --git a/src/gate.rs b/src/gate.rs index 8afe056..276eb68 100644 --- a/src/gate.rs +++ b/src/gate.rs @@ -18,14 +18,15 @@ pub enum Gate { } impl Gate { - pub fn new(gate_type: GateType, input: Vec<PinValue>, kind: PinType) -> Self { + // TODO: Find a way to have unique ids without having this unsafe block + pub fn new(gate_type: GateType, input: Vec<PinValue>) -> Self { static mut ID: usize = 0; unsafe { ID += 1; match gate_type { - GateType::And => Gate::And(AndGate::new(input, ID, kind)), + GateType::And => Gate::And(AndGate::new(input, ID)), GateType::Not => Gate::Not(NotGate::new(input, ID)), - GateType::Chip => Gate::Chip(Chip::new()), + GateType::Chip => Gate::Chip(Chip::new(ID)), } } } @@ -39,10 +40,11 @@ impl Gate { } fn add_input(&mut self, val: PinValue, connections: &mut Connections) -> usize { + let id = self.id().clone(); match self { Gate::And(gate) => gate.add_input(val, connections), Gate::Not(gate) => gate.add_input(val, connections), - Gate::Chip(_) => todo!(), + Gate::Chip(chip) => chip.add_input(Pin::new(PinType::ChipInput, id, val)), } } @@ -50,7 +52,7 @@ impl Gate { match self { Gate::And(gate) => &gate.pins, Gate::Not(gate) => &gate.pins, - Gate::Chip(_) => todo!(), + Gate::Chip(chip) => &chip.pins, } } @@ -58,7 +60,7 @@ impl Gate { match self { Gate::And(gate) => &mut gate.pins, Gate::Not(gate) => &mut gate.pins, - Gate::Chip(_) => todo!(), + Gate::Chip(chip) => &mut chip.pins, } } @@ -66,11 +68,11 @@ impl Gate { match self { Gate::And(gate) => gate.set_pin(id, val), Gate::Not(gate) => gate.set_pin(id, val), - Gate::Chip(_) => todo!(), + Gate::Chip(chip) => chip.set_pin(id, val), } } - fn input(&self) -> &Vec<usize> { + fn input(&self) -> &[usize] { match self { Gate::And(gate) => &gate.input, Gate::Not(gate) => &gate.input, @@ -78,11 +80,29 @@ impl Gate { } } + pub fn add_gate(&mut self, gate: Gate) -> usize { + match self { + Gate::Chip(chip) => chip.add_gate(gate), + _ => { + unreachable!("You shouldn't be calling this function"); + } + } + } + + pub fn connect_gate(&mut self, from: usize, to: usize) { + match self { + Gate::Chip(chip) => chip.connect_gate(from, to), + _ => { + unreachable!("You shouldn't be calling this function"); + } + } + } + pub fn pin(&self, id: usize) -> &Pin { match self { Gate::And(gate) => gate.pin(id), Gate::Not(gate) => gate.pin(id), - Gate::Chip(_) => todo!(), + Gate::Chip(chip) => chip.pin(id), } } @@ -90,15 +110,15 @@ impl Gate { match self { Gate::And(gate) => gate.pin_mut(id), Gate::Not(gate) => gate.pin_mut(id), - Gate::Chip(_) => todo!(), + Gate::Chip(chip) => chip.pin_mut(id), } } - fn output(&self) -> &usize { + fn output(&self) -> &[usize] { match self { Gate::And(gate) => &gate.output, Gate::Not(gate) => &gate.output, - Gate::Chip(_) => todo!(), + Gate::Chip(chip) => &chip.output, } } @@ -106,7 +126,7 @@ impl Gate { match self { Gate::And(gate) => gate.id, Gate::Not(gate) => gate.id, - Gate::Chip(_) => 0, + Gate::Chip(chip) => chip.id, } } } @@ -125,14 +145,16 @@ impl PartialEq for NotGate { #[derive(Debug, Clone)] pub struct AndGate { - id: usize, - pins: HashMap<usize, Pin>, - input: Vec<usize>, - output: usize, + id: usize, // unique id for every gate + pins: HashMap<usize, Pin>, // contains all the input and output pins of that gate + input: Vec<usize>, // contains only the ids of input pins + output: Vec<usize>, // contains only th ids of output pins } impl AndGate { - fn new(input: Vec<PinValue>, id: usize, kind: PinType) -> Self { + fn new(input: Vec<PinValue>, id: usize) -> Self { + /* if we are here it means the gate input doesn't depend on input + known when running the circuit aka these inputs will be evaluated at runtime */ if input.is_empty() { let pin_out = Pin::new(PinType::GateOutput, id, 42); let mut pins = HashMap::new(); @@ -141,10 +163,12 @@ impl AndGate { id, pins, input: vec![], - output: pin_out.id, + output: vec![pin_out.id], } - } else if input.len() == 1 { - let pin_1 = Pin::new(kind, id, input[0]); + } + // only one input is known before running the circuit + else if input.len() == 1 { + let pin_1 = Pin::new(PinType::GateInput, id, input[0]); let pin_out = Pin::new(PinType::GateOutput, id, 42); let mut pins = HashMap::new(); pins.insert(pin_1.id, pin_1); @@ -153,11 +177,13 @@ impl AndGate { id, pins, input: vec![pin_1.id], - output: pin_out.id, + output: vec![pin_out.id], } - } else { - let pin_1 = Pin::new(kind, id, input[0]); - let pin_2 = Pin::new(kind, id, input[1]); + } + // The two inputs are known before evaluating the circuit + else { + let pin_1 = Pin::new(PinType::GateInput, id, input[0]); + let pin_2 = Pin::new(PinType::GateInput, id, input[1]); let pin_out = Pin::new(PinType::GateOutput, id, 42); let mut pins = HashMap::new(); pins.insert(pin_1.id, pin_1); @@ -167,16 +193,18 @@ impl AndGate { id, pins, input: vec![pin_1.id, pin_2.id], - output: pin_out.id, + output: vec![pin_out.id], } } } pub fn pin(&self, id: usize) -> &Pin { + // TODO: Should return a Result and propagate the error up the stack self.pins.get(&id).expect("pin should exist") } fn pin_mut(&mut self, id: usize) -> &mut Pin { + // TODO: Should return a Result and propagate the error up the stack self.pins.get_mut(&id).expect("pin should exist") } @@ -184,30 +212,32 @@ impl AndGate { self.pin_mut(*id).val = val; } + // Adds an input pin and returns the id of that pin fn add_input(&mut self, val: PinValue, connections: &mut Connections) -> usize { let new_pin = Pin::new(PinType::GateInput, self.id, val); self.pins.insert(new_pin.id, new_pin); self.input.push(new_pin.id); connections - .entry(self.output) + .entry(self.output[0]) .and_modify(|val| val.push(new_pin.id)) .or_insert_with(|| vec![new_pin.id]); new_pin.id } + // Evaluating the And gate by literally anding it's two inputs fn evaluate(&mut self) -> bool { let res = (self.pin(self.input[0]).val.unwrap() & self.pin(self.input[1]).val.unwrap()) == 1; - println!( - "input: {:?}", - self.input - .iter() - .map(|&x| (self.pin(x).val, self.pin(x).id)) - .collect::<Vec<(Option<PinValue>, usize)>>() - ); - println!("Evaluating gate_{} with res = {}", self.id, res); - self.pin_mut(self.output).val = Some(res as u8); - self.pin_mut(self.output).kind = PinType::GateOutput; + // println!( + // "input: {:?}", + // self.input + // .iter() + // .map(|&x| (self.pin(x).val, self.pin(x).id)) + // .collect::<Vec<(Option<PinValue>, usize)>>() + // ); + // println!("Evaluating gate_{} with res = {}", self.id, res); + self.pin_mut(self.output[0]).val = Some(res as u8); + self.pin_mut(self.output[0]).kind = PinType::GateOutput; res } } @@ -217,7 +247,7 @@ pub struct NotGate { id: usize, pins: HashMap<usize, Pin>, input: Vec<usize>, - output: usize, + output: Vec<usize>, } impl NotGate { @@ -230,7 +260,7 @@ impl NotGate { id, pins, input: vec![], - output: pin_out.id, + output: vec![pin_out.id], } } else { let pin_1 = Pin::new(PinType::GateInput, id, input[0]); @@ -242,7 +272,7 @@ impl NotGate { id, pins, input: vec![pin_1.id], - output: pin_out.id, + output: vec![pin_out.id], } } } @@ -264,7 +294,7 @@ impl NotGate { self.pins.insert(new_pin.id, new_pin); self.input.push(new_pin.id); connections - .entry(self.output) + .entry(self.output[0]) .and_modify(|val| val.push(new_pin.id)) .or_insert_with(|| vec![new_pin.id]); new_pin.id @@ -272,22 +302,28 @@ impl NotGate { fn evaluate(&mut self) -> bool { let res = !(self.pin(self.input[0]).val.unwrap() == 1); - println!( - "input: {:?}", - self.input - .iter() - .map(|&x| (self.pin(x).val, self.pin(x).id)) - .collect::<Vec<(Option<PinValue>, usize)>>() - ); - println!("Evaluating gate_{} with res = {}", self.id, res); - self.pin_mut(self.output).val = Some(res as u8); - self.pin_mut(self.output).kind = PinType::GateOutput; + // println!( + // "input: {:?}", + // self.input + // .iter() + // .map(|&x| (self.pin(x).val, self.pin(x).id)) + // .collect::<Vec<(Option<PinValue>, usize)>>() + // ); + // println!("Evaluating gate_{} with res = {}", self.id, res); + self.pin_mut(self.output[0]).val = Some(res as u8); + self.pin_mut(self.output[0]).kind = PinType::GateOutput; res } } +/* +* A Chip is collection of smaller gates connected together it's essentially a complex gate +* A Chip very much like a gate have some input pins and output pins, but they also have +* connections map which defines the edges between gates and how they are connected +*/ #[derive(Debug, Clone, PartialEq)] pub struct Chip { + id: usize, pub gates: Gates, pub connections: Connections, pins: HashMap<usize, Pin>, @@ -296,19 +332,29 @@ pub struct Chip { } impl Chip { - pub fn new() -> Chip { + pub fn new(id: usize) -> Chip { Chip { - gates: Gates::new(), - connections: HashMap::new(), - pins: HashMap::new(), - input: vec![], - output: vec![], + id, + gates: Gates::new(), // Gates in the current chip + connections: HashMap::new(), // Essentially represents how the pins are connected + pins: HashMap::new(), // Pins in the current chip(Not including gates pins) + input: vec![], // Chip input pins + output: vec![], // Chip output pins } } - pub fn add_input(&mut self, pin: Pin) { + fn set_pin(&mut self, id: &usize, val: Option<PinValue>) { + /* + * TODO: This should return a Result and deals with faliure more properly instead of + crashing the program + */ + self.pins.get_mut(id).expect("Pin should exsist").val = val; + } + + pub fn add_input(&mut self, pin: Pin) -> usize { self.pins.insert(pin.id, pin); self.input.push(pin.id); + pin.id } pub fn add_output(&mut self, pin: Pin) { @@ -316,35 +362,65 @@ impl Chip { self.output.push(pin.id); } + fn set_output(&mut self) { + let g_pins = self.gate_dag(); + let gates = g_pins.iter().map(|x| x.0).collect::<Vec<_>>(); + for gate_id in gates { + let mut found = false; + for (_, children) in &g_pins { + if children.contains(gate_id) { + found = true; + break; + } + } + if !found { + self.output.push(*gate_id); + } + } + } + pub fn add_gate(&mut self, gate: Gate) -> usize { - // the output of a gate depends on its inputs + /* + * The output of a gate depends on its inputs + * so we have to add all of input pins as a dependency + * to the output pin in the conncections graph + */ for pin_in in gate.input() { - self.connections - .entry(*gate.output()) - .and_modify(|val| val.push(*pin_in)) - .or_insert_with(|| vec![*pin_in]); + for output in gate.output() { + self.connections + .entry(*output) + .and_modify(|val| val.push(*pin_in)) + .or_insert_with(|| vec![*pin_in]); + } } let id = gate.id(); self.gates.insert(id, gate); id } - pub fn connect_gate(&mut self, from: usize, to: usize, to_pin_idx: usize) { - let from_pin_id = self.gates.get(&from).unwrap().output().clone(); + /* + * This function takes two gate ids and connects them + */ + pub fn connect_gate(&mut self, from: usize, to: usize) { + let from_pins = self.gates.get(&from).unwrap().clone(); + let from_pins = from_pins.output(); let to_gate = self.gates.get_mut(&to).unwrap(); - let mut id = 42; + let mut _id = 42; if to_gate.input().len() < 2 { - id = to_gate.add_input(0, &mut self.connections) + _id = to_gate.add_input(0, &mut self.connections) } // the inputs of some gate depends on the output of some other gate - self.connections - .entry(to_gate.input()[to_pin_idx]) - .and_modify(|val| val.push(from_pin_id)) - .or_insert_with(|| vec![from_pin_id]); + for output in from_pins { + self.connections + .entry(to_gate.input()[to_gate.input().len() - 1]) + .and_modify(|val| val.push(*output)) + .or_insert_with(|| vec![*output]); + } } - pub fn pins(&self) -> HashMap<usize, &Pin> { + // Returns a HashMap containing all pins in the current chip + pub fn gates_pins(&self) -> HashMap<usize, &Pin> { let mut pins = HashMap::new(); for (_, gate) in &self.gates { for (id, pin) in gate.pins() { @@ -354,18 +430,19 @@ impl Chip { pins } - pub fn pins_mut(&mut self) -> HashMap<usize, &mut Pin> { - let mut pins = HashMap::new(); - for (_, gate) in &mut self.gates { - for (id, pin) in gate.pins_mut() { - pins.entry(*id).or_insert_with(|| pin); - } - } - pins + fn pin(&self, id: usize) -> &Pin { + // TODO: Do peoper error handling and propagate the error up the stack instead of crashing + self.pins.get(&id).expect("Pin should exist") + } + + pub fn pin_mut(&mut self, id: usize) -> &mut Pin { + // TODO: Do peoper error handling and propagate the error up the stack instead of crashing + self.pins.get_mut(&id).expect("Pin should exist") } + // Constructs the gate dag(Directed Acyclic Graph) from the connections map pub fn gate_dag(&self) -> HashMap<usize, Vec<usize>> { - let pins = self.pins(); + let pins = self.gates_pins(); let mut dag = HashMap::new(); for connection in &self.connections { for pin in connection.1 { @@ -389,13 +466,18 @@ impl Chip { } fn set_gate_pin(&mut self, gate_id: usize, pin_id: &usize, val: Option<PinValue>) { - println!( - "Propagating: gate_{} with pin_{} to val = {:?}", - gate_id, pin_id, val - ); + // println!( + // "Propagating: gate_{} with pin_{} to val = {:?}", + // gate_id, pin_id, val + // ); self.gates.get_mut(&gate_id).unwrap().set_pin(pin_id, val); } + /* + * The function that does all the magic of evaluating gates outputs recusively + * by utilizing toplogical sort(kind of) it just traverses the graph in post-order + * and it makes sure that all the gates output are propagated properly to their connected pins + */ fn simulate_helper( &mut self, gate_id: usize, @@ -417,34 +499,157 @@ impl Chip { } } - // TODO: Optimize this function specially the unecessary calling of self.pins() + /* + * Takes a gate id and propagates its output evaluation to its other conncted pins in the pin + * dag, this function should only be called when we are sure that the output has already been + * evaluated which should be the case because we are traversting the graph in post-order + */ fn propagate(&mut self, gate_id: usize) { + // TODO: Optimize this function especially the unecessary calling of self.pins() + // TODO: Add proper error handling of when the output value hasn't been evaluated yet let pin_dag = self.pin_dag().clone(); - let pin_out_id = self.gates.get(&gate_id).unwrap().output().clone(); + let pins_out = self.gates.get(&gate_id).unwrap().output(); + let mut propagated_pins = HashMap::new(); let pin_out_val = { - let pins = self.pins(); - pins.get(&pin_out_id).unwrap().val + let pins = self.gates_pins(); + pins.get(&pins_out[0]).unwrap().val }; - let propagated_pins = pin_dag - .iter() - .filter(|(_, pins)| pins.contains(&pin_out_id)); + for pin in pins_out { + propagated_pins.extend(pin_dag.iter().filter(|(_, pins)| pins.contains(&pin))); + } + /* set the values of the pins conncted to the output pin of that gate_id to the value of + * that output pin + */ for (pin_id, _) in propagated_pins { - let pins = self.pins(); + let pins = self.gates_pins(); if let Some(pin) = pins.get(&pin_id).cloned() { let gate_id = pin.gate_id; - self.set_gate_pin(gate_id, pin_id, pin_out_val); + self.set_gate_pin(gate_id, &pin_id, pin_out_val); } } } + /* + * The function that kickstarts simulate_helper which does all the job of evaluating gates + * recusively + */ pub fn simulate(&mut self) -> bool { let dag = self.gate_dag(); let mut visited = HashSet::new(); - for child in dag.get(&8).unwrap() { - if !visited.contains(child) { - self.simulate_helper(*child, &mut visited, &dag); + self.set_output(); + println!("output: {:?}", self.output); + for out in self.output.clone() { + for child in dag.get(&out).unwrap() { + if !visited.contains(child) { + self.simulate_helper(*child, &mut visited, &dag); + } } + return self.gates.get_mut(&out).unwrap().evaluate(); } - self.gates.get_mut(&8).unwrap().evaluate() + false + } +} + +mod tests { + use crate::{ + gate::{Gate, GateType}, + types::PinValue, + }; + + fn test_or_helper(a: u8, b: u8) -> bool { + let input: Vec<PinValue> = vec![a, b]; + println!("input: {:?}", input); + let gate_1 = Gate::new(GateType::And, vec![a, a]); + let gate_2 = Gate::new(GateType::Not, vec![]); + let gate_3 = Gate::new(GateType::And, vec![b, b]); + let gate_4 = Gate::new(GateType::Not, vec![]); + let gate_5 = Gate::new(GateType::And, vec![]); + let gate_6 = Gate::new(GateType::Not, vec![]); + + let gate_1_id = gate_1.id(); + let gate_2_id = gate_2.id(); + let gate_3_id = gate_3.id(); + let gate_4_id = gate_4.id(); + let gate_5_id = gate_5.id(); + let gate_6_id = gate_6.id(); + + let mut or = Gate::new(GateType::Chip, vec![]); + + or.add_gate(gate_1); + or.add_gate(gate_2); + or.add_gate(gate_3); + or.add_gate(gate_4); + or.add_gate(gate_5); + or.add_gate(gate_6); + + or.connect_gate(gate_1_id, gate_2_id); + or.connect_gate(gate_2_id, gate_5_id); + or.connect_gate(gate_3_id, gate_4_id); + or.connect_gate(gate_4_id, gate_5_id); + or.connect_gate(gate_5_id, gate_6_id); + + println!("Output: {:?}", or.evaluate()); + or.evaluate() + } + + fn test_xor_helper(a: u8, b: u8) -> bool { + let input: Vec<PinValue> = vec![a, b]; + println!("input: {:?}", input); + let gate_1 = Gate::new(GateType::And, input); + let gate_2 = Gate::new(GateType::Not, vec![]); + let gate_3 = Gate::new(GateType::And, vec![a]); + let gate_4 = Gate::new(GateType::Not, vec![]); + let gate_5 = Gate::new(GateType::And, vec![b]); + let gate_6 = Gate::new(GateType::Not, vec![]); + let gate_7 = Gate::new(GateType::And, vec![]); + let gate_8 = Gate::new(GateType::Not, vec![]); + + let gate_1_id = gate_1.id(); + let gate_2_id = gate_2.id(); + let gate_3_id = gate_3.id(); + let gate_4_id = gate_4.id(); + let gate_5_id = gate_5.id(); + let gate_6_id = gate_6.id(); + let gate_7_id = gate_7.id(); + let gate_8_id = gate_8.id(); + + let mut xor = Gate::new(GateType::Chip, vec![]); + + xor.add_gate(gate_1); + xor.add_gate(gate_2); + xor.add_gate(gate_3); + xor.add_gate(gate_4); + xor.add_gate(gate_5); + xor.add_gate(gate_6); + xor.add_gate(gate_7); + xor.add_gate(gate_8); + + xor.connect_gate(gate_1_id, gate_2_id); + xor.connect_gate(gate_2_id, gate_3_id); + xor.connect_gate(gate_2_id, gate_5_id); + xor.connect_gate(gate_3_id, gate_4_id); + xor.connect_gate(gate_5_id, gate_6_id); + xor.connect_gate(gate_4_id, gate_7_id); + xor.connect_gate(gate_6_id, gate_7_id); + xor.connect_gate(gate_7_id, gate_8_id); + + println!("Output: {:?}", xor.evaluate()); + xor.evaluate() + } + + #[test] + fn test_xor() { + assert!(!test_xor_helper(0, 0)); + assert!(test_xor_helper(0, 1)); + assert!(test_xor_helper(1, 0)); + assert!(!test_xor_helper(1, 1)); + } + + #[test] + fn test_or() { + assert!(!test_or_helper(0, 0)); + assert!(test_or_helper(0, 1)); + assert!(test_or_helper(1, 0)); + assert!(test_or_helper(1, 1)); } } diff --git a/src/main.rs b/src/main.rs index 222af4b..43c2084 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,62 +4,36 @@ mod gate; mod pin; mod types; use crate::gate::*; -use crate::pin::*; use crate::types::*; use std::vec; fn main() { - let mut _chip = Chip::new(); - let a: u8 = 1; - let b: u8 = 0; - let input: Vec<PinValue> = vec![a, b]; - println!("input: {:?}", input); - let gate_1 = Gate::new(GateType::And, input, PinType::GateInput); - let gate_2 = Gate::new(GateType::Not, vec![], PinType::GateInput); - let gate_3 = Gate::new(GateType::And, vec![a], PinType::GateInput); - let gate_4 = Gate::new(GateType::Not, vec![], PinType::GateInput); - let gate_5 = Gate::new(GateType::And, vec![b], PinType::GateInput); - let gate_6 = Gate::new(GateType::Not, vec![], PinType::GateInput); - let gate_7 = Gate::new(GateType::And, vec![], PinType::GateInput); - let gate_8 = Gate::new(GateType::Not, vec![], PinType::GateInput); + { + let a: u8 = 1; + let b: u8 = 1; + let input: Vec<PinValue> = vec![a, b]; + println!("input: {:?}", input); + let gate_1 = Gate::new(GateType::And, vec![a, a]); + let gate_2 = Gate::new(GateType::Not, vec![]); + let gate_1_id = gate_1.id(); + let gate_2_id = gate_2.id(); - let gate_1_id = gate_1.id(); - let gate_2_id = gate_2.id(); - let gate_3_id = gate_3.id(); - let gate_4_id = gate_4.id(); - let gate_5_id = gate_5.id(); - let gate_6_id = gate_6.id(); - let gate_7_id = gate_7.id(); - let gate_8_id = gate_8.id(); + let mut nand_1 = Gate::new(GateType::Chip, vec![]); - let mut xor = Chip::new(); + nand_1.add_gate(gate_1); + nand_1.add_gate(gate_2); + nand_1.connect_gate(gate_1_id, gate_2_id); - xor.add_gate(gate_1); - xor.add_gate(gate_2); - xor.add_gate(gate_3); - xor.add_gate(gate_4); - xor.add_gate(gate_5); - xor.add_gate(gate_6); - xor.add_gate(gate_7); - xor.add_gate(gate_8); + let nand_1_id = nand_1.id(); + let mut double_nand = Gate::new(GateType::Chip, vec![]); - xor.connect_gate(gate_1_id, gate_2_id, 0); - xor.connect_gate(gate_2_id, gate_3_id, 1); - xor.connect_gate(gate_2_id, gate_5_id, 1); - xor.connect_gate(gate_3_id, gate_4_id, 0); - xor.connect_gate(gate_5_id, gate_6_id, 0); - xor.connect_gate(gate_4_id, gate_7_id, 0); - xor.connect_gate(gate_6_id, gate_7_id, 1); - xor.connect_gate(gate_7_id, gate_8_id, 0); + let gate_3 = Gate::new(GateType::Not, vec![]); + let gate_3_id = gate_3.id(); + double_nand.add_gate(nand_1); + double_nand.add_gate(gate_3); - let dag = xor.gate_dag(); - let output = xor.simulate(); - println!("Output: {:?}", output); - // println!("connections: {:#?}", xor.connections); - // println!("pins: {:?}", xor.pin_dag()); - // println!("pins: {:#?}", xor.pins()); -} + double_nand.connect_gate(nand_1_id, gate_3_id); -// #[macroquad::main("lgsim")] -// async fn main() { -// } + println!("chip: {:#?}", double_nand); + } +} |
