diff --git a/Aufgabe3-HexMax/Cargo.toml b/Aufgabe3-HexMax/Cargo.toml index cb42a53..fc5d819 100644 --- a/Aufgabe3-HexMax/Cargo.toml +++ b/Aufgabe3-HexMax/Cargo.toml @@ -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"] diff --git a/Aufgabe3-HexMax/src/lib.rs b/Aufgabe3-HexMax/src/lib.rs index ddc5b3d..fa25922 100644 --- a/Aufgabe3-HexMax/src/lib.rs +++ b/Aufgabe3-HexMax/src/lib.rs @@ -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, } -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, 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, - }); - 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 = 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 let Some(moved) = best_move { - *move_option = best_move; - total_put = put_with_undo + moved.put; - total_taken = taken_with_undo + moved.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} + }); + 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} + }); } } + 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, Vec) { - let mut moves_put: Vec = Vec::with_capacity(number_of_swaps); - let mut moves_taken: Vec = Vec::with_capacity(number_of_swaps); +pub fn gen_swaps(digits: &[DigitHistory], number_of_swaps: usize) -> (Vec, Vec) { + let mut moves_put: Vec = Vec::with_capacity(number_of_swaps); + let mut moves_taken: Vec = 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 (Vec, 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 = 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 +} diff --git a/Aufgabe3-HexMax/src/main.rs b/Aufgabe3-HexMax/src/main.rs index ff01fbc..d6b2c5c 100644 --- a/Aufgabe3-HexMax/src/main.rs +++ b/Aufgabe3-HexMax/src/main.rs @@ -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 = 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); diff --git a/Aufgabe3-HexMax/testdaten/0.txt b/Aufgabe3-HexMax/testdaten/0.txt new file mode 100644 index 0000000..e6b5b23 --- /dev/null +++ b/Aufgabe3-HexMax/testdaten/0.txt @@ -0,0 +1,2 @@ +8D5 +3