Choose values randomly

This commit is contained in:
Nicolas 2022-04-09 18:25:45 +02:00
parent 1dcc712983
commit 35ca4b2605
2 changed files with 104 additions and 8 deletions

61
src/choose.rs Normal file
View 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));
}
}

View File

@ -3,10 +3,11 @@ use std::time::Duration;
use anyhow::Error; use anyhow::Error;
use clap::Parser; use clap::Parser;
use clap::ArgEnum; use clap::ArgEnum;
use crossterm::style::Color::*; use rand::rngs::OsRng;
use crate::animation::Animation; use crate::animation::Animation;
use crate::animation::circle::CircleAnimation; use crate::animation::circle::CircleAnimation;
use crate::char::SimpleCharSampler; use crate::char::SimpleCharSampler;
use crate::choose::{Chooser, Options};
use crate::color::{ColorSampler, SimpleColorSampler}; use crate::color::{ColorSampler, SimpleColorSampler};
use crate::fill::circle::CircleFillMode; use crate::fill::circle::CircleFillMode;
use crate::fill::FillMode; use crate::fill::FillMode;
@ -29,12 +30,21 @@ mod sampler;
mod render; mod render;
mod timer; mod timer;
mod runner; mod runner;
mod choose;
#[derive(Copy, Clone, ArgEnum)] #[derive(Copy, Clone, ArgEnum)]
enum AnimationType { enum AnimationType {
Circle Circle
} }
impl Options for AnimationType {
fn all() -> Vec<Self> where Self: Sized {
use AnimationType::*;
vec![Circle]
}
}
#[derive(Copy, Clone, ArgEnum)] #[derive(Copy, Clone, ArgEnum)]
enum ColorType { enum ColorType {
Red, Red,
@ -47,12 +57,28 @@ enum ColorType {
Rainbow, 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)] #[derive(Copy, Clone, ArgEnum)]
enum FillModeType { enum FillModeType {
Circle, Circle,
Level Level
} }
impl Options for FillModeType {
fn all() -> Vec<Self> where Self: Sized {
use FillModeType::*;
vec![Circle, Level]
}
}
#[derive(Parser)] #[derive(Parser)]
#[clap(author = env!("CARGO_PKG_AUTHORS"), version = env!("CARGO_PKG_VERSION"), about = env!("CARGO_PKG_DESCRIPTION"))] #[clap(author = env!("CARGO_PKG_AUTHORS"), version = env!("CARGO_PKG_VERSION"), about = env!("CARGO_PKG_DESCRIPTION"))]
struct Args { struct Args {
@ -64,6 +90,10 @@ struct Args {
color: Vec<ColorType>, color: Vec<ColorType>,
#[clap(long, default_value = ".-+%#", help = "Set chars")] #[clap(long, default_value = ".-+%#", help = "Set chars")]
chars: String, 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]")] #[clap(long, help = "Set width [default: terminal width]")]
width: Option<usize>, width: Option<usize>,
#[clap(long, help = "Set height [default: terminal height]")] #[clap(long, help = "Set height [default: terminal height]")]
@ -72,23 +102,26 @@ struct Args {
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
let args = Args::parse(); let args = Args::parse();
let mut chooser = Chooser::new(OsRng::default());
let terminal = crossterm::terminal::size()?; let terminal = crossterm::terminal::size()?;
let width = args.width.unwrap_or(terminal.0 as usize); 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 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 animation = create_animation(chooser.choose(args.animation), size);
let fill = create_fill(args.fill[0], size); let fill = create_fill(chooser.choose(args.fill), size);
let color = create_color(args.color[0]); let color = create_color(chooser.choose(args.color));
let char = Box::new(SimpleCharSampler::new(args.chars)); let char = Box::new(SimpleCharSampler::new(args.chars));
let sampler = ComposedSampler::new(animation, fill, color, char); 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 renderer = SamplerRenderer::new(surface, sampler);
let timer = SimpleTimer::new(Duration::from_millis(1000 / 60)); let timer = SimpleTimer::new(delay);
let runner = Runner::new(Duration::from_secs(2), timer, renderer); let runner = Runner::new(duration, timer, renderer);
runner.run() runner.run()
} }
@ -107,6 +140,8 @@ fn create_fill(fill: FillModeType, size: Vector) -> Box<dyn FillMode> {
} }
fn create_color(color: ColorType) -> Box<dyn ColorSampler> { fn create_color(color: ColorType) -> Box<dyn ColorSampler> {
use crossterm::style::Color::*;
match color { match color {
ColorType::Red => Box::new(SimpleColorSampler::new(vec![Yellow, DarkYellow, Red])), ColorType::Red => Box::new(SimpleColorSampler::new(vec![Yellow, DarkYellow, Red])),
ColorType::Green => Box::new(SimpleColorSampler::new(vec![Cyan, DarkGreen, Green])), ColorType::Green => Box::new(SimpleColorSampler::new(vec![Cyan, DarkGreen, Green])),