141 lines
4.7 KiB
Rust
141 lines
4.7 KiB
Rust
use crossterm::{style::Stylize, terminal::size};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use super::units::Module;
|
|
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
|
pub(crate) struct Tracker {
|
|
pub(crate) unit: Module,
|
|
questions_answered: u64,
|
|
questions_correct: u64,
|
|
probability_known: f64,
|
|
results: Vec<bool>, // Vector to store correct/incorrect results
|
|
milestones: usize,
|
|
milestones_completed: usize,
|
|
}
|
|
|
|
impl Tracker {
|
|
pub(crate) fn new(unit: Module) -> Self {
|
|
Self {
|
|
unit,
|
|
questions_answered: 0,
|
|
questions_correct: 0,
|
|
probability_known: 0.3, // Start with a 30% chance of knowing the answer
|
|
results: Vec::new(),
|
|
milestones: 0,
|
|
milestones_completed: 0,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn quiz_result(&mut self, correct: bool) -> f64 {
|
|
self.questions_answered += 1;
|
|
self.results.push(correct);
|
|
if correct {
|
|
self.milestones_completed = (self.milestones_completed + 1).min(self.milestones);
|
|
self.questions_correct += 1;
|
|
}
|
|
|
|
// Calculate streak of correct answers
|
|
let mut streak = 0;
|
|
for &result in self.results.iter().rev() {
|
|
if result {
|
|
streak += 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
let prior = self.probability_known;
|
|
let slip = if self.questions_answered < 10 {
|
|
0.05 // Lower slip rate for beginners
|
|
} else if self.probability_known > 0.8 {
|
|
0.15 // Higher slip rate for advanced students
|
|
} else {
|
|
0.1 // Default slip rate
|
|
};
|
|
let guess = if self.questions_answered < 10 {
|
|
0.2 // Lower guess rate for beginners
|
|
} else if self.probability_known > 0.8 {
|
|
0.3 // Higher guess rate for advanced students
|
|
} else {
|
|
0.25 // Default guess rate (average of 4 options)
|
|
};
|
|
let likelihood = if correct {
|
|
1.0 - slip
|
|
} else {
|
|
guess
|
|
};
|
|
|
|
// Adjust posterior based on streak
|
|
let streak_multiplier = 1.0 + (streak as f64 * 0.1); // Increase probability for streaks
|
|
let posterior = if prior == 0.0 {
|
|
likelihood * streak_multiplier // Start with likelihood if prior is zero
|
|
} else {
|
|
((likelihood * prior) / ((likelihood * prior) + ((1.0 - likelihood) * (1.0 - prior)))) * streak_multiplier
|
|
};
|
|
|
|
self.probability_known = posterior.min(1.0).max(0.0);
|
|
|
|
self.probability_known
|
|
}
|
|
|
|
pub(crate) fn get_probability(&self) -> f64 {
|
|
// self.probability_known
|
|
if self.milestones == 0 {
|
|
return 0.0;
|
|
}
|
|
if self.milestones_completed == 0 {
|
|
return 0.0;
|
|
}
|
|
self.milestones_completed as f64 / self.milestones as f64
|
|
}
|
|
|
|
// pub fn get_milestones(&self) -> usize {
|
|
// self.milestones
|
|
// }
|
|
// pub fn get_milestones_completed(&self) -> usize {
|
|
// self.milestones_completed
|
|
// }
|
|
|
|
pub(crate) fn print_progress(&self) {
|
|
let (cols, _) = size().unwrap();
|
|
// let percent = self.probability_known * 100.0; // Assuming `probability_known` is a method in `LessonTracker`
|
|
let percent = if self.milestones_completed > 0 {
|
|
(self.milestones_completed as f64) / (self.milestones as f64) * 100.0 // Assuming `probability_known` is a method in `LessonTracker`
|
|
} else {0.0};
|
|
let percent_name = format!("{:>4.0}%", percent).dark_blue();
|
|
let unit_name = format!("{} {} ", percent_name, self.unit);
|
|
let dots = ".".repeat((cols as usize).saturating_sub(unit_name.len() + 11));
|
|
match percent {
|
|
percent if percent > 0.0 => {
|
|
let progress = percent as usize;
|
|
let filled_percent = progress / 5; // Each '=' represents 5%
|
|
let bars = format!(
|
|
"|{}{}|",
|
|
"█".repeat(filled_percent),
|
|
" ".repeat(20_usize.saturating_sub(filled_percent)),
|
|
);
|
|
println!(
|
|
"{} {} {}",
|
|
unit_name,
|
|
dots,
|
|
bars,
|
|
);
|
|
}
|
|
_ => {
|
|
println!(
|
|
"{} {} |{}|",
|
|
unit_name,
|
|
dots,
|
|
" ".repeat(20),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
pub fn set_milestones(&mut self, milestones: usize) {
|
|
self.milestones = milestones;
|
|
}
|
|
pub fn set_completed_milestones(&mut self, completed_milestones: usize) {
|
|
self.milestones_completed = completed_milestones;
|
|
}
|
|
} |