This commit is contained in:
2025-10-22 14:17:43 -06:00
commit d1176cff5f
3 changed files with 270 additions and 0 deletions

7
Cargo.lock generated Normal file
View File

@@ -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"

6
Cargo.toml Normal file
View File

@@ -0,0 +1,6 @@
[package]
name = "logic_gates"
version = "0.1.0"
edition = "2024"
[dependencies]

257
src/main.rs Normal file
View File

@@ -0,0 +1,257 @@
#![feature(trait_alias)]
use std::collections::HashMap;
struct BakedGate {
table: Vec<bool>
}
impl BakedGate {
fn test(&self, input: Vec<bool>) -> bool {
let mut total = 0;
for (i, input) in input.iter().enumerate() {
if *input {
total += 1 << i
}
}
self.table[total]
}
}
struct Gate<T> {
function: T,
qty_inputs: usize,
qty_outputs: usize,
}
trait Logic = Fn(Vec<bool>) -> bool;
impl<T: Logic> Gate<T> {
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>) -> 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<Box<dyn Logic>>> = HashMap::new();
let and: Gate<Box<dyn Logic>> = Gate::new(
2,
Box::new(|f| f[0] && f[1]),
);
registry.insert("AND", and);
let not: Gate<Box<dyn Logic>> = 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<Box<dyn Logic>> = 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();
}