use crate::expr::are_valid_expressions; use crate::game::Hand; use crate::lexer::lexer; use crate::parser::parse; use crate::tile::{Digit, Operator, Tile}; use itertools::Itertools; fn merge_expression( numbers: &[&Digit], operators: &[&Operator], equals_idx: usize, buf: &mut Vec, ) { let mut op_it = operators.iter(); for (i, &number) in numbers.iter().enumerate() { buf.push(Tile::Digit(*number)); if i == equals_idx { buf.push(Tile::Equals); } else if let Some(&&operator) = op_it.next() { buf.push(Tile::Operator(operator)); } } } pub fn generate_valid_combinations(hand: &Hand) -> Vec> { let mut combinations = Vec::new(); // Separate numbers and operators let mut numbers = Vec::new(); let mut operators = Vec::new(); for &tile in &hand.tiles { match tile { Tile::Digit(digit) => numbers.push(digit), Tile::Operator(operator) => operators.push(operator), _ => (), } } let mut trial: Vec = Vec::with_capacity(numbers.len() + operators.len() + 1); // Generate all possible permutations, with an increasing number of tiles for nb_digits in 2..=numbers.len() { for digits in numbers.iter().permutations(nb_digits) { // Then try to place the equals sign at each possible position // Since equality is commutative, we only need to try half of the positions for equals_idx in 0..(nb_digits / 2) { for operators in operators.iter().permutations(nb_digits - 2) { merge_expression(&digits, &operators, equals_idx, &mut trial); if let Ok(tokens) = lexer(&trial) { if let Ok(expressions) = parse(&tokens) { if are_valid_expressions(&expressions) { combinations.push(trial.clone()); } } } trial.clear(); } } } } combinations } #[cfg(test)] mod tests { use super::*; use crate::tile::{Digit, Operator}; #[test] fn generate_combinations() { let hand = Hand::new(vec![ Tile::Digit(Digit::new(1)), Tile::Digit(Digit::new(3)), Tile::Digit(Digit::new(4)), Tile::Operator(Operator::Add), Tile::Operator(Operator::Subtract), ]); let combinations = generate_valid_combinations(&hand); assert_eq!(combinations.len(), 4); } }