Skip to content

Instantly share code, notes, and snippets.

@Momijiichigo
Last active May 13, 2024 10:49
Show Gist options
  • Select an option

  • Save Momijiichigo/1651ad5c725c686bfa252d5dca2ac10c to your computer and use it in GitHub Desktop.

Select an option

Save Momijiichigo/1651ad5c725c686bfa252d5dca2ac10c to your computer and use it in GitHub Desktop.
Matrix Char Rain

Matrix Char Rain

Image

copy from my old repo.

run the script in node.js

Update

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);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment