This commit is contained in:
2022-02-08 20:45:19 +01:00
parent 1a78cec632
commit 745d04169c

View File

@ -1,9 +1,16 @@
#![feature(trait_alias)]
use clap::Parser; use clap::Parser;
use std::collections::HashSet; use std::collections::HashSet;
use std::collections::HashMap; use std::collections::HashMap;
use rand::distributions::{Distribution, Uniform}; use rand::distributions::{Distribution, Uniform};
use num_derive::FromPrimitive; use num_derive::FromPrimitive;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use num_traits::NumCast;
use num_integer::Integer;
use std::hash::Hash;
trait BasicInteger = Integer + Hash + Copy;
#[derive(FromPrimitive)] #[derive(FromPrimitive)]
enum Operator { enum Operator {
@ -35,31 +42,33 @@ struct Args {
solution_print: bool, solution_print: bool,
} }
type RiddleMap = HashMap<i64, u64>; struct PartOperation<T> {
results: HashMap<T, Option<u64>>,
struct PartOperation {
results: RiddleMap,
last_operator: Option<usize>, last_operator: Option<usize>,
} }
struct ResultStore { struct ResultStore<T> {
riddles: RiddleMap, riddles: HashMap<T, u64>,
results_already_taken: HashSet<i64>, results_already_taken: HashSet<T>,
} }
impl ResultStore { impl<T: Eq + Hash> ResultStore<T> {
fn new() -> Self { fn new() -> Self {
Self{ Self{
riddles: HashMap::new(), riddles: HashMap::new(),
results_already_taken: HashSet::new(), results_already_taken: HashSet::new(),
} }
} }
fn store(&mut self, result: i64, operators: u64) { fn store(&mut self, result: T, operators: Option<u64>) {
if self.results_already_taken.contains(&result) {return;} if self.results_already_taken.contains(&result) {return;}
match self.riddles.remove(&result) { if match operators {
None => {self.riddles.insert(result, operators);} None => true,
Some(_x) => {self.results_already_taken.insert(result);} Some(_x) => {self.riddles.contains_key(&result)}
} {
self.riddles.remove(&result);
self.results_already_taken.insert(result);
} }
else {self.riddles.insert(result, operators.unwrap());}
} }
} }
@ -92,76 +101,84 @@ fn main() {
*digit = rand_number + 1; *digit = rand_number + 1;
} }
} }
{ calc_results::<i64>(args, digits);
let mut results = ResultStore::new(); }
for dm_as_map in 0..2u64.pow(args.count as u32) {
let mut results_multiplicate: Vec<PartOperation> = Vec::new(); fn calc_results<T: BasicInteger + 'static + FromPrimitive + NumCast>(args: Args, digits: Vec<u8>) {
let mut results = ResultStore::new();
for dm_as_map in 0..2u32.pow(args.count as u32) {
let mut results_multiplicate: Vec<PartOperation<T>> = Vec::new();
{
let mut last_i: usize = 0;
let mut i: usize;
let mut state: AddSubOrMultiplicateDivide = FromPrimitive::from_u32(dm_as_map & 1).unwrap();
while last_i < args.count as usize {
i = last_i;
while i < args.count as usize && dm_as_map >> i & 1 == state as u32 {
if state == AddSubOrMultiplicateDivide::AddSub {
results_multiplicate.push(insert_digit(&digits, i));
}
i += 1;
}
if state == AddSubOrMultiplicateDivide::MultiplicateDivide {
let mut part_results: HashMap<T, Option<u64>> = HashMap::new();
i += 1;
let mut digits_calc = digits[last_i .. i].iter();
let first_digit = FromPrimitive::from_u8(*digits_calc.next().unwrap()).unwrap();
multiplicate_divide(digits_calc, &mut part_results, last_i as u8 * 2, first_digit, 0);
results_multiplicate.push(PartOperation{
results: part_results,
last_operator: last_operator_helper(last_i),
});
}
state = match state {
AddSubOrMultiplicateDivide::MultiplicateDivide => AddSubOrMultiplicateDivide::AddSub,
AddSubOrMultiplicateDivide::AddSub => AddSubOrMultiplicateDivide::MultiplicateDivide,
};
last_i = i;
}
if dm_as_map >> args.count - 1 & 1 == AddSubOrMultiplicateDivide::AddSub as u32 {
results_multiplicate.push(insert_digit(&digits, digits.len() - 1));
}
{ {
let mut last_i: usize = 0; let mut iter = results_multiplicate.iter();
let mut i: usize; for (part_result, operators) in &iter.next().unwrap().results {
let mut state: AddSubOrMultiplicateDivide = FromPrimitive::from_u64(dm_as_map & 1).unwrap(); add_sub(iter.clone(), &mut results, *part_result, *operators);
while last_i < args.count as usize {
i = last_i;
while i < args.count as usize && dm_as_map >> i & 1 == state as u64 {
if state == AddSubOrMultiplicateDivide::AddSub {
results_multiplicate.push(insert_digit(&digits, i));
}
i += 1;
}
if state == AddSubOrMultiplicateDivide::MultiplicateDivide {
let mut part_results = ResultStore::new();
i += 1;
let mut digits_calc = digits[last_i .. i].iter();
let first_digit = *digits_calc.next().unwrap() as i64;
calc_part(digits_calc, &mut part_results, last_i as u8 * 2, first_digit, 0);
results_multiplicate.push(PartOperation{
results: part_results.riddles,
last_operator: last_operator_helper(last_i),
});
}
state = match state {
AddSubOrMultiplicateDivide::MultiplicateDivide => AddSubOrMultiplicateDivide::AddSub,
AddSubOrMultiplicateDivide::AddSub => AddSubOrMultiplicateDivide::MultiplicateDivide,
};
last_i = i;
}
if dm_as_map >> args.count - 1 & 1 == AddSubOrMultiplicateDivide::AddSub as u64 {
results_multiplicate.push(insert_digit(&digits, digits.len() - 1));
}
{
let mut iter = results_multiplicate.iter();
for (part_result, operators) in &iter.next().unwrap().results {
add_sub(iter.clone(), &mut results, *part_result, *operators);
}
} }
} }
} }
let mut not_first = false; }
for (result, operators) in results.riddles { let mut not_first = false;
if not_first {println!();} for (result, operators) in results.riddles {
not_first = true; if not_first {println!();}
print_riddle(&digits, false, result, operators); not_first = true;
if args.solution_print { let result_u128 = num_traits::cast(result).unwrap();
print_riddle(&digits, true, result, operators); print_riddle(&digits, false, result_u128, operators);
} if args.solution_print {
print_riddle(&digits, true, result_u128, operators);
} }
} }
} }
fn calc_part<'a>(mut iter: impl Clone + Iterator<Item = &'a u8>, results: &mut ResultStore, operator_index: u8, part_result: i64, operators: u64) { fn multiplicate_divide<'a, T: BasicInteger + FromPrimitive>
(mut iter: impl Clone + Iterator<Item = &'a u8>, results: &mut HashMap<T, Option<u64>>,
operator_index: u8, part_result: T, operators: u64) {
match iter.next() { match iter.next() {
None => results.store(part_result, operators), None => {
results.insert(part_result, if results.contains_key(&part_result)
{None} else {Some(operators)});
}
Some(next) => { Some(next) => {
let next_digit = *next as i64; let next_digit = FromPrimitive::from_u8(*next).unwrap();
for operator in [Operator::Multiplicate, Operator::Divide] { for operator in [Operator::Multiplicate, Operator::Divide] {
calc_part(iter.clone(), results, operator_index + 2, multiplicate_divide(iter.clone(), results, operator_index + 2,
match operator { match operator {
Operator::Multiplicate => part_result * next_digit, Operator::Multiplicate => part_result * next_digit,
Operator::Divide => { Operator::Divide => {
if part_result % next_digit != 0 {continue;} if part_result % next_digit != T::zero() {continue;}
part_result / next_digit part_result / next_digit
} }
_ => 0, _ => T::zero(),
}, },
operators | (operator as u64) << operator_index); operators | (operator as u64) << operator_index);
} }
@ -169,21 +186,27 @@ fn calc_part<'a>(mut iter: impl Clone + Iterator<Item = &'a u8>, results: &mut R
} }
} }
fn add_sub<'a>(mut iter: impl Clone + Iterator<Item = &'a PartOperation>, results: &mut ResultStore, part_result: i64, operators: u64) { fn add_sub<'a, T: BasicInteger + 'static>
(mut iter: impl Clone + Iterator<Item = &'a PartOperation<T>>,
results: &mut ResultStore<T>, part_result: T, operators: Option<u64>) {
match iter.next() { match iter.next() {
None => { None => {
if part_result > 0 {results.store(part_result, operators);} if part_result > T::zero() {results.store(part_result, operators);}
} }
Some(next) => { Some(next) => {
for (next_result, part_operators) in &next.results { for (next_result, part_operators) in &next.results {
for operator in [Operator::Add, Operator::Subtract] { for operator in [Operator::Add, Operator::Subtract] {
add_sub(iter.clone(), results, add_sub(iter.clone(), results,
match operator { match operator {
Operator::Add => part_result + next_result, Operator::Add => part_result + *next_result,
Operator::Subtract => part_result - next_result, Operator::Subtract => part_result - *next_result,
_ => 0, _ => T::zero(),
}, },
operators | part_operators | (operator as u64) << 2 * next.last_operator.unwrap() if operators == None || *part_operators == None {None}
else {
Some(operators.unwrap() | part_operators.unwrap() |
(operator as u64) << 2 * next.last_operator.unwrap())
}
); );
} }
} }
@ -195,16 +218,16 @@ fn last_operator_helper(index: usize) -> Option<usize> {
if index == 0 {None} else {Some(index as usize - 1)} if index == 0 {None} else {Some(index as usize - 1)}
} }
fn insert_digit(digits: &Vec<u8>, i: usize) -> PartOperation { fn insert_digit<T: Eq + Hash + FromPrimitive>(digits: &Vec<u8>, i: usize) -> PartOperation<T> {
let mut result_map = RiddleMap::new(); let mut result_map: HashMap<T, Option<u64>> = HashMap::new();
result_map.insert(digits[i] as i64, 0); result_map.insert(T::from_u8(digits[i]).unwrap(), Some(0));
return PartOperation{ return PartOperation{
results: result_map, results: result_map,
last_operator: last_operator_helper(i), last_operator: last_operator_helper(i),
}; };
} }
fn print_riddle(digits: &Vec<u8>, show_solution: bool, result: i64, operators: u64) { fn print_riddle(digits: &Vec<u8>, show_solution: bool, result: u128, operators: u64) {
print!("{}: ", if show_solution {"Lösung"} else {"Rätsel"}); print!("{}: ", if show_solution {"Lösung"} else {"Rätsel"});
let mut i = 0; let mut i = 0;
for digit in digits[.. digits.len() - 1].iter() { for digit in digits[.. digits.len() - 1].iter() {