add fancy progress bar :D

This commit is contained in:
tali 2023-04-14 13:25:29 -04:00
parent 04197d4256
commit 517a64156a
1 changed files with 54 additions and 9 deletions

View File

@ -3,7 +3,7 @@ use rand::RngCore as _;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::Path; use std::path::Path;
use std::sync::{atomic, mpsc, Arc}; use std::sync::{atomic, mpsc, Arc};
use std::time::Duration; use std::time::{Duration, Instant};
use fish::bot; use fish::bot;
use tidepool::{cli, config, output, sim}; use tidepool::{cli, config, output, sim};
@ -75,14 +75,21 @@ fn single(args: cli::SingleRun) -> Result<()> {
tracing::debug!("heartbeat"); tracing::debug!("heartbeat");
} }
Msg::Status(_id, status) => { Msg::Status(_id, status) => {
if !args.io.quiet { if exit_early.load(atomic::Ordering::Relaxed) {
let ps = status.pieces; continue;
let ll = status.lines_left;
let pps = ps as f64 / status.time.as_secs_f64();
eprintln!("#{ps}, {ll} lines left, {pps:.2} pps");
} }
write_progress_bar(
&args.io,
status.pieces,
status.lines_left,
config.game.goal,
status.time,
)?;
} }
Msg::Done(_id, output) => { Msg::Done(_id, output) => {
// dropping rx early does two things here: 1) removing any of the 'break's
// in this block become a compile error, 2) interrupts will not be able to
// be sent so the ctrl-c handler will abort the program
std::mem::drop(rx); std::mem::drop(rx);
if output.cleared < config.game.goal { if output.cleared < config.game.goal {
@ -144,6 +151,44 @@ fn write_output(io_args: &cli::IoArgs, path: Option<&Path>, output: &output::Out
} }
} }
fn write_progress_bar(
io_args: &cli::IoArgs,
pieces: usize,
lines_left: usize,
goal: usize,
time: Duration,
) -> std::io::Result<()> {
if io_args.quiet {
return Ok(());
}
let width = 40; // TODO: get terminal size?
let cleared = goal - lines_left;
let pps = pieces as f64 / time.as_secs_f64().max(0.001);
let pace = pieces * 100 / cleared.max(1);
let writer = std::io::stderr().lock();
let mut writer = std::io::BufWriter::new(writer);
write!(writer, "\r[")?;
for i in 0..width {
if goal * i <= cleared * (width - 1) {
write!(writer, "#")
} else {
write!(writer, " ")
}?;
}
write!(
writer,
"] {cleared}/{goal} #{pieces}, {pps:.2} pps, {pace} pace"
)?;
if cleared == goal {
writeln!(writer)
} else {
writer.flush()
}
}
fn prompt_yn(io_args: &cli::IoArgs, msg: &str) -> bool { fn prompt_yn(io_args: &cli::IoArgs, msg: &str) -> bool {
if io_args.noninteractive { if io_args.noninteractive {
return true; return true;
@ -174,7 +219,7 @@ fn run_simulation(
}; };
let mut sim = sim::Simul::new(seed, sim_opts); let mut sim = sim::Simul::new(seed, sim_opts);
let time_start = std::time::Instant::now(); let time_start = Instant::now();
while sim.lines_left() > 0 { while sim.lines_left() > 0 {
if exit_early.load(atomic::Ordering::Relaxed) { if exit_early.load(atomic::Ordering::Relaxed) {
@ -213,14 +258,14 @@ fn run_simulation(
let status = Status { let status = Status {
lines_left: sim.lines_left(), lines_left: sim.lines_left(),
pieces: sim.pieces(), pieces: sim.pieces(),
time: std::time::Instant::now() - time_start, time: Instant::now() - time_start,
}; };
if tx.send(Msg::Status(id, status.into())).is_err() { if tx.send(Msg::Status(id, status.into())).is_err() {
break; break;
} }
} }
let time_end = std::time::Instant::now(); let time_end = Instant::now();
let profile = data_args.profile.then(|| output::Profile { let profile = data_args.profile.then(|| output::Profile {
time: time_end - time_start, time: time_end - time_start,