a3 refactoring

This commit is contained in:
2022-03-05 21:46:07 +01:00
parent 738fef4068
commit 841c6631fb
4 changed files with 87 additions and 66 deletions

View File

@ -7,3 +7,8 @@ edition = "2021"
[dependencies]
clap = { version = "3.1.0", features = ["derive"] }
[dependencies.derive_more]
version = "0.99.17"
default-features = false
features = ["add", "add_assign"]

View File

@ -3,8 +3,7 @@ use std::fs;
#[derive(Clone, Copy)]
struct Move {
digit: u8,
put: u16,
taken: u16,
swaps: PutTaken,
}
pub struct DigitHistory {
@ -12,11 +11,22 @@ pub struct DigitHistory {
move_option: Option<Move>,
}
pub struct PutTaken {
pub struct ChangedSticks {
pub digit_i: usize,
pub stick_map: u8,
}
#[derive(Clone, Copy, derive_more::SubAssign, derive_more::AddAssign, derive_more::Add)]
struct PutTaken {
put: u16,
taken: u16,
}
struct ChangeDigitsControl {
change_digit: bool,
break_free: bool,
}
pub const HEX: [u8; 16] = [
0b1110111, // 0
0b0010010, // 1
@ -53,70 +63,27 @@ pub fn largest_hex(filepath: &str) -> (Vec<DigitHistory>, u16) {
max_swaps = lines.next().unwrap().parse().unwrap();
}
{
let mut total_put: u16 = 0;
let mut total_taken: u16 = 0;
while total_taken != total_put || total_put != max_swaps {
for DigitHistory {original_digit, move_option} in digits.iter_mut() {
if move_option.is_some() {continue;}
let digit_hex = HEX[*original_digit as usize];
for (j, to_digit) in HEX.iter().enumerate().rev() {
if j <= *original_digit as usize {break;}
let put: u16 = amount_put(digit_hex, *to_digit);
let taken: u16 = amount_put(*to_digit, digit_hex);
if total_put + put <= max_swaps && total_taken + taken <= max_swaps {
total_put += put;
total_taken += taken;
*move_option = Some(Move {
digit: j as u8,
put,
taken,
let mut total_swaps = PutTaken{ put: 0, taken: 0};
for i in 0..digits.len() {
if total_swaps.taken == total_swaps.put && total_swaps.put == max_swaps {break;}
total_swaps = change_digits(digits.iter_mut(), total_swaps, max_swaps, (), true, |_, _, _| {
ChangeDigitsControl {change_digit: true, break_free: true}
});
break;
}
}
}
for DigitHistory {original_digit, move_option} in digits.iter_mut().rev() {
if total_put == total_taken {break;}
let mut put_with_undo = total_put;
let mut taken_with_undo = total_taken;
if let Some(moved) = move_option {
put_with_undo -= moved.put;
taken_with_undo -= moved.taken;
}
let digit_hex = HEX[*original_digit as usize];
let mut best_move: Option<Move> = None;
let mut best_diff = i16::MAX;
for (j, to_digit) in HEX.iter().enumerate().rev() {
let put = amount_put(digit_hex, *to_digit);
let taken = amount_put(*to_digit, digit_hex);
let new_total_put = put_with_undo + put;
let new_total_taken = taken_with_undo + taken;
let new_diff = (new_total_put as i16 - new_total_taken as i16).abs();
if new_diff < (total_put as i16 - total_taken as i16).abs() &&
new_total_taken <= max_swaps && new_total_put <= max_swaps && new_diff < best_diff {
best_diff = new_diff;
best_move = Some(Move {
digit: j as u8,
put,
taken,
if total_swaps.put != total_swaps.taken {
total_swaps = change_digits(digits.iter_mut().rev(), total_swaps, max_swaps, i16::MAX, false, |new_total_swaps, total_swaps, best_diff| {
let new_diff = (new_total_swaps.put as i16 - new_total_swaps.taken as i16).abs();
let change_digit = new_diff < (total_swaps.put as i16 - total_swaps.taken as i16).abs()
&& new_diff < *best_diff;
if change_digit {*best_diff = new_diff;}
ChangeDigitsControl {change_digit, break_free: false}
});
}
}
if let Some(moved) = best_move {
*move_option = best_move;
total_put = put_with_undo + moved.put;
total_taken = taken_with_undo + moved.taken;
}
}
}
println!("taken {}, put {}", total_swaps.taken, total_swaps.put);
(digits, max_swaps)
}
}
fn amount_put(from: u8, to: u8) -> u16 {
((from ^ to) & to).count_ones() as u16
}
pub fn to_hex_str(digits: &[DigitHistory]) -> String {
let mut largest_hex_str = String::with_capacity(digits.len());
for digit in digits {
@ -125,9 +92,9 @@ pub fn to_hex_str(digits: &[DigitHistory]) -> String {
largest_hex_str
}
pub fn gen_swaps(digits: &[DigitHistory], number_of_swaps: usize) -> (Vec<PutTaken>, Vec<PutTaken>) {
let mut moves_put: Vec<PutTaken> = Vec::with_capacity(number_of_swaps);
let mut moves_taken: Vec<PutTaken> = Vec::with_capacity(number_of_swaps);
pub fn gen_swaps(digits: &[DigitHistory], number_of_swaps: usize) -> (Vec<ChangedSticks>, Vec<ChangedSticks>) {
let mut moves_put: Vec<ChangedSticks> = Vec::with_capacity(number_of_swaps);
let mut moves_taken: Vec<ChangedSticks> = Vec::with_capacity(number_of_swaps);
for (j, DigitHistory {original_digit, move_option}) in digits.iter().enumerate() {
if let Some(moved) = move_option {
let from_hex = HEX[*original_digit as usize];
@ -139,7 +106,7 @@ pub fn gen_swaps(digits: &[DigitHistory], number_of_swaps: usize) -> (Vec<PutTak
for i in 0..u8::BITS {
let stick_map = put_or_taken & 1 << i;
if stick_map != 0 {
moves_put_or_taken.push(PutTaken {
moves_put_or_taken.push(ChangedSticks {
digit_i: j,
stick_map,
});
@ -150,3 +117,45 @@ pub fn gen_swaps(digits: &[DigitHistory], number_of_swaps: usize) -> (Vec<PutTak
}
(moves_put, moves_taken)
}
fn change_digits<'a, I: Iterator<Item = &'a mut DigitHistory>, T: Copy,
F: Fn(PutTaken, PutTaken, &mut T) -> ChangeDigitsControl>
(iter: I, mut total_swaps: PutTaken, max_swaps: u16, init_t: T, higher_digit: bool, run: F) -> PutTaken {
for DigitHistory {original_digit, move_option} in iter {
if higher_digit && move_option.is_some() {continue;}
let mut swaps_with_undo = total_swaps;
if let Some(moved) = move_option {
swaps_with_undo -= moved.swaps;
}
let digit_hex = HEX[*original_digit as usize];
let mut best_move: Option<Move> = None;
let mut t = init_t;
for (j, to_digit) in HEX.iter().enumerate().rev() {
if j as u8 == *original_digit {
if higher_digit {break;}
else {continue;}
}
let changed_sticks = digit_hex ^ *to_digit;
let swaps = PutTaken {
put: (changed_sticks & *to_digit).count_ones() as u16,
taken: (changed_sticks & digit_hex).count_ones() as u16,
};
let new_total_swaps = swaps_with_undo + swaps;
if new_total_swaps.put <= max_swaps && new_total_swaps.taken <= max_swaps {
let control = run(new_total_swaps, total_swaps, &mut t);
if control.change_digit {
best_move = Some(Move {
digit: j as u8,
swaps,
});
}
if control.break_free {break;}
}
}
if let Some(moved) = best_move {
*move_option = best_move;
total_swaps = swaps_with_undo + moved.swaps;
}
}
total_swaps
}

View File

@ -9,12 +9,17 @@ struct Args {
/// Ausgabe der Umlegungen
#[clap(short, long)]
swap_print: bool,
/// Ausgabe der Anzahl der Umlegungen
#[clap(short, long)]
number_of_swaps_print: bool,
}
fn main() {
let args = Args::parse();
let (digits, number_of_swaps) = hexmax::largest_hex(&args.filepath);
println!("{}", hexmax::to_hex_str(&digits));
if args.number_of_swaps_print {println!("Anzahl der Umlegungen: {}", number_of_swaps);}
if args.swap_print {
let (moves_put, moves_taken) = hexmax::gen_swaps(&digits, number_of_swaps as usize);
let mut digits_hex: Vec<u8> = digits.iter()
@ -25,7 +30,7 @@ fn main() {
let mut not_first = false;
for (move_put, move_taken) in moves_put.iter().zip(&moves_taken) {
if not_first {println!();}
for hexmax::PutTaken {digit_i, stick_map} in [move_put, move_taken] {
for hexmax::ChangedSticks {digit_i, stick_map} in [move_put, move_taken] {
digits_hex[*digit_i] ^= stick_map;
}
swap_print(&digits_hex);

View File

@ -0,0 +1,2 @@
8D5
3