post-push-party 0.1.7

Push code, earn points, throw a party!
Documentation
use std::io::{Write, stdout};

use crossterm::{
    cursor::{Hide, MoveTo, Show},
    event::{self, Event},
    execute,
    terminal::{Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen},
};

use super::{renderer::Renderer, sim::Sim};

pub fn run(colors: &[String]) -> anyhow::Result<()> {
    // HACK could probably smooth this out
    let colors = colors.iter().map(|s| s.as_str()).collect::<Vec<_>>();

    // start terminal
    let mut stdout = stdout();
    execute!(stdout, Hide, EnterAlternateScreen)?;
    crossterm::terminal::enable_raw_mode()?;
    execute!(stdout, Clear(ClearType::All))?;

    let (cols, rows) = crossterm::terminal::size().unwrap();

    let mut renderer = Renderer::new(rows as usize, cols as usize, &colors);
    let mut sim = Sim::new(cols as f64, rows as f64 * 2.);
    let mut time = std::time::Instant::now();

    loop {
        // bail on any key press
        if event::poll(std::time::Duration::from_millis(10))? {
            let event = event::read()?;
            if matches!(event, Event::Key(_)) {
                break;
            }
        }

        // update sim
        let dt = time.elapsed();
        time = std::time::Instant::now();
        sim.update(dt.as_secs_f64());

        // render
        let output = renderer.render(&sim);

        if let Some(output) = output {
            execute!(stdout, MoveTo(0, 0)).unwrap();
            stdout.write_all(output.as_bytes()).unwrap();
        } else {
            // nothing left on screen, so we're done
            break;
        }
    }

    // restore terminal
    execute!(stdout, Show, LeaveAlternateScreen)?;
    crossterm::terminal::disable_raw_mode()?;

    Ok(())
}