I tried to convert Andy Sloane's donut.c to Rust programming language. Suggestions are welcome.
//
// donut -- rotating donut
//
// note: ported a C version by CJKim - July 9, 2024
//
// the original C version's author is Andy Sloane
//
use std::{env, thread, time::Duration};
use getopts::Options;
fn donut(delay: u64) {
const GRIDSIZE: usize = 1760;
const TEXTURE: [char; 12] = ['.',',','-','~', ':', ';', '=', '!', '*', '#', '$', '@'];
let mut rot_a: f32 = 0.0;
let mut rot_b: f32 = 0.0;
let mut iter: usize = 0;
loop {
iter += 1;
let mut z: [f32; GRIDSIZE] = [0.0; GRIDSIZE];
let mut b: [char; GRIDSIZE] = [' '; GRIDSIZE];
let mut grid = b.clone();
let mut j: f32 = 0.0;
while j < 6.28 {
let mut i: f32 = 0.0;
while i < 6.28 {
let c: f32 = i.sin();
let d: f32 = j.cos();
let e: f32 = rot_a.sin();
let f: f32 = j.sin();
let g: f32 = rot_a.cos();
let h: f32 = d + 2.0;
let deg: f32 = 1.0 / (c * h * e + f * g + 5.0);
let l: f32 = i.cos();
let m: f32 = rot_b.cos();
let n: f32 = rot_b.sin();
let t: f32 = c * h * g - f * e;
let x = (40.0 + 30.0 * deg * (l * h * m - t * n)) as i32;
let y = (12.0 + 15.0 * deg * (l * h * n + t * m)) as i32;
let o = (x + 80 * y) as usize;
let idx: usize = (8.0 * ((f * e - c * d * g) * m
- c * d * e - f * g - l * d * n)) as usize;
if 22 > y && y > 0 && x > 0 && 80 > x && deg > z[o as usize] {
z[o] = deg;
let pidx: usize = if idx > 0 { idx } else { 0 };
b[o] = TEXTURE[pidx];
}
i += 0.02;
}
j += 0.07;
}
for k in 0..GRIDSIZE {
// putchar(k % 80 ? b[k] : 10);
let chr = if k % 80 == 0 { '\n' } else { b[k as usize] };
grid[k as usize] = chr;
rot_a += 0.00004;
rot_b += 0.00002;
}
let ostr = String::from_iter(grid); // convert chars to a string
println!("\x1b[H{}\n{}", ostr, iter);
// BUG: when rot_a reaches 1024 and rot_b 512, the donut no longer spins
if rot_a > 1000.0 || rot_b > 500.0 {
rot_a = 0.0;
rot_b = 0.0;
}
thread::sleep(Duration::from_millis(delay));
}
}
fn print_usage(prgnam: &str, opts: Options) {
let usage = format!("usage: {} [options]", prgnam);
println!("{}", opts.usage(&usage));
}
fn main() {
let args: Vec<String> = env::args().collect();
let prognam = args[0].clone();
let mut opts = Options::new();
opts.optopt("d", "delay", "number of milliseconds between iterations (default=30)", "milsecs");
opts.optflag("h", "help", "print this help message and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => { m }
Err(e) => {
println!("{}", e.to_string());
print_usage(&prognam, opts);
return;
}
};
if matches.opt_present("h") {
print_usage(&prognam, opts);
return;
}
let delay: u64 = match matches.opt_str("d") {
Some(m) => {
match m.parse() {
Ok(x) => { x }
Err(e) => {
println!("{} - {}", "bad milliseconds specified", e);
print_usage(&prognam, opts);
return;
}
}
}
_ => { 30 as u64 }
};
print!("\x1b[2J\x1b[HHello, donut lovers! [Hit ^C to stop it.]");
donut(delay);
}
No comments:
Post a Comment