This solution gives similar performance results than the tree based one, mostly because of the intermediate vectors.
82 lines
2.7 KiB
Rust
82 lines
2.7 KiB
Rust
use crate::expr::is_valid_guess_of_tokens;
|
|
use crate::game::Hand;
|
|
use crate::lexer::{lexer_reuse, Token};
|
|
use crate::tile::{Digit, Operator, Tile};
|
|
use itertools::Itertools;
|
|
|
|
fn merge_expression(
|
|
numbers: &[&Digit],
|
|
operators: &[&Operator],
|
|
equals_idx: usize,
|
|
buf: &mut Vec<Tile>,
|
|
) {
|
|
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<Vec<Tile>> {
|
|
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<Tile> = Vec::with_capacity(numbers.len() + operators.len() + 1);
|
|
let mut tokens: Vec<Token> = 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 nb_operators in 0..=(nb_digits - 2) {
|
|
for operators in operators.iter().permutations(nb_operators) {
|
|
merge_expression(&digits, &operators, equals_idx, &mut trial);
|
|
lexer_reuse(&trial, &mut tokens);
|
|
if is_valid_guess_of_tokens(&tokens) {
|
|
combinations.push(trial.clone());
|
|
}
|
|
trial.clear();
|
|
tokens.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);
|
|
}
|
|
}
|