Draft generation of valid AI movements

This commit is contained in:
2023-02-26 14:05:17 +01:00
parent 1c37b72b55
commit 1472e9f6d8
7 changed files with 113 additions and 4 deletions

81
board-shared/src/ai.rs Normal file
View File

@@ -0,0 +1,81 @@
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<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);
// 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);
}
}