init; basic quiz functionality

This commit is contained in:
2026-06-24 20:39:57 -04:00
commit 8ca8f1af42
4 changed files with 199 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
/target
Generated
+7
View File
@@ -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"
+6
View File
@@ -0,0 +1,6 @@
[package]
name = "fast-math"
version = "0.1.0"
edition = "2024"
[dependencies]
+185
View File
@@ -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<QuestionStats> = 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::<i32>() {
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());
}