Remove Option<Signal> in tiles, Arithmetic

main
Shad Amethyst 2 years ago
parent 386c2ed9ee
commit 0b7596fc1c
Signed by: amethyst
GPG Key ID: D970C8DD1D6DEE36

@ -16,6 +16,7 @@
font-size: inherit;
margin: 0;
color: white;
font-weight: normal;
}
.h3 {

@ -9,16 +9,19 @@ import Number from "./input/Number.jsx";
import Value from "./input/Value.jsx";
import Bool from "./input/Bool.jsx";
import CmpOp from "./input/CmpOp.jsx";
import ArithOp from "./input/ArithOp.jsx";
export const COMPONENTS = new Map();
COMPONENTS.set("Signal", (props) => <Signal signal={props.value} setSignal={props.setValue} />);
COMPONENTS.set("Direction", Direction);
COMPONENTS.set("Orientation", Orientation);
COMPONENTS.set("Orientation|NotAny", (props) => Orientation({...props, not_any: true}));
COMPONENTS.set("Uint", (props) => <Number value={props.value} setValue={props.setValue} min={0} />);
COMPONENTS.set("Int", Number);
COMPONENTS.set("Value", Value);
COMPONENTS.set("CmpOp", CmpOp);
COMPONENTS.set("ArithOp", ArithOp);
export default function Tile(props) {
let {full_tile, set_full_tile} = props;
@ -58,7 +61,7 @@ export default function Tile(props) {
}
return (<>
<h2 class={styles.h2}>Tile:</h2>
<h2 class={styles.h2}><b>Tile:</b> {tile_name()}</h2>
<Show when={tile()} fallback={<i class={styles.gray}>No tile</i>}>
<div class={styles.indent}>
<ol class={styles.properties}>
@ -66,10 +69,12 @@ export default function Tile(props) {
{([label, type, value]) => {
if (COMPONENTS.has(type)) {
let setValue = bindSetValue(label, value);
return (<li><label>
<b class={styles.prop_name}>{label}: </b>
{COMPONENTS.get(type)({value: () => value, setValue})}
</label></li>);
return (<li>
{/* <label> */}
<b class={styles.prop_name}>{label}: </b>
{COMPONENTS.get(type)({value: () => value, setValue})}
{/* </label> */}
</li>);
} else {
return (<li>
<b class={styles.prop_name}>{label}: </b>

@ -0,0 +1,20 @@
import {createEffect} from "solid-js";
import styles from "./input.module.css";
export default function ArithOp(props) {
let {value, setValue} = props;
let select;
createEffect(() => {
select.value = value();
});
return (<select class={styles.select} title="ArithOp" ref={select} onChange={() => setValue(select.value)}>
<option value="Add" default>+ Add</option>
<option value="Sub">- Subtract</option>
<option value="Mul">* Multiply</option>
<option value="Div">/ Divide</option>
<option value="Mod">% Modulo</option>
</select>);
}

@ -11,7 +11,7 @@ export default function Orientation(props) {
});
return (<select class={styles.select} title="Orientation" ref={select} onChange={() => setValue(select.value)}>
<Show when={!props.no_any}><option value="Any" default>Any</option></Show>
<Show when={!props.not_any}><option value="Any" default>Any</option></Show>
<option value="Vertical">Vertical</option>
<option value="Horizontal">Horizontal</option>
</select>);

@ -15,6 +15,7 @@ veccell = { version = "0.4.0", features = ["serde"] }
pathfinding = "3.0"
colored = "2.0"
serde = { version = "1", features = ["derive"] }
serde_with = "2.0.0"
[dev-dependencies]
criterion = { version = "0.3.5", features = ["html_reports"] }

@ -224,6 +224,12 @@ impl PartialEq<Signal> for Signal {
}
}
impl Default for Signal {
fn default() -> Self {
Self::empty(Direction::default())
}
}
/// Creates a signal with initial values in its stack.
///
/// The syntax for the macro is `signal!(position, direction, [value1, value2, ...])`, where:

@ -73,17 +73,17 @@ macro_rules! assert_stored {
let guard = $world
.get_as::<stackline::tile::Store>(($x, $y))
.unwrap_or_else(|| panic!("Couldn't get store tile at {}:{}", $x, $y));
let signal = guard.signal().cloned();
let signal = guard.signal().clone();
assert!(
signal.is_some(),
!signal.is_stack_empty(),
"Expected stored signal at {}:{}!\n{}",
$x,
$y,
$world
);
signal.unwrap()
signal
}};
( $world:expr, $x:expr, $y:expr, $signal:expr ) => {{
@ -108,7 +108,7 @@ macro_rules! assert_no_stored {
let signal = guard.signal();
assert!(
signal.is_none(),
signal.is_stack_empty(),
"Expected no stored signal at {}:{}!\n{}",
$x,
$y,

@ -8,7 +8,7 @@ fn test_if() {
let mut world = load_test!("tests/logic/if.json");
world.init();
world.set_signal((0, 0), signal!([0]));
world.set_signal((0, 0), signal!([-1, 0]));
run!(world, 8);
@ -18,7 +18,7 @@ fn test_if() {
let mut world = load_test!("tests/logic/if.json");
world.init();
world.set_signal((0, 0), signal!([1]));
world.set_signal((0, 0), signal!([-1, 1]));
run!(world, 8);

File diff suppressed because one or more lines are too long

@ -1 +1 @@
{"panes":{"main":{"tiles":[{"cell":{"Diode":"Down"},"signal":null,"state":"Idle","updated":false},{"cell":{"Add":null},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Left"},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":{"Wire":"Vertical"},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":{"Push":{"value":{"Number":1.0}}},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":{"Store":{"signal":{"direction":"Up","stack":[{"Number":0.0}]}}},"signal":null,"state":"Idle","updated":false},{"cell":{"Reader":"Right"},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Up"},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Up"},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false}],"width":4,"height":4,"position":[0,0]}},"blink_speed":{"secs":0,"nanos":250000000}}
{"panes":{"main":{"tiles":[{"cell":{"Diode":"Down"},"signal":null,"state":"Idle","updated":false},{"cell":{"Arithmetic":"Add"},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Left"},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":{"Wire":"Vertical"},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":{"Push":{"value":{"Number":1.0}}},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":{"Store":{"signal":{"direction":"Up","stack":[{"Number":0.0}]}}},"signal":null,"state":"Idle","updated":false},{"cell":{"Reader":"Right"},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Up"},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Up"},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false}],"width":4,"height":4,"position":[0,0]}},"blink_speed":{"secs":0,"nanos":250000000}}

@ -1 +1 @@
{"panes":{"main":{"tiles":[{"cell":{"Diode":"Down"},"signal":null,"state":"Idle","updated":false},{"cell":{"Add":null},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Left"},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":{"Wire":"Vertical"},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":{"Push":{"value":{"Number":1.0}}},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Right"},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Down"},"signal":null,"state":"Idle","updated":false},{"cell":{"Store":{"signal":{"direction":"Right","stack":[{"Number":0.0}]}}},"signal":null,"state":"Idle","updated":false},{"cell":{"Reader":"Right"},"signal":null,"state":"Idle","updated":false},{"cell":{"Wire":"Any"},"signal":null,"state":"Idle","updated":false},{"cell":{"Stacker":{"signal":null,"orientation":"Vertical"}},"signal":null,"state":"Idle","updated":false},{"cell":{"Wire":"Vertical"},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Right"},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Up"},"signal":null,"state":"Idle","updated":false},{"cell":{"Resistor":{"direction":"Right","signal":null}},"signal":null,"state":"Idle","updated":false},{"cell":{"Reader":"Up"},"signal":null,"state":"Idle","updated":false},{"cell":{"Wire":"Vertical"},"signal":null,"state":"Idle","updated":false},{"cell":{"Wire":"Any"},"signal":null,"state":"Idle","updated":false},{"cell":{"Resistor":{"direction":"Right","signal":null}},"signal":null,"state":"Idle","updated":false},{"cell":{"Resistor":{"direction":"Down","signal":null}},"signal":null,"state":"Idle","updated":false},{"cell":{"Store":{"signal":{"direction":"Right","stack":[]}}},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Left"},"signal":null,"state":"Idle","updated":false},{"cell":{"Resistor":{"direction":"Up","signal":null}},"signal":null,"state":"Idle","updated":false},{"cell":{"Resistor":{"direction":"Left","signal":null}},"signal":null,"state":"Idle","updated":false},{"cell":{"Resistor":{"direction":"Left","signal":null}},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false}],"width":5,"height":6,"position":[0,0]}},"blink_speed":{"secs":0,"nanos":250000000}}
{"panes":{"main":{"tiles":[{"cell":{"Diode":"Down"},"signal":null,"state":"Idle","updated":false},{"cell":{"Arithmetic":"Add"},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Left"},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":{"Wire":"Vertical"},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":{"Push":{"value":{"Number":1.0}}},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Right"},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Down"},"signal":null,"state":"Idle","updated":false},{"cell":{"Store":{"signal":{"direction":"Right","stack":[{"Number":0.0}]}}},"signal":null,"state":"Idle","updated":false},{"cell":{"Reader":"Right"},"signal":null,"state":"Idle","updated":false},{"cell":{"Wire":"Any"},"signal":null,"state":"Idle","updated":false},{"cell":{"Stacker":{"signal":null,"orientation":"Vertical"}},"signal":null,"state":"Idle","updated":false},{"cell":{"Wire":"Vertical"},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Right"},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Up"},"signal":null,"state":"Idle","updated":false},{"cell":{"Resistor":{"direction":"Right","signal":null}},"signal":null,"state":"Idle","updated":false},{"cell":{"Reader":"Up"},"signal":null,"state":"Idle","updated":false},{"cell":{"Wire":"Vertical"},"signal":null,"state":"Idle","updated":false},{"cell":{"Wire":"Any"},"signal":null,"state":"Idle","updated":false},{"cell":{"Resistor":{"direction":"Right","signal":null}},"signal":null,"state":"Idle","updated":false},{"cell":{"Resistor":{"direction":"Down","signal":null}},"signal":null,"state":"Idle","updated":false},{"cell":{"Store":{"signal":{"direction":"Right","stack":[]}}},"signal":null,"state":"Idle","updated":false},{"cell":{"Diode":"Left"},"signal":null,"state":"Idle","updated":false},{"cell":{"Resistor":{"direction":"Up","signal":null}},"signal":null,"state":"Idle","updated":false},{"cell":{"Resistor":{"direction":"Left","signal":null}},"signal":null,"state":"Idle","updated":false},{"cell":{"Resistor":{"direction":"Left","signal":null}},"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false},{"cell":null,"signal":null,"state":"Idle","updated":false}],"width":5,"height":6,"position":[0,0]}},"blink_speed":{"secs":0,"nanos":250000000}}

@ -28,130 +28,89 @@ macro_rules! binary_op {
}
}
/// Adds two values together: `[..., a, b] -> [..., a+b]`
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Add;
pub struct Arithmetic(ArithOp);
impl Add {
fn binary_op(&self, left: Value, right: Value) -> Option<Value> {
Some(left + right)
}
}
impl Tile for Add {
binary_op!();
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
TextChar::from_state('\u{2295}', ctx.state) // CIRCLED PLUS
impl Arithmetic {
pub fn new(op: ArithOp) -> Self {
Self(op)
}
}
/// Subtracts two values: `[..., a, b] -> [..., a-b]`
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Sub;
impl Sub {
fn binary_op(&self, left: Value, right: Value) -> Option<Value> {
use Value::*;
match (left, right) {
(Number(x), Number(y)) => Some(Number(x - y)),
(String(mut x), Number(y)) => {
x.truncate(y as usize);
Some(String(x))
}
(String(x), String(y)) => {
Some(String(x.split(&y).collect()))
}
_ => None
}
self.0.binary_op(left, right)
}
}
impl Tile for Sub {
impl Tile for Arithmetic {
binary_op!();
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
TextChar::from_state('\u{2296}', ctx.state) // CIRCLED MINUS
}
}
/// Multiplies two values together: `[..., a, b] -> [..., a*b]`
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Mul;
use ArithOp::*;
impl Mul {
fn binary_op(&self, left: Value, right: Value) -> Option<Value> {
use Value::*;
match (left, right) {
(Number(x), Number(y)) => Some(Number(x * y)),
(String(x), Number(y)) => Some(String(x.repeat(y as usize))),
_ => None
match self.0 {
Add => TextChar::from_state('\u{2295}', ctx.state), // CIRCLED PLUS
Sub => TextChar::from_state('\u{2296}', ctx.state), // CIRCLED MINUS
Mul => TextChar::from_state('\u{2297}', ctx.state), // CIRCLED TIMES
Div => TextChar::from_state('\u{2298}', ctx.state), // CIRCLED DIVISION SLASH
Mod => TextChar::from_state('\u{2299}', ctx.state), // CIRCLED DOT OPERATOR
}
}
}
impl Tile for Mul {
binary_op!();
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
TextChar::from_state('\u{2297}', ctx.state) // CIRCLED TIMES
}
}
/// Divides two values together: `[..., a, b] -> [..., a/b]`
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Div;
impl Div {
fn binary_op(&self, left: Value, right: Value) -> Option<Value> {
use Value::*;
match (left, right) {
(Number(x), Number(y)) => Some(Number(x / y)),
_ => None
}
fn schema(&self) -> TileSchema {
TileSchema::value("Operator", "ArithOp")
}
}
impl Tile for Div {
binary_op!();
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
TextChar::from_state('\u{2298}', ctx.state) // CIRCLED DIVISION SLASH
}
#[derive(Debug, Clone, Serialize, Deserialize, Copy, PartialEq, Eq)]
pub enum ArithOp {
Add,
Sub,
Mul,
Div,
Mod
}
/// Computes the modulo of two values: `[..., a, b] -> [..., a%b]`
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Mod;
impl Mod {
impl ArithOp {
fn binary_op(&self, left: Value, right: Value) -> Option<Value> {
use Value::*;
match (left, right) {
(Number(x), Number(y)) => Some(Number(x % y)),
use ArithOp::*;
match (self, left, right) {
// == Add ==
(Add, left, right) => Some(left + right),
// == Sub ==
(Sub, Number(x), Number(y)) => Some(Number(x - y)),
(Sub, String(mut x), Number(y)) => {
x.truncate(y as usize);
Some(String(x))
}
(Sub, String(x), String(y)) => {
Some(String(x.split(&y).collect()))
}
// == Mul ==
(Mul, Number(x), Number(y)) => Some(Number(x * y)),
(Mul, String(x), Number(y)) => Some(String(x.repeat(y as usize))),
// == Div ==
(Div, Number(x), Number(y)) => Some(Number(x / y)),
// == Mod ==
(Mod, Number(x), Number(y)) => Some(Number(x % y)),
// Default
_ => None
}
}
}
impl Tile for Mod {
binary_op!();
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
TextChar::from_state('\u{2299}', ctx.state) // CIRCLED DOT OPERATOR
impl Default for ArithOp {
fn default() -> Self {
Self::Add
}
}
/// Compares the top two values: `[..., a, b] -> [..., a ?? b]`
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Cmp(Operation);
pub struct Cmp(CmpOp);
#[derive(Debug, Clone, Serialize, Deserialize, Copy, PartialEq, Eq)]
pub enum Operation {
pub enum CmpOp {
Eq,
Neq,
Gt,
@ -163,7 +122,7 @@ pub enum Operation {
impl Cmp {
fn binary_op(&self, left: Value, right: Value) -> Option<Value> {
use Value::*;
use Operation::*;
use CmpOp::*;
let res = match (self.0, left, right) {
(Eq, Number(x), Number(y)) => Some(x == y),
@ -195,7 +154,7 @@ impl Tile for Cmp {
binary_op!();
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
use Operation::*;
use CmpOp::*;
match self.0 {
Eq => TextChar::from_state('\u{229c}', ctx.state), // CIRCLED EQUALS
@ -208,11 +167,11 @@ impl Tile for Cmp {
}
fn schema(&self) -> TileSchema {
TileSchema::value("Operation", "CmpOp")
TileSchema::value("CmpOp", "CmpOp")
}
}
impl Default for Operation {
impl Default for CmpOp {
fn default() -> Self {
Self::Eq
}

@ -3,16 +3,23 @@
use crate::prelude::*;
use crate::tile::prelude::*;
use serde_with::{serde_as, DefaultOnNull};
use veccell::VecRef;
#[serde_as]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Store {
signal: Option<Signal>,
#[serde_as(deserialize_as = "DefaultOnNull")]
signal: Signal,
}
impl Store {
pub fn signal(&self) -> Option<&Signal> {
self.signal.as_ref()
pub fn signal(&self) -> &Signal {
&self.signal
}
pub fn is_empty(&self) -> bool {
self.signal.is_stack_empty()
}
}
@ -25,7 +32,7 @@ impl Tile for Store {
// but by delaying the write we can read from a `Store` without being order-dependent
context.callback(move |pane| {
if let Some(mut this) = pane.borrow_mut_as::<Self>(position) {
this.signal = Some(signal);
this.signal = signal;
}
});
}
@ -36,10 +43,10 @@ impl Tile for Store {
}
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
if self.signal.is_some() {
TextChar::from_state('\u{25c9}', ctx.state) // FISHEYE
} else {
if self.is_empty() {
TextChar::from_state('\u{25cb}', ctx.state) // WHITE CIRCLE
} else {
TextChar::from_state('\u{25c9}', ctx.state) // FISHEYE
}
}
@ -80,7 +87,7 @@ impl Tile for Reader {
let _: Option<()> = try {
let store_position = context.offset(self.0.opposite().into_offset())?;
let store = context.get(store_position).and_then(get_store)?;
let signal = store.signal.clone()?;
let signal = store.signal.clone();
drop(store);
let target_position = context.offset(self.0.into_offset())?;
@ -118,7 +125,7 @@ impl Tile for StorageCount {
for dir in Orientation::Any.into_directions() {
if let Some(store_position) = context.offset(dir.into_offset()) {
if let Some(store) = context.get(store_position).and_then(get_store) {
count += store.signal.is_some() as u8;
count += (!store.is_empty()) as u8;
}
}
}
@ -140,9 +147,11 @@ impl Tile for StorageCount {
}
}
#[serde_as]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Stacker {
signal: Option<Signal>,
#[serde_as(deserialize_as = "DefaultOnNull")]
signal: Signal,
/// May only be Horizontal or Vertical
orientation: Orientation,
}
@ -150,13 +159,17 @@ pub struct Stacker {
impl Stacker {
pub fn new(orientation: Orientation) -> Self {
Self {
signal: None,
signal: Signal::empty(Direction::default()),
orientation,
}
}
pub fn signal(&self) -> Option<&Signal> {
self.signal.as_ref()
pub fn signal(&self) -> &Signal {
&self.signal
}
pub fn is_empty(&self) -> bool {
self.signal.is_stack_empty()
}
}
@ -171,9 +184,7 @@ impl Tile for Stacker {
if let Some(mut signal) = context.take_signal() {
if self.orientation.contains(signal.direction()) {
// Stack the stored signal on top of the incomming signal
if let Some(ref stored) = self.signal {
signal.append(stored);
}
signal.append(&self.signal);
if let Some(target_position) = context.offset(signal.direction().into_offset()) {
let _ = context.send(target_position, signal.direction(), signal);
@ -184,7 +195,7 @@ impl Tile for Stacker {
}
} else {
// Store the signal inside of ourselves
self.signal = Some(signal);
self.signal = signal;
context.set_state(State::Idle);
}
@ -206,7 +217,7 @@ impl Tile for Stacker {
fn schema(&self) -> TileSchema {
TileSchema::map()
.add("signal", TileSchema::value("Signal to stack", "Signal"))
.add("orientation", TileSchema::value("Orientation", "Orientation"))
.add("orientation", TileSchema::value("Orientation", "Orientation|NotAny"))
}
}

Loading…
Cancel
Save