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 std::collections::HashSet;
use std::collections::HashMap;
use rand::distributions::{Distribution, Uniform};
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use num_traits::NumCast;
use num_integer::Integer;
use std::hash::Hash;
trait BasicInteger = Integer + Hash + Copy;
#[derive(FromPrimitive)]
enum Operator {
@ -35,31 +42,33 @@ struct Args {
solution_print: bool,
}
type RiddleMap = HashMap<i64, u64>;
struct PartOperation {
results: RiddleMap,
struct PartOperation<T> {
results: HashMap<T, Option<u64>>,
last_operator: Option<usize>,
}
struct ResultStore {
riddles: RiddleMap,
results_already_taken: HashSet<i64>,
struct ResultStore<T> {
riddles: HashMap<T, u64>,
results_already_taken: HashSet<T>,
}
impl ResultStore {
impl<T: Eq + Hash> ResultStore<T> {
fn new() -> Self {
Self{
riddles: HashMap::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;}
match self.riddles.remove(&result) {
None => {self.riddles.insert(result, operators);}
Some(_x) => {self.results_already_taken.insert(result);}
if match operators {
None => true,
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,30 +101,33 @@ fn main() {
*digit = rand_number + 1;
}
}
{
calc_results::<i64>(args, digits);
}
fn calc_results<T: BasicInteger + 'static + FromPrimitive + NumCast>(args: Args, digits: Vec<u8>) {
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();
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_u64(dm_as_map & 1).unwrap();
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 u64 {
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 = ResultStore::new();
let mut part_results: HashMap<T, Option<u64>> = HashMap::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);
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.riddles,
results: part_results,
last_operator: last_operator_helper(last_i),
});
}
@ -125,7 +137,7 @@ fn main() {
};
last_i = i;
}
if dm_as_map >> args.count - 1 & 1 == AddSubOrMultiplicateDivide::AddSub as u64 {
if dm_as_map >> args.count - 1 & 1 == AddSubOrMultiplicateDivide::AddSub as u32 {
results_multiplicate.push(insert_digit(&digits, digits.len() - 1));
}
{
@ -140,28 +152,33 @@ fn main() {
for (result, operators) in results.riddles {
if not_first {println!();}
not_first = true;
print_riddle(&digits, false, result, operators);
let result_u128 = num_traits::cast(result).unwrap();
print_riddle(&digits, false, result_u128, operators);
if args.solution_print {
print_riddle(&digits, true, result, operators);
}
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() {
None => results.store(part_result, operators),
None => {
results.insert(part_result, if results.contains_key(&part_result)
{None} else {Some(operators)});
}
Some(next) => {
let next_digit = *next as i64;
let next_digit = FromPrimitive::from_u8(*next).unwrap();
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 {
Operator::Multiplicate => part_result * next_digit,
Operator::Divide => {
if part_result % next_digit != 0 {continue;}
if part_result % next_digit != T::zero() {continue;}
part_result / next_digit
}
_ => 0,
_ => T::zero(),
},
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() {
None => {
if part_result > 0 {results.store(part_result, operators);}
if part_result > T::zero() {results.store(part_result, operators);}
}
Some(next) => {
for (next_result, part_operators) in &next.results {
for operator in [Operator::Add, Operator::Subtract] {
add_sub(iter.clone(), results,
match operator {
Operator::Add => part_result + next_result,
Operator::Subtract => part_result - next_result,
_ => 0,
Operator::Add => part_result + *next_result,
Operator::Subtract => part_result - *next_result,
_ => 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)}
}
fn insert_digit(digits: &Vec<u8>, i: usize) -> PartOperation {
let mut result_map = RiddleMap::new();
result_map.insert(digits[i] as i64, 0);
fn insert_digit<T: Eq + Hash + FromPrimitive>(digits: &Vec<u8>, i: usize) -> PartOperation<T> {
let mut result_map: HashMap<T, Option<u64>> = HashMap::new();
result_map.insert(T::from_u8(digits[i]).unwrap(), Some(0));
return PartOperation{
results: result_map,
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"});
let mut i = 0;
for digit in digits[.. digits.len() - 1].iter() {