copy from my old repo.
run the script in node.js
added Rust version. In order to run it, add
[features]
default = ["simd"]
simd = []
in Cargo.toml
copy from my old repo.
run the script in node.js
added Rust version. In order to run it, add
[features]
default = ["simd"]
simd = []
in Cargo.toml
| #![feature(portable_simd)] | |
| use rand::{rngs::ThreadRng, Rng}; | |
| use std::{ | |
| cmp::min, | |
| io::{self, stdout, Stdout, Write}, | |
| thread::sleep, | |
| time::Duration | |
| }; | |
| #[cfg(feature = "simd")] | |
| use std::simd::i16x4; | |
| use termion::{color, cursor}; | |
| // number of characters in each char-rains | |
| const LENGTH: u8 = 40; | |
| const LENGTH_U16: u16 = LENGTH as u16; | |
| struct ColorInfo { | |
| #[cfg(not(feature = "simd"))] | |
| start: color::Rgb, | |
| #[cfg(not(feature = "simd"))] | |
| color_step: (i8, i8, i8) | |
| #[cfg(feature = "simd")] | |
| start: i16x4, | |
| #[cfg(feature = "simd")] | |
| color_step: i16x4, | |
| } | |
| impl ColorInfo { | |
| #[cfg(feature = "simd")] | |
| fn new(start: i16x4, end: i16x4) -> Self { | |
| Self { | |
| start, | |
| color_step: (end - start) / i16x4::splat(LENGTH as i16) | |
| } | |
| } | |
| #[cfg(not(feature = "simd"))] | |
| fn new(start: color::Rgb, end: color::Rgb) -> Self { | |
| todo!(); | |
| } | |
| } | |
| struct ScreenInfo<'a> { | |
| color_info: ColorInfo, | |
| term_size: &'a mut (u16, u16), | |
| } | |
| struct CharRain { | |
| x: u16, | |
| /// position of bottom character | |
| y: u16, | |
| } | |
| enum LineState { | |
| Falling, | |
| ReachedEnd, | |
| } | |
| fn from_i16x4_to_rgb(input: i16x4) -> color::Rgb { | |
| color::Rgb( | |
| input[0] as u8, | |
| input[1] as u8, | |
| input[2] as u8 | |
| ) | |
| } | |
| impl CharRain { | |
| fn new(x: u16, y: u16) -> Self { | |
| CharRain { x, y } | |
| } | |
| fn new_random(rng: &mut ThreadRng, term_width: u16) -> Self { | |
| CharRain { x: rng.gen_range(1..term_width), y: 1 } | |
| } | |
| fn redrop_random(&mut self, rng: &mut ThreadRng, term_width: u16) { | |
| self.x = rng.gen_range(1..term_width); | |
| self.y = 1; | |
| } | |
| fn draw( | |
| &mut self, | |
| stdout: &mut Stdout, | |
| rng: &mut ThreadRng, | |
| screen_info: &ScreenInfo | |
| ) -> io::Result<LineState> { | |
| let &mut Self { x, y } = self; | |
| write!(stdout, "{}", cursor::Goto(x, y))?; | |
| let shown_length = min(y, LENGTH_U16); | |
| let ScreenInfo { color_info, term_size: &mut (.., height) } = screen_info; | |
| let (shown_length, mut current_color) = if y >= height { | |
| if y - LENGTH_U16 >= height { | |
| return Ok(LineState::ReachedEnd); | |
| } | |
| let gap = y - height; | |
| let color_start = color_info.start + color_info.color_step * i16x4::splat(gap as i16); | |
| write!(stdout, "{}", color::Fg(from_i16x4_to_rgb(color_start)))?; | |
| ( | |
| shown_length - gap, | |
| color_start | |
| ) | |
| } else { | |
| write!(stdout, "{}", color::Fg(color::White))?; | |
| (shown_length, color_info.start) | |
| }; | |
| for _ in 1..shown_length { | |
| let color = from_i16x4_to_rgb(current_color); | |
| write!( | |
| stdout, | |
| "{}{}{}{}", | |
| rng.gen_range::<u8, _>(33..126) as char, | |
| color::Fg(color), | |
| cursor::Up(1), | |
| cursor::Left(1) | |
| )?; | |
| current_color += color_info.color_step; | |
| } | |
| write!(stdout, " ")?; | |
| self.y += 1; | |
| Ok(LineState::Falling) | |
| } | |
| } | |
| fn main() -> io::Result<()> { | |
| let color_info: ColorInfo = ColorInfo::new(i16x4::from([4, 255, 0, 0]), i16x4::from([27, 64, 27, 0])); | |
| let mut rng = rand::thread_rng(); | |
| let mut stdout = stdout(); | |
| let mut term_size = termion::terminal_size()?; | |
| let screen_info = ScreenInfo { color_info, term_size: &mut term_size }; | |
| let mut char_rains = Vec::<CharRain>::new(); | |
| let mut done_appending = false; | |
| loop { | |
| *screen_info.term_size = termion::terminal_size()?; | |
| if !done_appending { | |
| char_rains.push(CharRain::new_random(&mut rng, screen_info.term_size.0)); | |
| } | |
| for rain in &mut char_rains { | |
| if let LineState::ReachedEnd = rain.draw(&mut stdout, &mut rng, &screen_info)? { | |
| if !done_appending { | |
| done_appending = true; | |
| } | |
| rain.redrop_random(&mut rng, screen_info.term_size.0); | |
| } | |
| } | |
| sleep(Duration::from_millis(15)); | |
| if false { | |
| break; | |
| } | |
| } | |
| Ok(()) | |
| } |
| const xint = process.stdout.columns,yint = process.stdout.rows; | |
| //first rgb and final rgb | |
| const colorInfo={ | |
| r1:27, | |
| g1:64, | |
| b1:27, | |
| r2:4, | |
| g2:255, | |
| b2:0 | |
| } | |
| const length = 30; | |
| //color change steps | |
| const rr=((colorInfo.r2-colorInfo.r1)/length)^0,gr=((colorInfo.g2-colorInfo.g1)/length)^0,br=((colorInfo.b2-colorInfo.b1)/length)^0; | |
| class CodeRain{ | |
| constructor(){ | |
| this.x = this.getRandomInt(xint); | |
| this.y=-length; | |
| } | |
| draw(){ | |
| if(this.y>0)process.stdout.cursorTo(this.x,this.y); | |
| else process.stdout.cursorTo(this.x,0); | |
| process.stdout.write(' '); | |
| for(let c=0;c<length;c++){ | |
| if(this.y+c<=0)continue; | |
| process.stdout.write('\x1b[B\x1b[D'); | |
| if(this.y+c>yint)break; | |
| else if(c==length-1)process.stdout.write('\x1b[97m'); | |
| else process.stdout.write(`\x1b[38;2;${colorInfo.r1+c*rr};${colorInfo.g1+c*gr};${colorInfo.b1+c*br}m`); | |
| process.stdout.write(String.fromCharCode(this.getRandomInt(93)+33)); | |
| } | |
| this.y++; | |
| } | |
| getRandomInt(max) { | |
| return Math.floor(Math.random() * Math.floor(max)); | |
| } | |
| } | |
| let rain = []; | |
| let mainLoop = setInterval(()=>{ | |
| rain.push(new CodeRain()); | |
| rain.forEach((value,index)=>{ | |
| value.draw(); | |
| if(value.y>yint+1)delete rain[index]; | |
| }) | |
| },15); |