commit d1176cff5fcb7e6546abd61ab346a7e60a3d485d Author: Rushmore75 Date: Wed Oct 22 14:17:43 2025 -0600 init diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..e923090 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "logic_gates" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..77d898d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "logic_gates" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..648fdfc --- /dev/null +++ b/src/main.rs @@ -0,0 +1,257 @@ +#![feature(trait_alias)] + +use std::collections::HashMap; + +struct BakedGate { + table: Vec +} + +impl BakedGate { + fn test(&self, input: Vec) -> bool { + + let mut total = 0; + + for (i, input) in input.iter().enumerate() { + if *input { + total += 1 << i + } + } + + self.table[total] + } +} + +struct Gate { + function: T, + qty_inputs: usize, + qty_outputs: usize, + +} + +trait Logic = Fn(Vec) -> bool; + +impl Gate { + fn new(expected_inputs: usize, f: T) -> Self { + Self { + function: f, + qty_inputs: expected_inputs, + qty_outputs: 1, + } + } + + fn bake(&self) -> BakedGate { + // we will count in binary for this + let max = (1 << (self.qty_inputs)) -1; + + let mut options = Vec::new(); + + for args in 0..=max { + let mut inputs = Vec::new(); + + for i in 0..self.qty_inputs { + let b = 1 << i & args; + let ans = b > 0 ; + inputs.push(ans); + } + inputs.reverse(); + + let output = self.tick(inputs); + // The index is the question, and the item at the index is the answer + options.push(output); + + println!(); + } + BakedGate { + table: options + } + } + + fn tick(&self, inputs: Vec) -> bool { + assert!(self.qty_inputs == inputs.len()); + + (self.function)(inputs) + } +} + +#[test] +fn baked_gate() { + let and = Gate::new(2, |f| { + let a = f[0]; + let b = f[1]; + a && b + }); + let baked = and.bake(); + + assert_eq!(baked.test(vec![true, true]), true); + assert_eq!(baked.test(vec![true, false]), false); + assert_eq!(baked.test(vec![false, true]), false); + assert_eq!(baked.test(vec![false, false]), false); + + let or = Gate::new(2, |f| { + let a = f[0]; + let b = f[1]; + a || b + }); + let baked = or.bake(); + + assert_eq!(baked.test(vec![true, true]), true); + assert_eq!(baked.test(vec![true, false]), true); + assert_eq!(baked.test(vec![false, true]), true); + assert_eq!(baked.test(vec![false, false]), false); + + let not = Gate::new(1, |f| { + !f[0] + }); + let baked = not.bake(); + + assert_eq!(baked.test(vec![true]), false); + assert_eq!(baked.test(vec![false]), true); +} + +#[test] +fn baked_registry() { + let mut registry: HashMap<&str, BakedGate> = HashMap::new(); + + let and = Gate::new(2, |f| f[0] && f[1]); + let or = Gate::new(2, |f| f[0] | f[1]); + let not = Gate::new(1, |f| !f[0]); + + registry.insert("AND", and.bake()); + registry.insert("OR", or.bake()); + registry.insert("NOT", not.bake()); + + if let (Some(and), Some(not)) = (registry.get("AND"), registry.get("NOT")) { + + let nand = Gate::new(2, |f| { + not.test(vec![and.test(f)]) + }); + + registry.insert("NAND", nand.bake()); + } + + if let Some(nand) = registry.get("NAND") { + assert_eq!(nand.test(vec![true, true]), false); + assert_eq!(nand.test(vec![false, true]), true); + assert_eq!(nand.test(vec![true, false]), true); + assert_eq!(nand.test(vec![false, false]), true); + } else { + unreachable!() + } + +} + +#[test] +fn unbaked_registry() { + use std::collections::HashMap; + + let mut registry: HashMap<&str, Gate>> = HashMap::new(); + + let and: Gate> = Gate::new( + 2, + Box::new(|f| f[0] && f[1]), + ); + + registry.insert("AND", and); + + let not: Gate> = Gate::new(1, Box::new(|f| !f[0])); + + registry.insert("NOT", not); + + if let (Some(not), Some(and)) = (registry.get("NOT"), registry.get("AND")) { + let nand: Gate> = Gate::new( + 2, + Box::new(|f| { + let a = f[0]; + let b = f[1]; + + let n = and.tick(vec![a, b]); + not.tick(vec![n]) + }), + ); + + assert_eq!(not.tick(vec![true]), false); + assert_eq!(not.tick(vec![false]), true); + + assert_eq!(and.tick(vec![true, true]), true); + assert_eq!(and.tick(vec![true, false]), false); + assert_eq!(and.tick(vec![false, true]), false); + assert_eq!(and.tick(vec![false, false]), false); + + assert_eq!(nand.tick(vec![true, true]), false); + assert_eq!(nand.tick(vec![true, false]), true); + assert_eq!(nand.tick(vec![false, true]), true); + assert_eq!(nand.tick(vec![false, false]), true); + }; +} + +#[test] +fn nand_gate() { + let and = Gate::new(2, |f| { + let a = f[0]; + let b = f[1]; + a && b + }); + let not = Gate::new(1, |f| !f[0]); + + let nand = Gate::new(2, |f| not.tick(vec![and.tick(f)])); + + assert_eq!(nand.tick(vec![true, true]), false); + assert_eq!(nand.tick(vec![true, false]), true); + assert_eq!(nand.tick(vec![false, true]), true); + assert_eq!(nand.tick(vec![false, false]), true); +} + +#[test] +fn generic_gates() { + let and = Gate::new(2, |f| { + let a = f[0]; + let b = f[1]; + a && b + }); + + assert_eq!(and.tick(vec![true, true]), true); + assert_eq!(and.tick(vec![true, false]), false); + assert_eq!(and.tick(vec![false, true]), false); + assert_eq!(and.tick(vec![false, false]), false); + + let not = Gate::new(1, |f| !f[0]); + + assert_eq!(not.tick(vec![true]), false); + assert_eq!(not.tick(vec![false]), true); + + let or = Gate::new(2, |f| { + let a = f[0]; + let b = f[1]; + a | b + }); + + assert_eq!(or.tick(vec![true, true]), true); + assert_eq!(or.tick(vec![true, false]), true); + assert_eq!(or.tick(vec![false, true]), true); + assert_eq!(or.tick(vec![false, false]), false); +} + +fn main() { + let g = Gate::new(2, |f| {true}); + + let mut registry: HashMap<&str, BakedGate> = HashMap::new(); + + let and = Gate::new(2, |f| f[0] && f[1]); + let or = Gate::new(2, |f| f[0] | f[1]); + let not = Gate::new(1, |f| !f[0]); + + registry.insert("AND", and.bake()); + registry.insert("OR", or.bake()); + registry.insert("NOT", not.bake()); + + if let (Some(and), Some(not)) = (registry.get("AND"), registry.get("NOT")) { + + let nand = Gate::new(2, |f| { + not.test(vec![and.test(f)]) + }); + + registry.insert("NAND", nand.bake()); + } + + g.bake(); +}