Skip to content

Commit

Permalink
Merge pull request #15 from ckaznable/refactor
Browse files Browse the repository at this point in the history
Code Refactor
  • Loading branch information
ckaznable authored Apr 9, 2024
2 parents 9cf863f + 165de9f commit 78211d8
Show file tree
Hide file tree
Showing 16 changed files with 617 additions and 490 deletions.
376 changes: 19 additions & 357 deletions src/app.rs

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use std::str::FromStr;
use clap::Parser;
use clap_num::number_range;
use ratatui::style::Color;
use crate::app::{Mode, WindMode};

#[derive(Parser)]
use crate::state::{wind::WindMode, Mode};

#[derive(Parser, Clone, Copy)]
#[command(author, version, about, long_about = None)]
pub struct Args {
#[arg(long, default_value_t = Mode::Rain)]
Expand Down
6 changes: 4 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
mod app;
mod cli;
mod state;
mod tui;
mod ui;
mod util;
mod weather;
mod widget;

use anyhow::Result;
use app::App;
use clap::Parser;
use cli::Args;
use weather::Weather;

#[tokio::main]
async fn main() -> Result<()> {
let args = Args::parse();
let mut app = App::new(args)?;
let mut app = App::new(args, Weather::from(args))?;
app.run().await?;
Ok(())
}

33 changes: 33 additions & 0 deletions src/state/buffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use std::cell::RefCell;
use std::rc::Rc;

use ratatui::layout::Rect;
use tinyvec::ArrayVec;

use super::DropColumn;
use super::DropSpeed;

pub struct RenderBuffer {
pub buf: Vec<DropColumn>,
pub line: Vec<DropSpeed>,
}

impl RenderBuffer {
pub fn new(size: Rect) -> Self {
let mut buf = Vec::with_capacity(size.width as usize);
for _ in 0..size.width {
let mut column = Vec::with_capacity(size.height as usize);
for _ in 0..size.height {
column.push(ArrayVec::<[DropSpeed; 3]>::default());
}

buf.push(Rc::new(RefCell::new(column)));
}

Self {
line: Vec::with_capacity(buf.len()),
buf,
}
}
}

116 changes: 116 additions & 0 deletions src/state/dropping.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use super::{buffer::RenderBuffer, DropCell, DropColumn, DropSpeed, Mode, EachFrameImpl};

pub struct DroppingState {
pub threshold: u16,
pub mode: Mode,
}

impl DroppingState {
fn gen_drop(&self, rb: &mut RenderBuffer, seed: u64) {
rb.line.clear();

const GROUP_SIZE: u64 = 64;
let len = rb.buf.len() as u64;
let last_group = len % GROUP_SIZE;
let groups = len / GROUP_SIZE + if last_group > 0 { 1 } else { 0 };

for g in 0..groups {
let range = if groups.saturating_sub(1) == g { last_group } else { GROUP_SIZE };
for i in 0..range {
rb.line.push(if seed & (1 << i) != 0 {
Self::get_drop_speed(seed.saturating_sub(i), self.threshold)
} else {
DropSpeed::None
});
}
}
}

/// generate new drop line
fn new_drop(&self, rb: &mut RenderBuffer, seed: u64) {
self.gen_drop(rb, seed);
rb.line
.iter()
.enumerate()
.for_each(|(i, d)| {
if let Some(cell) = rb.buf
.get_mut(i)
.unwrap()
.try_borrow_mut()
.unwrap()
.get_mut(0) {

*cell = Self::merge_drop_state(*cell, *d)
};
});
}

fn drop(col: &mut DropColumn, ticks: u8, mode: Mode) {
let len = col.borrow().len();

for col_index in 0..len {
let next_index = len.saturating_sub(col_index.saturating_add(1));
let current_index = len.saturating_sub(col_index.saturating_add(2));
let current = { col.borrow().get(current_index).cloned() };
let Some(current) = current else { continue; };
let mut column = col.try_borrow_mut().unwrap();

'state: for i in 0..current.len() {
let state = match current.get(i) {
Some(s) if ticks % mode.get_frame_by_speed(*s) == 0 => s,
_ => continue 'state
};

column[current_index] = Self::remove_drop_state(column[current_index], *state);
column[next_index] = Self::merge_drop_state(column[next_index], *state);
}
}
}

#[inline]
fn clean_latest_drop(col: &mut DropColumn) {
let len = col.borrow().len();
if len > 0 {
let mut col = col.try_borrow_mut().unwrap();
if let Some(c) = col.get_mut(len - 1) {
c.clear()
};
}
}

#[inline]
fn merge_drop_state(mut cell: DropCell, state: DropSpeed) -> DropCell {
if !cell.contains(&state) && state != DropSpeed::None {
cell.push(state);
};

cell
}

#[inline]
fn remove_drop_state(cell: DropCell, state: DropSpeed) -> DropCell {
cell.into_iter().filter(|c| *c != state).collect()
}

#[inline]
fn get_drop_speed(num: u64, threshold: u16) -> DropSpeed {
match num % threshold as u64 {
0 => DropSpeed::Normal,
1 => DropSpeed::Fast,
2 => DropSpeed::Slow,
_ => DropSpeed::None,
}
}
}

impl EachFrameImpl for DroppingState {
fn on_frame(&mut self, rb: &mut super::buffer::RenderBuffer, seed: u64, frame: u8) {
// each column
for i in 0..rb.buf.len() {
Self::clean_latest_drop(&mut rb.buf[i]);
Self::drop(&mut rb.buf[i], frame, self.mode);
}

self.new_drop(rb, seed);
}
}
119 changes: 119 additions & 0 deletions src/state/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
use std::{cell::RefCell, fmt::Display, rc::Rc};

use clap::ValueEnum;
use rand::{rngs::SmallRng, RngCore, SeedableRng};
use ratatui::layout::Rect;
use tinyvec::ArrayVec;

use self::{
buffer::RenderBuffer,
timer::Timer,
};

pub mod buffer;
pub mod dropping;
pub mod timer;
pub mod wind;

pub type DropCell = ArrayVec<[DropSpeed; 3]>;
pub type DropColumn = Rc<RefCell<Vec<DropCell>>>;

pub trait EachFrameImpl {
fn on_frame(&mut self, rb: &mut RenderBuffer, seed: u64, frame: u8);
}

#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub enum DropSpeed {
Fast,
Normal,
Slow,
#[default]
None,
}

#[derive(Copy, Clone, Default, ValueEnum, PartialEq, Eq)]
pub enum Mode {
#[default]
Rain,
Snow,
Meteor,
Star,
}

impl Display for Mode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match *self {
Mode::Rain => "rain",
Mode::Snow => "snow",
Mode::Meteor => "meteor",
Mode::Star => "star",
};

s.fmt(f)
}
}

impl Mode {
pub fn get_frame_by_speed(&self, s: DropSpeed) -> u8 {
use DropSpeed::*;
use Mode::*;

match self {
Rain => match s {
Fast => 1,
Normal => 2,
Slow => 3,
_ => 0,
},
Snow => match s {
Fast => 2,
Normal => 4,
Slow => 6,
_ => 0,
},
_ => 0
}
}
}

pub struct State<T> {
pub rb: RenderBuffer,
pub timer: Timer,
pub weather: T,
frame: u8,
rng: SmallRng,
seed: u64,
}

impl<T: EachFrameImpl> State<T> {
pub fn new(size: Rect, weather: T) -> Self {
State {
rb: RenderBuffer::new(size),
rng: SmallRng::from_entropy(),
frame: 0,
timer: Timer::default(),
seed: 0,
weather,
}
}

pub fn on_resize(&mut self, columns: u16, rows: u16) {
self.rb = RenderBuffer::new(Rect {
x: 0,
y: 0,
height: rows,
width: columns,
});
}

pub fn tick_timer(&mut self) {
self.timer = Timer::new();
}

pub fn tick(&mut self) {
self.frame = if self.frame > 240 { 0 } else { self.frame.saturating_add(1) };
self.seed = self.rng.next_u64();
self.weather.on_frame(&mut self.rb, self.seed, self.frame);
}
}

29 changes: 29 additions & 0 deletions src/state/timer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::time::SystemTime;

use chrono::{DateTime, Local, Timelike};

#[derive(Copy, Clone)]
pub struct Timer {
pub hours: u8,
pub minutes: u8,
pub seconds: u8,
}

impl Timer {
pub fn new() -> Self {
Self::default()
}
}

impl Default for Timer {
fn default() -> Self {
let system_time = SystemTime::now();
let datetime: DateTime<Local> = system_time.into();
Self {
hours: datetime.hour() as u8,
minutes: datetime.minute() as u8,
seconds: datetime.second() as u8,
}
}
}

Loading

0 comments on commit 78211d8

Please sign in to comment.