mirror of
https://github.com/ricoriedel/wipe.git
synced 2024-11-22 16:06:38 +00:00
Choose values randomly
This commit is contained in:
parent
1dcc712983
commit
35ca4b2605
61
src/choose.rs
Normal file
61
src/choose.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use rand::prelude::IteratorRandom;
|
||||
use rand::Rng;
|
||||
|
||||
pub trait Options {
|
||||
fn all() -> Vec<Self> where Self: Sized;
|
||||
}
|
||||
|
||||
pub struct Chooser<TRng> {
|
||||
rng: TRng
|
||||
}
|
||||
|
||||
impl<TRng: Rng> Chooser<TRng> {
|
||||
pub fn new(rng: TRng) -> Self {
|
||||
Self { rng }
|
||||
}
|
||||
|
||||
pub fn choose<TValue: Options>(&mut self, selection: Vec<TValue>) -> TValue {
|
||||
let options = if selection.is_empty() {
|
||||
TValue::all()
|
||||
} else {
|
||||
selection
|
||||
};
|
||||
options.into_iter().choose_stable(&mut self.rng).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rand::rngs::mock::StepRng;
|
||||
use crate::{Chooser, Options};
|
||||
|
||||
enum MockOptions {
|
||||
First,
|
||||
Second,
|
||||
Third
|
||||
}
|
||||
|
||||
impl Options for MockOptions {
|
||||
fn all() -> Vec<Self> where Self: Sized {
|
||||
use MockOptions::*;
|
||||
|
||||
vec![First, Second, Third]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn choose() {
|
||||
let rng = StepRng::new(0, 1);
|
||||
let mut chooser = Chooser::new(rng);
|
||||
|
||||
assert!(matches!(chooser.choose(vec![MockOptions::First, MockOptions::Second]), MockOptions::Second));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn choose_empty() {
|
||||
let rng = StepRng::new(0, 1);
|
||||
let mut chooser = Chooser::new(rng);
|
||||
|
||||
assert!(matches!(chooser.choose(Vec::new()), MockOptions::Third));
|
||||
}
|
||||
}
|
51
src/main.rs
51
src/main.rs
@ -3,10 +3,11 @@ use std::time::Duration;
|
||||
use anyhow::Error;
|
||||
use clap::Parser;
|
||||
use clap::ArgEnum;
|
||||
use crossterm::style::Color::*;
|
||||
use rand::rngs::OsRng;
|
||||
use crate::animation::Animation;
|
||||
use crate::animation::circle::CircleAnimation;
|
||||
use crate::char::SimpleCharSampler;
|
||||
use crate::choose::{Chooser, Options};
|
||||
use crate::color::{ColorSampler, SimpleColorSampler};
|
||||
use crate::fill::circle::CircleFillMode;
|
||||
use crate::fill::FillMode;
|
||||
@ -29,12 +30,21 @@ mod sampler;
|
||||
mod render;
|
||||
mod timer;
|
||||
mod runner;
|
||||
mod choose;
|
||||
|
||||
#[derive(Copy, Clone, ArgEnum)]
|
||||
enum AnimationType {
|
||||
Circle
|
||||
}
|
||||
|
||||
impl Options for AnimationType {
|
||||
fn all() -> Vec<Self> where Self: Sized {
|
||||
use AnimationType::*;
|
||||
|
||||
vec![Circle]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, ArgEnum)]
|
||||
enum ColorType {
|
||||
Red,
|
||||
@ -47,12 +57,28 @@ enum ColorType {
|
||||
Rainbow,
|
||||
}
|
||||
|
||||
impl Options for ColorType {
|
||||
fn all() -> Vec<Self> where Self: Sized {
|
||||
use ColorType::*;
|
||||
|
||||
vec![Red, Green, Blue, LightRed, LightGreen, LightBlue, Grey, Rainbow]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, ArgEnum)]
|
||||
enum FillModeType {
|
||||
Circle,
|
||||
Level
|
||||
}
|
||||
|
||||
impl Options for FillModeType {
|
||||
fn all() -> Vec<Self> where Self: Sized {
|
||||
use FillModeType::*;
|
||||
|
||||
vec![Circle, Level]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(author = env!("CARGO_PKG_AUTHORS"), version = env!("CARGO_PKG_VERSION"), about = env!("CARGO_PKG_DESCRIPTION"))]
|
||||
struct Args {
|
||||
@ -64,6 +90,10 @@ struct Args {
|
||||
color: Vec<ColorType>,
|
||||
#[clap(long, default_value = ".-+%#", help = "Set chars")]
|
||||
chars: String,
|
||||
#[clap(long, default_value = "30", help = "Set frames per second")]
|
||||
fps: u64,
|
||||
#[clap(long, default_value = "1000", help = "Set duration [milliseconds]")]
|
||||
duration: u64,
|
||||
#[clap(long, help = "Set width [default: terminal width]")]
|
||||
width: Option<usize>,
|
||||
#[clap(long, help = "Set height [default: terminal height]")]
|
||||
@ -72,23 +102,26 @@ struct Args {
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
let args = Args::parse();
|
||||
let mut chooser = Chooser::new(OsRng::default());
|
||||
|
||||
let terminal = crossterm::terminal::size()?;
|
||||
let width = args.width.unwrap_or(terminal.0 as usize);
|
||||
let height = args.width.unwrap_or(terminal.1 as usize);
|
||||
let height = args.height.unwrap_or(terminal.1 as usize);
|
||||
let size = Vector::from_terminal(width, height);
|
||||
let delay = Duration::from_micros(1_000_000 / args.fps);
|
||||
let duration = Duration::from_millis(args.duration);
|
||||
|
||||
let animation = create_animation(args.animation[0], size);
|
||||
let fill = create_fill(args.fill[0], size);
|
||||
let color = create_color(args.color[0]);
|
||||
let animation = create_animation(chooser.choose(args.animation), size);
|
||||
let fill = create_fill(chooser.choose(args.fill), size);
|
||||
let color = create_color(chooser.choose(args.color));
|
||||
let char = Box::new(SimpleCharSampler::new(args.chars));
|
||||
|
||||
let sampler = ComposedSampler::new(animation, fill, color, char);
|
||||
let surface =WriteSurface::new(stdout(), width, height);
|
||||
let surface = WriteSurface::new(stdout(), width, height);
|
||||
|
||||
let renderer = SamplerRenderer::new(surface, sampler);
|
||||
let timer = SimpleTimer::new(Duration::from_millis(1000 / 60));
|
||||
let runner = Runner::new(Duration::from_secs(2), timer, renderer);
|
||||
let timer = SimpleTimer::new(delay);
|
||||
let runner = Runner::new(duration, timer, renderer);
|
||||
|
||||
runner.run()
|
||||
}
|
||||
@ -107,6 +140,8 @@ fn create_fill(fill: FillModeType, size: Vector) -> Box<dyn FillMode> {
|
||||
}
|
||||
|
||||
fn create_color(color: ColorType) -> Box<dyn ColorSampler> {
|
||||
use crossterm::style::Color::*;
|
||||
|
||||
match color {
|
||||
ColorType::Red => Box::new(SimpleColorSampler::new(vec![Yellow, DarkYellow, Red])),
|
||||
ColorType::Green => Box::new(SimpleColorSampler::new(vec![Cyan, DarkGreen, Green])),
|
||||
|
Loading…
Reference in New Issue
Block a user