Skip to content

Commit

Permalink
update stats struct and update wpm counting
Browse files Browse the repository at this point in the history
  • Loading branch information
radlinskii committed Sep 26, 2023
1 parent 9f8216d commit 35afc44
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/args.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clap::Parser;

/// cli typing test
/// a very minimalistic cli typing test
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Args {
Expand Down
34 changes: 27 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,42 @@ fn main() -> anyhow::Result<()> {

let args = Args::parse();
let config = Config::new(args, config_file_path).context("Unable to create config")?;
let duration = config.duration.as_secs();
let expected_input = ExpectedInput::new(&config).context("Unable to create expected input")?;

let mut terminal = configure_terminal().context("Unable to configure terminal")?;

let mut app = Runner::new(config, expected_input);
let res = app.run(&mut terminal);

restore_terminal(terminal).context("Unable to restore terminal")?;

if let Err(err) = res {
println!("{:?}", err)
} else if let Ok(stats) = res {
println!("{:?}", stats);
}
match res {
Ok(stats) => {
println!("WPM: {}", stats.wpm);
println!("Raw accuracy: {:.2}%", stats.raw_accuracy);
println!("Raw valid characters: {}", stats.raw_valid_characters_count);
println!("Raw mistakes: {}", stats.raw_mistakes_count);
println!("Raw characters typed: {}", stats.raw_typed_characters_count);
println!("Accuracy after corrections: {:.2}%", stats.accuracy);
println!(
"Valid characters after corrections: {}",
stats.valid_characters_count
);
println!("Mistakes after corrections: {}", stats.mistakes_count);
println!(
"Characters typed after corrections: {}",
stats.typed_characters_count
);
println!("Time: {} seconds", duration);

Ok(())
Ok(())
}
Err(err) => {
println!("Error: {:?}", err);

Err(err)
}
}
}

fn configure_terminal() -> Result<Terminal<CrosstermBackend<io::Stdout>>, anyhow::Error> {
Expand Down
74 changes: 45 additions & 29 deletions src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,21 @@ pub struct Runner {
input_mode: InputMode,
config: Config,
expected_input: Box<dyn ExpectedInputInterface>,
mistakes: u64,
valid_characters: u64,
raw_mistakes_count: u64,
raw_valid_characters_count: u64,
}

#[derive(Debug)]
pub struct Stats {
pub wpm: f64,
pub characters: u64,
pub valid_characters: u64,
pub mistakes: u64,
pub raw_accuracy: f64,
pub raw_valid_characters_count: u64,
pub raw_mistakes_count: u64,
pub raw_typed_characters_count: u64,
pub accuracy: f64,
pub uncorrected_mistakes: u64,
pub uncorrected_accuracy: f64,
pub valid_characters_count: u64,
pub typed_characters_count: u64,
pub mistakes_count: u64,
}

impl Runner {
Expand All @@ -46,8 +48,8 @@ impl Runner {
input_mode: InputMode::Normal,
config,
expected_input: Box::new(expected_input),
mistakes: 0,
valid_characters: 0,
raw_mistakes_count: 0,
raw_valid_characters_count: 0,
}
}

Expand Down Expand Up @@ -90,14 +92,17 @@ impl Runner {
self.input_mode = InputMode::Editing;
}
KeyCode::Char('q') => {
// todo return canceled test error and handle it in main
return Ok(Stats {
wpm: 0.0,
characters: 0,
valid_characters: 0,
mistakes: 0,
raw_accuracy: 0.0,
raw_valid_characters_count: 0,
raw_mistakes_count: 0,
raw_typed_characters_count: 0,
accuracy: 0.0,
uncorrected_mistakes: 0,
uncorrected_accuracy: 0.0,
valid_characters_count: 0,
mistakes_count: 0,
typed_characters_count: 0,
});
}
_ => {}
Expand All @@ -116,9 +121,9 @@ impl Runner {
self.input.chars().last() == expected_input.last().copied();

if !is_correct {
self.mistakes += 1;
self.raw_mistakes_count += 1;
} else {
self.valid_characters += 1;
self.raw_valid_characters_count += 1;
}
}
KeyCode::Backspace => {
Expand Down Expand Up @@ -309,23 +314,34 @@ impl Runner {
}

fn get_stats(&self) -> Stats {
let characters = self.input.chars().count() as u64;
let uncorrected_mistakes = self
.input
.chars()
.zip(self.expected_input.get_string(self.input.len()).chars())
let typed_characters = self.input.chars();
let typed_characters_count = typed_characters.clone().count();
let expected_input_str = self.expected_input.get_string(typed_characters_count);
let expected_characters = expected_input_str.chars();

let mistakes_count = typed_characters
.clone()
.zip(expected_characters.clone())
.filter(|(input_char, expected_input_char)| input_char != expected_input_char)
.count() as u64;
let valid_characters_count = typed_characters_count as u64 - mistakes_count;

Stats {
wpm: characters as f64 / 5.0 * 60.0 / self.config.duration.as_secs() as f64,
characters,
valid_characters: self.valid_characters,
mistakes: self.mistakes,
accuracy: 100.0 - self.mistakes as f64 / self.valid_characters as f64 * 100.0,
uncorrected_mistakes,
uncorrected_accuracy: 100.0
- uncorrected_mistakes as f64 / self.valid_characters as f64 * 100.0,
wpm: valid_characters_count as f64 / 5.0 * 60.0 / self.config.duration.as_secs() as f64,

raw_accuracy: (self.raw_valid_characters_count) as f64
/ (self.raw_valid_characters_count + self.raw_mistakes_count) as f64
* 100.0,
raw_valid_characters_count: self.raw_valid_characters_count,
raw_mistakes_count: self.raw_mistakes_count,
raw_typed_characters_count: self.raw_valid_characters_count + self.raw_mistakes_count,

accuracy: (typed_characters_count - mistakes_count as usize) as f64
/ typed_characters_count as f64
* 100.0,
valid_characters_count,
mistakes_count,
typed_characters_count: typed_characters_count as u64,
}
}
}
Expand Down

0 comments on commit 35afc44

Please sign in to comment.