use rand::Rng;
pub fn evaluate_expression(expression: &str) -> Result<f64, &'static str> {
let tokens = tokenize(expression)?;
let postfix_tokens = infix_to_postfix(&tokens)?;
let result = evaluate_postfix(&postfix_tokens)?;
Ok(result)
}
fn tokenize(expression: &str) -> Result<Vec<String>, &'static str> {
let mut tokens = Vec::new();
let mut number = String::new();
for c in expression.chars() {
if c.is_whitespace() {
continue;
} else if c.is_digit(10) || c == '.' {
number.push(c);
} else if c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')' {
if !number.is_empty() {
tokens.push(number.clone());
number.clear();
}
tokens.push(c.to_string());
} else {
return Err("Invalid character in expression");
}
}
if !number.is_empty() {
tokens.push(number);
}
Ok(tokens)
}
fn infix_to_postfix(tokens: &[String]) -> Result<Vec<String>, &'static str> {
let mut output = Vec::new();
let mut operators = Vec::new();
for token in tokens {
if let Ok(_) = token.parse::<f64>() {
output.push(token.clone());
} else if token == "(" {
operators.push(token.clone());
} else if token == ")" {
while let Some(op) = operators.pop() {
if op == "(" {
break;
}
output.push(op);
}
} else if token == "+" || token == "-" || token == "*" || token == "/" {
while let Some(op) = operators.last() {
if precedence(op) >= precedence(token) {
output.push(operators.pop().unwrap());
} else {
break;
}
}
operators.push(token.clone());
} else {
return Err("Invalid token in expression");
}
}
while let Some(op) = operators.pop() {
output.push(op);
}
Ok(output)
}
fn precedence(op: &str) -> i32 {
match op {
"+" | "-" => 1,
"*" | "/" => 2,
_ => 0,
}
}
fn evaluate_postfix(tokens: &[String]) -> Result<f64, &'static str> {
let mut stack = Vec::new();
for token in tokens {
if let Ok(num) = token.parse::<f64>() {
stack.push(num);
} else if token == "+" || token == "-" || token == "*" || token == "/" {
let b = stack.pop().ok_or("Invalid expression")?;
let a = stack.pop().ok_or("Invalid expression")?;
let result = match token.as_str() {
"+" => a + b,
"-" => a - b,
"*" => a * b,
"/" => a / b,
_ => return Err("Invalid operator"),
};
stack.push(result);
} else {
return Err("Invalid token in expression");
}
}
stack.pop().ok_or("Invalid expression")
}
pub fn generate_random_expression() -> String {
let mut rng = rand::thread_rng();
let operators = vec!["+", "-", "*", "/"];
let mut expression = String::new();
fn generate_number(rng: &mut rand::rngs::ThreadRng) -> String {
rng.gen_range(1..10).to_string()
}
fn generate_simple_expression(rng: &mut rand::rngs::ThreadRng, operators: &Vec<&str>) -> String {
let num1 = generate_number(rng);
let op = operators[rng.gen_range(0..operators.len())];
let num2 = generate_number(rng);
format!("{} {} {}", num1, op, num2)
}
for _ in 0..3 {
if rng.gen_bool(0.5) {
expression.push('(');
expression.push_str(&generate_simple_expression(&mut rng, &operators));
expression.push(')');
} else {
expression.push_str(&generate_number(&mut rng));
}
let op = operators[rng.gen_range(0..operators.len())];
expression.push_str(" ");
expression.push_str(op);
expression.push_str(" ");
}
if rng.gen_bool(0.5) {
expression.push('(');
expression.push_str(&generate_simple_expression(&mut rng, &operators));
expression.push(')');
} else {
expression.push_str(&generate_number(&mut rng));
}
expression
}