Refactor Tile::draw_simple, blink support in stackline-cli

main
Shad Amethyst 2 years ago
parent c264001ee0
commit 399883d8ba
Signed by: amethyst
GPG Key ID: D970C8DD1D6DEE36

@ -14,6 +14,8 @@ struct Args {
file: Option<PathBuf>,
}
const BLINK_DURATION: Duration = Duration::new(0, 250_000_000);
fn main() {
let args = Args::parse();
@ -28,6 +30,7 @@ fn main() {
} else {
World::new()
};
world.set_blink(BLINK_DURATION);
loop {
let mut line = String::new();
@ -53,7 +56,22 @@ fn main() {
}
Some("print") => {
print!("{}", world);
if let Some(blinks) = tokens.next().and_then(|b| b.parse::<usize>().ok()) {
let mut first = true;
let mut stdout = std::io::stdout();
for _ in 0..blinks {
if first {
first = false;
} else {
std::thread::sleep(BLINK_DURATION);
write!(stdout, "\x1b[{};A", world.get_bounds().3).unwrap();
}
print!("{}", world);
stdout.flush().unwrap();
}
} else {
print!("{}", world);
}
}
Some("panes") => {
panes(&world);
@ -565,6 +583,7 @@ fn load(world: &mut World, path: impl AsRef<Path>) {
Ok(string) => match serde_json::from_str(&string) {
Ok(parsed) => {
*world = parsed;
world.set_blink(BLINK_DURATION);
}
Err(err) => {
eprintln!("Error while parsing file: {}", err);

@ -1,5 +1,4 @@
use super::*;
use std::time::Duration;
use veccell::{VecRef, VecRefMut};
/** Provides an interface between a [`Tile`] and its parent [`Pane`] during [`Tile::update`].

@ -7,6 +7,7 @@ This library is the rust implementation of the core logic of the language.
*/
#![feature(div_duration)]
#![feature(drain_filter)]
use std::num::NonZeroUsize;

@ -46,6 +46,15 @@ impl<'a> From<&'a str> for Value {
}
}
impl std::fmt::Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::Number(num) => write!(f, "{:.2}", num),
Value::String(string) => write!(f, "\"{}\"", string),
}
}
}
/// The unit of information that [`Tile`]s transmit between each other.
/// A `Signal` is made up of a [`stack`](Signal::stack), and tracks its [`position`](Signal::position) and [`direction`](Signal::direction).
///

@ -169,19 +169,19 @@ pub trait Tile: std::clone::Clone + std::fmt::Debug + Serialize + for<'d> Deseri
// TODO: Use a 2d slice type
#[inline]
#[allow(unused_variables)]
fn draw<'b>(&'b self, surface: &mut TextSurface, ctx: DrawContext<'b>) {
fn draw(&self, surface: &mut TextSurface, ctx: DrawContext<'_>) {
if let (Ok(x), Ok(y)) = (
ctx.surface_coords.0.try_into(),
ctx.surface_coords.1.try_into(),
) {
surface.set(x, y, self.draw_simple(ctx.state));
surface.set(x, y, self.draw_simple(ctx));
}
}
/// Used by the default implementation of `draw`,
#[inline]
#[allow(unused_variables)]
fn draw_simple(&self, state: State) -> TextChar {
fn draw_simple(&self, ctx: DrawContext<'_>) -> TextChar {
TextChar::default()
}
}

@ -142,7 +142,17 @@ impl Blink {
}
}
// TODO: methods for blinking text
pub fn period(&self, amount: usize) -> usize {
if self.blink_speed.is_zero() {
0
} else {
self.elapsed.div_duration_f32(self.blink_speed) as usize % amount
}
}
pub fn scroll(&self, text: &str) -> char {
text.chars().nth(self.period(text.len())).unwrap_or(' ')
}
}
#[cfg(test)]

@ -179,6 +179,10 @@ impl World {
pub fn panes(&self) -> &HashMap<String, Pane> {
&self.panes
}
pub fn set_blink(&mut self, blink_speed: Duration) {
self.blink_speed = blink_speed;
}
}
impl std::fmt::Display for World {

@ -0,0 +1,143 @@
//! Basic stack operations: push a value, pop a value, swap, etc.
use crate::prelude::*;
use crate::tile::prelude::*;
/// Pushes a value on the stack, then lets the signal through
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Push {
value: Value
}
impl Push {
pub fn new(value: Value) -> Self {
Self {
value
}
}
}
impl Default for Push {
fn default() -> Self {
Self::new(Value::Number(0.0))
}
}
impl Tile for Push {
fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) {
if let Some(mut signal) = context.take_signal() {
signal.push(self.value.clone());
if let Some(coords) = context.offset(signal.direction().into_offset()) {
context.send(coords, signal.direction(), signal).unwrap_or_else(|_| unreachable!());
}
}
if context.state() != State::Idle {
context.next_state();
}
}
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
TextChar::from_state('p', ctx.state)
}
}
/// Pops `n` values from the top of the stack, then lets the signal through
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Pop {
amount: usize,
}
impl Pop {
pub fn new(amount: usize) -> Self {
Self {
amount
}
}
}
impl Default for Pop {
fn default() -> Self {
Self::new(1)
}
}
impl Tile for Pop {
fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) {
if let Some(mut signal) = context.take_signal() {
for _ in 0..self.amount {
let _ = signal.pop();
}
if let Some(coords) = context.offset(signal.direction().into_offset()) {
context.send(coords, signal.direction(), signal).unwrap_or_else(|_| unreachable!());
}
}
if context.state() != State::Idle {
context.next_state();
}
}
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
if self.amount == 1 {
TextChar::from_state('P', ctx.state)
} else {
TextChar::from_state(ctx.blink.scroll(&format!("PPP{}", self.amount)), ctx.state)
}
}
}
/// Reverses the order of the top `n` values from the stack, then lets the signal through
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Swap {
amount: usize,
}
impl Swap {
pub fn new(amount: usize) -> Self {
Self {
amount
}
}
}
impl Default for Swap {
fn default() -> Self {
Self::new(2)
}
}
impl Tile for Swap {
fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) {
if let Some(mut signal) = context.take_signal() {
let len = signal.stack().len();
let last_elements = if self.amount > len {
&mut signal.stack_mut()[..]
} else {
&mut signal.stack_mut()[(len - self.amount)..len]
};
last_elements.reverse();
if let Some(coords) = context.offset(signal.direction().into_offset()) {
context.send(coords, signal.direction(), signal).unwrap_or_else(|_| unreachable!());
}
}
if context.state() != State::Idle {
context.next_state();
}
}
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
if self.amount == 2 {
TextChar::from_state('s', ctx.state)
} else {
TextChar::from_state(ctx.blink.scroll(&format!("sss{}", self.amount)), ctx.state)
}
}
}
// TODO: SwapN, RotateLeft, RotateRight, RotateLeftN, RotateRightN

@ -28,8 +28,8 @@ impl Tile for Teleporter {
}
}
fn draw_simple(&self, state: State) -> TextChar {
TextChar::from_state('P', state)
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
TextChar::from_state('P', ctx.state)
}
}

@ -34,14 +34,14 @@ impl Tile for Wire {
self.0.contains(direction)
}
fn draw_simple(&self, state: State) -> TextChar {
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
let ch = match self.0 {
Orientation::Horizontal => '-',
Orientation::Vertical => '|',
Orientation::Any => '+',
};
TextChar::from_state(ch, state)
TextChar::from_state(ch, ctx.state)
}
}
@ -76,7 +76,7 @@ impl Tile for Diode {
direction.opposite() != self.0
}
fn draw_simple(&self, state: State) -> TextChar {
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
let ch = match self.0 {
Direction::Up => '^',
Direction::Down => 'v',
@ -84,7 +84,7 @@ impl Tile for Diode {
Direction::Right => '>',
};
TextChar::from_state(ch, state)
TextChar::from_state(ch, ctx.state)
}
}
@ -119,7 +119,7 @@ impl Tile for Resistor {
}
}
fn draw_simple(&self, state: State) -> TextChar {
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
let ch = match self.direction {
Direction::Up => '\u{2191}', // Upwards Arrow
Direction::Down => '\u{2193}', // Downwards Arrow
@ -127,7 +127,7 @@ impl Tile for Resistor {
Direction::Right => '\u{2192}', // Rightwards Arrow
};
TextChar::from_state(ch, state)
TextChar::from_state(ch, ctx.state)
}
}

Loading…
Cancel
Save