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; font-size: inherit;
margin: 0; margin: 0;
color: white; color: white;
font-weight: normal;
} }
.h3 { .h3 {

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

@ -15,6 +15,7 @@ veccell = { version = "0.4.0", features = ["serde"] }
pathfinding = "3.0" pathfinding = "3.0"
colored = "2.0" colored = "2.0"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_with = "2.0.0"
[dev-dependencies] [dev-dependencies]
criterion = { version = "0.3.5", features = ["html_reports"] } 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. /// Creates a signal with initial values in its stack.
/// ///
/// The syntax for the macro is `signal!(position, direction, [value1, value2, ...])`, where: /// The syntax for the macro is `signal!(position, direction, [value1, value2, ...])`, where:

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

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

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

Loading…
Cancel
Save