commit 8ca8f1af420da121c22bfe9201451fe80405df5a Author: Ed Guloien Date: Wed Jun 24 20:39:57 2026 -0400 init; basic quiz functionality diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..8ebad91 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "fast-math" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..aa47190 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "fast-math" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ff21ed5 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,185 @@ +use std::io::{self, BufRead, Write}; +use std::time::{Duration, Instant, SystemTime}; + +struct Rng { + state: u64, +} + +impl Rng { + fn new() -> Self { + let seed = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .subsec_nanos() as u64; + Self { state: seed ^ 0x9e3779b97f4a7c15 } + } + + fn next_u64(&mut self) -> u64 { + self.state = self.state.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407); + self.state + } + + fn range(&mut self, min: i32, max: i32) -> i32 { + let range = (max - min + 1) as u64; + (self.next_u64() % range) as i32 + min + } +} + +#[derive(Clone, Copy)] +enum Op { + Add, + Sub, + Mul, + Div, +} + +impl Op { + fn symbol(self) -> char { + match self { + Op::Add => '+', + Op::Sub => '-', + Op::Mul => 'x', + Op::Div => '/', + } + } + + fn apply(self, a: i32, b: i32) -> i32 { + match self { + Op::Add => a + b, + Op::Sub => a - b, + Op::Mul => a * b, + Op::Div => a / b, + } + } +} + +struct Question { + a: i32, + b: i32, + op: Op, + answer: i32, +} + +impl Question { + fn generate(rng: &mut Rng) -> Self { + let op = match rng.range(0, 3) { + 0 => Op::Add, + 1 => Op::Sub, + 2 => Op::Mul, + _ => Op::Div, + }; + + let (a, b) = match op { + Op::Add => (rng.range(1, 99), rng.range(1, 99)), + Op::Sub => { + let x = rng.range(1, 99); + let y = rng.range(1, x); + (x, y) + } + Op::Mul => (rng.range(2, 12), rng.range(2, 12)), + Op::Div => { + let b = rng.range(2, 12); + let quotient = rng.range(2, 12); + (b * quotient, b) + } + }; + + let answer = op.apply(a, b); + Question { a, b, op, answer } + } + + fn prompt(&self) -> String { + format!("{} {} {} = ", self.a, self.op.symbol(), self.b) + } +} + +struct QuestionStats { + a: i32, + b: i32, + op: Op, + answer: i32, + time_taken: Duration, + mistakes: u32, +} + +fn main() { + const ROUNDS: usize = 10; + + println!("\n=== Fast Math ==="); + println!("Complete {ROUNDS} questions to finish a round.\n"); + + let stdin = io::stdin(); + let mut stdin = stdin.lock(); + let mut rng = Rng::new(); + let mut stats: Vec = Vec::with_capacity(ROUNDS); + + for i in 0..ROUNDS { + let q = Question::generate(&mut rng); + println!("Question {}/{}:", i + 1, ROUNDS); + + let mut mistakes = 0u32; + let start = Instant::now(); + + loop { + print!(" {}", q.prompt()); + io::stdout().flush().unwrap(); + + let mut line = String::new(); + stdin.read_line(&mut line).unwrap(); + + match line.trim().parse::() { + Ok(n) if n == q.answer => { + println!(" Correct!\n"); + break; + } + Ok(_) => { + mistakes += 1; + println!(" Wrong, try again."); + } + Err(_) => { + println!(" Please enter a valid integer."); + } + } + } + + stats.push(QuestionStats { + a: q.a, + b: q.b, + op: q.op, + answer: q.answer, + time_taken: start.elapsed(), + mistakes, + }); + } + + print_summary(&stats); +} + +fn print_summary(stats: &[QuestionStats]) { + let total_time: Duration = stats.iter().map(|s| s.time_taken).sum(); + let total_mistakes: u32 = stats.iter().map(|s| s.mistakes).sum(); + let perfect = stats.iter().filter(|s| s.mistakes == 0).count(); + + println!("=== Round Complete ===\n"); + println!("{:<5} {:<12} {:<8} {:>10} {:>8}", "#", "Question", "Answer", "Time (s)", "Mistakes"); + println!("{}", "-".repeat(50)); + + for (i, s) in stats.iter().enumerate() { + let q = format!("{} {} {}", s.a, s.op.symbol(), s.b); + println!( + "{:<5} {:<12} {:<8} {:>10.2} {:>8}", + i + 1, + q, + s.answer, + s.time_taken.as_secs_f64(), + s.mistakes, + ); + } + + println!("{}", "-".repeat(50)); + println!( + "{:<5} {:<12} {:<8} {:>10.2} {:>8}", + "Tot", "", "", total_time.as_secs_f64(), total_mistakes + ); + println!("\nPerfect (no mistakes): {}/{}", perfect, stats.len()); +}