generics
This commit is contained in:
@ -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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user