Search code examples
rustiostdout

Cleared and re-printed output in shell is flashing


I'm trying to learn rust and wrote a small program. The program is supposed to take a matrix of random variables, convert them to chars and print them to stdout over and over again.

The code itself is running fine, but the output keeps flashing -- as if for a millisecond, something isn't printed properly. I recorded a video that shows the flashing:

https://www.youtube.com/watch?v=DaVzKSuXUjg

The code is as follows:

use std::io;
use std::io::Write;
use std::thread::sleep;
use std::time::Duration;

use rand::Rng;

fn main() {
    let mut image: [[f32; 30]; 30] = [[0.0; 30]; 30];

    loop {
        let x = rand::thread_rng().gen_range(0..30);
        let y = rand::thread_rng().gen_range(0..30);
        let value: f32 = rand::thread_rng().gen();
        image[x][y] = value;
        display(&image).expect("Can't display the image!");
        sleep(Duration::new(0, 10_000_000));
    }
}

fn display(image: &[[f32; 30]; 30]) -> io::Result<()> {
    let mut pixel_matrix = String::from("\x1B[2J\x1B[1;1H"); // reset cursor to 1,1
    for x in 0..image.len() {
        for y in 0..image[x].len() {
            let value = image[x][y];
            pixel_matrix.push(
                match value {
                    x if (0.0..0.1).contains(&x) => ' ',
                    x if (0.1..0.2).contains(&x) => '.',
                    x if (0.2..0.3).contains(&x) => ':',
                    x if (0.3..0.4).contains(&x) => '-',
                    x if (0.4..0.5).contains(&x) => '=',
                    x if (0.5..0.6).contains(&x) => '+',
                    x if (0.6..0.7).contains(&x) => '*',
                    x if (0.7..0.8).contains(&x) => '#',
                    x if (0.8..0.9).contains(&x) => '%',
                    x if (0.9..1.0).contains(&x) => '@',
                    _ => ' ',
                }
            );
        }
        pixel_matrix.push('\n');
        let mut stdout = io::stdout().lock();
        stdout.write_all(pixel_matrix.as_bytes()).expect("Can't write to stdout!");

    }
    Ok(())
}

What is causing the flashes? Is the code too fast and re-renders too early? Is something up with the terminal emulator?


Solution

  • This is caused by you having stdout.write_all for every line.

    You basically add line by line the new image and then sleep for 10ms. Sometimes you programm is fast enough that while the new lines come in the terminal is not rendering them, sometimes the terminal is rendering.

    I think what you want is to have your stdout.write_all outisde of the for loop in the line just above Ok(())