ratamath 0.1.0

A simple math training TUI game built with Ratatui( not final version)
use anyhow::bail;
use rand::seq::{IndexedMutRandom, IndexedRandom, SliceRandom};
use rand::{RngExt, rng};

#[derive(Debug, Clone)]
pub enum TypeProblem {
    Addition,
    Subtraction,
    Multiplication,
    Division,
}
#[derive(Debug)]
pub struct Domain {
    pub from: f32,
    pub to: f32,
    pub digits_after_num: Option<u32>,
}
impl Default for Domain {
    fn default() -> Self {
        Self {
            from: 0.0,
            to: 100.0,
            digits_after_num: None,
        }
    }
}
#[derive(Debug)]
pub struct GameParams {
    pub amount: u32,
    pub from: f32,
    pub to: f32,
    pub digits_after_num: u32,
    pub type_problems: Vec<TypeProblem>,
}
impl Default for GameParams {
    fn default() -> Self {
        Self {
            amount: 10,
            from: 0.0,
            to: 50.0,
            digits_after_num: 2,
            type_problems: vec![TypeProblem::Multiplication, TypeProblem::Addition],
        }
    }
}

#[derive(Default, Debug)]
pub struct Example {
    pub problem: String,
    pub answer: f32,
}
pub fn generate_problem(types: &Vec<TypeProblem>, domain: &GameParams) -> Example {
    let mut rng = rand::rng();
    let abs = 10u32.pow(domain.digits_after_num) as f32;
    let epsilon = 10.0_f32.powi(-((domain.digits_after_num + 1) as i32));

    let (operator, num1, num2, answer) = loop {
        let type_ = if let Some(t) = types.choose(&mut rng) {
            t.clone()
        } else {
            TypeProblem::Addition
        };

        let n1 = rng.random_range(domain.from as u32..domain.to as u32) as f32;
        let n2 = rng.random_range(domain.from as u32..domain.to as u32) as f32;

        match type_ {
            TypeProblem::Addition => break ('+', n1, n2, n1 + n2),
            TypeProblem::Subtraction => break ('-', n1, n2, n1 - n2),
            TypeProblem::Multiplication => break ('*', n1, n2, n1 * n2),
            TypeProblem::Division => {
                if n2 == 0.0 {
                    continue;
                }

                let ans = n1 / n2;
                let rounded = (ans * abs).round() / abs;

                if (ans - rounded).abs() < epsilon {
                    break ('/', n1, n2, ans);
                }
            }
        }
    };
    Example {
        problem: format!("{} {} {} = ", num1, operator, num2),
        answer,
    }
}