generics
This commit is contained in:
@ -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,76 +101,84 @@ fn main() {
|
||||
*digit = rand_number + 1;
|
||||
}
|
||||
}
|
||||
{
|
||||
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();
|
||||
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..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 i: usize;
|
||||
let mut state: AddSubOrMultiplicateDivide = FromPrimitive::from_u64(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 {
|
||||
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 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 {
|
||||
if not_first {println!();}
|
||||
not_first = true;
|
||||
print_riddle(&digits, false, result, operators);
|
||||
if args.solution_print {
|
||||
print_riddle(&digits, true, result, operators);
|
||||
}
|
||||
}
|
||||
let mut not_first = false;
|
||||
for (result, operators) in results.riddles {
|
||||
if not_first {println!();}
|
||||
not_first = true;
|
||||
let result_u128 = num_traits::cast(result).unwrap();
|
||||
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() {
|
||||
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() {
|
||||
|
||||
Reference in New Issue
Block a user