Skip to content

Commit

Permalink
switch node, speed slider
Browse files Browse the repository at this point in the history
wasm
  • Loading branch information
mkhan45 committed Apr 11, 2021
1 parent 9736927 commit 9683d97
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 49 deletions.
Binary file modified docs/simple_electronics.wasm
Binary file not shown.
20 changes: 13 additions & 7 deletions src/components.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,38 @@
use core::marker::PhantomData;
use macroquad::prelude::Vec2;
use specs::{prelude::*, Component};

pub mod nodes;

pub trait Node<const I: usize, const O: usize> {
fn calculate_state(inputs: [bool; I]) -> [bool; O]
where
Self: Sized;
pub trait Node<const I: usize, const O: usize>: Default {
fn calculate_state(&self, inputs: [bool; I]) -> [bool; O];
}

#[derive(Component)]
pub struct Connected<N, const I: usize, const O: usize>
where
N: Node<I, O> + 'static,
{
pub node: PhantomData<N>,
pub node: N,
pub inputs: [Option<Entity>; I],
pub outputs: [Option<Entity>; O],
}

impl<N, const I: usize, const O: usize> Connected<N, I, O>
where
N: Node<I, O> + 'static,
{
pub fn calculate_state(&self, inputs: [bool; I]) -> [bool; O] {
self.node.calculate_state(inputs)
}
}

impl<N, const I: usize, const O: usize> Default for Connected<N, I, O>
where
N: Node<I, O> + 'static,
{
fn default() -> Self {
Connected {
node: PhantomData::<N>,
node: N::default(),
inputs: [None; I],
outputs: [None; O],
}
Expand Down
33 changes: 23 additions & 10 deletions src/components/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct Wire {
}

impl Node<1, 1> for Wire {
fn calculate_state(i: [bool; 1]) -> [bool; 1] {
fn calculate_state(&self, i: [bool; 1]) -> [bool; 1] {
i
}
}
Expand All @@ -28,80 +28,92 @@ pub enum NodeTy {
NorNode,
XorNode,
XnorNode,
SwitchNode,
}

#[derive(Default)]
pub struct OnNode;
impl Node<0, 1> for OnNode {
fn calculate_state(_: [bool; 0]) -> [bool; 1] {
fn calculate_state(&self, _: [bool; 0]) -> [bool; 1] {
[true]
}
}

#[derive(Default)]
pub struct OffNode;
impl Node<0, 1> for OffNode {
fn calculate_state(_: [bool; 0]) -> [bool; 1] {
fn calculate_state(&self, _: [bool; 0]) -> [bool; 1] {
[false]
}
}

#[derive(Default)]
pub struct NotNode;
impl Node<1, 1> for NotNode {
fn calculate_state(input: [bool; 1]) -> [bool; 1] {
fn calculate_state(&self, input: [bool; 1]) -> [bool; 1] {
[!input[0]]
}
}

#[derive(Default)]
pub struct AndNode;
impl Node<2, 1> for AndNode {
fn calculate_state(input: [bool; 2]) -> [bool; 1] {
fn calculate_state(&self, input: [bool; 2]) -> [bool; 1] {
[input[0] && input[1]]
}
}

#[derive(Default)]
pub struct OrNode;
impl Node<2, 1> for OrNode {
fn calculate_state(input: [bool; 2]) -> [bool; 1] {
fn calculate_state(&self, input: [bool; 2]) -> [bool; 1] {
[input[0] || input[1]]
}
}

#[derive(Default)]
pub struct NandNode;
impl Node<2, 1> for NandNode {
fn calculate_state(input: [bool; 2]) -> [bool; 1] {
fn calculate_state(&self, input: [bool; 2]) -> [bool; 1] {
[!(input[0] && input[1])]
}
}

#[derive(Default)]
pub struct NorNode;
impl Node<2, 1> for NorNode {
fn calculate_state(input: [bool; 2]) -> [bool; 1] {
fn calculate_state(&self, input: [bool; 2]) -> [bool; 1] {
[!(input[0] || input[1])]
}
}

#[derive(Default)]
pub struct XorNode;
impl Node<2, 1> for XorNode {
fn calculate_state(input: [bool; 2]) -> [bool; 1] {
fn calculate_state(&self, input: [bool; 2]) -> [bool; 1] {
[input[0] ^ input[1]]
}
}

#[derive(Default)]
pub struct XnorNode;
impl Node<2, 1> for XnorNode {
fn calculate_state(input: [bool; 2]) -> [bool; 1] {
fn calculate_state(&self, input: [bool; 2]) -> [bool; 1] {
[!(input[0] ^ input[1])]
}
}

#[derive(Default)]
pub struct SwitchNode {
pub state: bool,
}

impl Node<0, 1> for SwitchNode {
fn calculate_state(&self, _input: [bool; 0]) -> [bool; 1] {
[self.state]
}
}

#[macro_export]
macro_rules! all_nodes {
($macro:ident) => {
Expand All @@ -116,6 +128,7 @@ macro_rules! all_nodes {
[NorNode, 2, 1],
[XorNode, 2, 1],
[XnorNode, 2, 1],
[SwitchNode, 0, 1],
)
};
}
Expand Down
12 changes: 6 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::nodes::Wire;
use crate::resources::UiSignal;
use core::marker::PhantomData;
use egui_macroquad;
use macroquad::prelude::*;
use specs::prelude::*;
Expand Down Expand Up @@ -99,7 +98,7 @@ async fn main() {
world
.create_entity()
.with(Connected {
node: PhantomData::<nodes::OnNode>,
node: nodes::SwitchNode::default(),
inputs: [],
outputs: [Some(wire_1)],
})
Expand All @@ -109,7 +108,7 @@ async fn main() {
world
.create_entity()
.with(Connected {
node: PhantomData::<nodes::OnNode>,
node: nodes::SwitchNode { state: true },
inputs: [],
outputs: [Some(wire_2)],
})
Expand All @@ -119,7 +118,7 @@ async fn main() {
world
.create_entity()
.with(Connected {
node: PhantomData::<nodes::XnorNode>,
node: nodes::XorNode::default(),
inputs: [Some(wire_1), Some(wire_2)],
outputs: [Some(wire_3)],
})
Expand All @@ -129,14 +128,15 @@ async fn main() {
world
.create_entity()
.with(Connected {
node: PhantomData::<nodes::NandNode>,
node: nodes::AndNode::default(),
inputs: [Some(wire_2), Some(wire_1)],
outputs: [Some(wire_4)],
})
.with(Pos::from_vec(Vec2::new(350.0, 2.0 * screen_height() / 3.0)))
.build();

world.insert(resources::Tick(0));
world.insert(resources::TickFrames(60));

let mut last_fps = [60i32; 256];

Expand All @@ -146,7 +146,7 @@ async fn main() {
last_fps[i % last_fps.len()] = get_fps();

// let tick_frames: usize = (last_fps.iter().sum::<i32>() / last_fps.len() as i32) as usize;
let tick_frames = 144;
let tick_frames = world.fetch::<resources::TickFrames>().0;

world.insert(resources::TickProgress(
(i % tick_frames) as f64 / tick_frames as f64,
Expand Down
3 changes: 3 additions & 0 deletions src/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ impl Tick {
}
}

#[derive(Clone, Copy, Default)]
pub struct TickFrames(pub usize);

#[derive(Eq, PartialEq, Copy, Clone)]
pub enum GridMode {
Lines,
Expand Down
47 changes: 29 additions & 18 deletions src/systems/draw_systems.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::nodes::SwitchNode;
use crate::Wire;
use crate::{components::nodes::NandNode, nodes::NotNode};
use crate::{components::nodes::NorNode, nodes::OnNode};
Expand All @@ -22,7 +23,7 @@ where
N: Node<I, O> + 'static,
{
node: PhantomData<N>,
draw_fn: Arc<dyn Fn(Pos, &Textures)>,
draw_fn: Arc<dyn Fn(&N, Pos, &Textures)>,
input_offsets: [Vec2; I],
}

Expand Down Expand Up @@ -220,7 +221,7 @@ where
}
}
});
(self.draw_fn)(*self_pos, &textures);
(self.draw_fn)(&node.node, *self_pos, &textures);
});
}
}
Expand Down Expand Up @@ -336,21 +337,21 @@ pub fn add_draw_system<'a, 'b>(builder: DispatcherBuilder<'a, 'b>) -> Dispatcher
.with_thread_local(DrawGridSys)
.with_thread_local(DrawNodeSys {
node: PhantomData::<OnNode>,
draw_fn: Arc::new(|Pos { pos, .. }, _| {
draw_fn: Arc::new(|_, Pos { pos, .. }, _| {
draw_circle(pos.x, pos.y, 25.0, RED);
}),
input_offsets: [],
})
.with_thread_local(DrawNodeSys {
node: PhantomData::<OffNode>,
draw_fn: Arc::new(|Pos { pos, .. }, _| {
draw_fn: Arc::new(|_, Pos { pos, .. }, _| {
draw_circle(pos.x, pos.y, 25.0, WHITE);
}),
input_offsets: [],
})
.with_thread_local(DrawNodeSys {
node: PhantomData::<NotNode>,
draw_fn: Arc::new(|Pos { pos, .. }, textures: &Textures| {
draw_fn: Arc::new(|_, Pos { pos, .. }, textures: &Textures| {
let texture = textures.0.get("NOT_GATE").unwrap();
let w = 50.0;
let h = 50.0;
Expand All @@ -369,7 +370,7 @@ pub fn add_draw_system<'a, 'b>(builder: DispatcherBuilder<'a, 'b>) -> Dispatcher
})
.with_thread_local(DrawNodeSys {
node: PhantomData::<AndNode>,
draw_fn: Arc::new(|Pos { pos, .. }, textures: &Textures| {
draw_fn: Arc::new(|_, Pos { pos, .. }, textures: &Textures| {
let texture = textures.0.get("AND_GATE").unwrap();
let w = 75.0;
let h = 50.0;
Expand All @@ -384,11 +385,11 @@ pub fn add_draw_system<'a, 'b>(builder: DispatcherBuilder<'a, 'b>) -> Dispatcher
},
);
}),
input_offsets: [Vec2::new(-25.0, -10.0), Vec2::new(-25.0, 10.0)],
input_offsets: [Vec2::new(-25.0, -15.0), Vec2::new(-25.0, 15.0)],
})
.with_thread_local(DrawNodeSys {
node: PhantomData::<OrNode>,
draw_fn: Arc::new(|Pos { pos, .. }, textures: &Textures| {
draw_fn: Arc::new(|_, Pos { pos, .. }, textures: &Textures| {
let texture = textures.0.get("OR_GATE").unwrap();
let w = 100.0;
let h = 75.0;
Expand All @@ -403,11 +404,11 @@ pub fn add_draw_system<'a, 'b>(builder: DispatcherBuilder<'a, 'b>) -> Dispatcher
},
);
}),
input_offsets: [Vec2::new(-25.0, -10.0), Vec2::new(-25.0, 10.0)],
input_offsets: [Vec2::new(-25.0, -15.0), Vec2::new(-25.0, 15.0)],
})
.with_thread_local(DrawNodeSys {
node: PhantomData::<NandNode>,
draw_fn: Arc::new(|Pos { pos, .. }, textures: &Textures| {
draw_fn: Arc::new(|_, Pos { pos, .. }, textures: &Textures| {
let texture = textures.0.get("NAND_GATE").unwrap();
let w = 100.0;
let h = 75.0;
Expand All @@ -422,11 +423,11 @@ pub fn add_draw_system<'a, 'b>(builder: DispatcherBuilder<'a, 'b>) -> Dispatcher
},
);
}),
input_offsets: [Vec2::new(-25.0, -10.0), Vec2::new(-25.0, 10.0)],
input_offsets: [Vec2::new(-25.0, -15.0), Vec2::new(-25.0, 15.0)],
})
.with_thread_local(DrawNodeSys {
node: PhantomData::<NorNode>,
draw_fn: Arc::new(|Pos { pos, .. }, textures: &Textures| {
draw_fn: Arc::new(|_, Pos { pos, .. }, textures: &Textures| {
let texture = textures.0.get("NOR_GATE").unwrap();
let w = 100.0;
let h = 75.0;
Expand All @@ -441,11 +442,11 @@ pub fn add_draw_system<'a, 'b>(builder: DispatcherBuilder<'a, 'b>) -> Dispatcher
},
);
}),
input_offsets: [Vec2::new(-25.0, -10.0), Vec2::new(-25.0, 10.0)],
input_offsets: [Vec2::new(-25.0, -15.0), Vec2::new(-25.0, 15.0)],
})
.with_thread_local(DrawNodeSys {
node: PhantomData::<XorNode>,
draw_fn: Arc::new(|Pos { pos, .. }, textures: &Textures| {
draw_fn: Arc::new(|_, Pos { pos, .. }, textures: &Textures| {
let texture = textures.0.get("XOR_GATE").unwrap();
let w = 100.0;
let h = 75.0;
Expand All @@ -460,11 +461,11 @@ pub fn add_draw_system<'a, 'b>(builder: DispatcherBuilder<'a, 'b>) -> Dispatcher
},
);
}),
input_offsets: [Vec2::new(-25.0, -10.0), Vec2::new(-25.0, 10.0)],
input_offsets: [Vec2::new(-26.0, -15.0), Vec2::new(-26.0, 15.0)],
})
.with_thread_local(DrawNodeSys {
node: PhantomData::<XnorNode>,
draw_fn: Arc::new(|Pos { pos, .. }, textures: &Textures| {
draw_fn: Arc::new(|_, Pos { pos, .. }, textures: &Textures| {
let texture = textures.0.get("XNOR_GATE").unwrap();
let w = 100.0;
let h = 75.0;
Expand All @@ -479,13 +480,23 @@ pub fn add_draw_system<'a, 'b>(builder: DispatcherBuilder<'a, 'b>) -> Dispatcher
},
);
}),
input_offsets: [Vec2::new(-25.0, -10.0), Vec2::new(-25.0, 10.0)],
input_offsets: [Vec2::new(-26.5, -15.0), Vec2::new(-26.5, 15.0)],
})
.with_thread_local(DrawNodeSys {
node: PhantomData::<Wire>,
draw_fn: Arc::new(|Pos { pos, .. }, _: &Textures| {
draw_fn: Arc::new(|_, Pos { pos, .. }, _: &Textures| {
draw_circle(pos.x, pos.y, 10.0, WHITE);
}),
input_offsets: [Vec2::new(0.0, 0.0)],
})
.with_thread_local(DrawNodeSys {
node: PhantomData::<SwitchNode>,
draw_fn: Arc::new(|node: &SwitchNode, Pos { pos, .. }, _: &Textures| {
let color = if node.state { RED } else { WHITE };
draw_rectangle(pos.x - 30.0, pos.y - 30.0, 60.0, 60.0, WHITE);
draw_circle(pos.x, pos.y, 25.0, color);
draw_circle_lines(pos.x, pos.y, 25.0, 2.5, BLACK);
}),
input_offsets: [],
})
}
2 changes: 1 addition & 1 deletion src/systems/simulation_systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ where
}
}

let outputs = N::calculate_state(inputs);
let outputs = node.calculate_state(inputs);

for (i, output_entity) in node.outputs.iter().enumerate() {
if let Some(e) = output_entity {
Expand Down
Loading

0 comments on commit 9683d97

Please sign in to comment.