diff --git a/Aufgabe3-HexMax/src/lib.rs b/Aufgabe3-HexMax/src/lib.rs new file mode 100644 index 0000000..ddc5b3d --- /dev/null +++ b/Aufgabe3-HexMax/src/lib.rs @@ -0,0 +1,152 @@ +use std::fs; + +#[derive(Clone, Copy)] +struct Move { + digit: u8, + put: u16, + taken: u16, +} + +pub struct DigitHistory { + pub original_digit: u8, + move_option: Option, +} + +pub struct PutTaken { + pub digit_i: usize, + pub stick_map: u8, +} + +pub const HEX: [u8; 16] = [ + 0b1110111, // 0 + 0b0010010, // 1 + 0b1011101, // 2 + 0b1011011, // 3 + 0b0111010, // 4 + 0b1101011, // 5 + 0b1101111, // 6 + 0b1010010, // 7 + 0b1111111, // 8 + 0b1111011, // 9 + 0b1111110, // A + 0b0101111, // B + 0b1100101, // C + 0b0011111, // D + 0b1101101, // E + 0b1101100, // F +]; + +pub fn largest_hex(filepath: &str) -> (Vec, u16) { + let mut digits: Vec; + let max_swaps: u16; + { + let content = fs::read_to_string(filepath).unwrap(); + let mut lines = content.lines(); + let line = lines.next().unwrap(); + digits = Vec::with_capacity(line.len()); + for character in line.chars() { + digits.push(DigitHistory { + original_digit: character.to_digit(16).unwrap() as u8, + move_option: None, + }); + } + 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; + } + } + } + (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 { + largest_hex_str += &format!("{:X}", digit.move_option.map_or(digit.original_digit, |m| m.digit)); + } + 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); + 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]; + let to_hex = HEX[moved.digit as usize]; + let changed = from_hex ^ to_hex; + let put = changed & to_hex; + let taken = changed & from_hex; + for (put_or_taken, moves_put_or_taken) in [(put, &mut moves_put), (taken, &mut moves_taken)] { + for i in 0..u8::BITS { + let stick_map = put_or_taken & 1 << i; + if stick_map != 0 { + moves_put_or_taken.push(PutTaken { + digit_i: j, + stick_map, + }); + } + } + } + } + } + (moves_put, moves_taken) +} diff --git a/Aufgabe3-HexMax/src/main.rs b/Aufgabe3-HexMax/src/main.rs index c07e814..ff01fbc 100644 --- a/Aufgabe3-HexMax/src/main.rs +++ b/Aufgabe3-HexMax/src/main.rs @@ -1,182 +1,39 @@ use clap::Parser; -use std::fs; +use hexmax; #[derive(Parser)] struct Args { /// Dateipfad der Eingabedatei filepath: String, - /// Ausgabe von Debuginformationen - #[clap(short, long)] - debug: bool, - /// Ausgabe der Umlegungen #[clap(short, long)] swap_print: bool, } -#[derive(Clone, Copy)] -struct Move { - digit: u8, - put: u16, - taken: u16, -} - -struct DigitHistory { - original_digit: u8, - move_option: Option, -} - -struct PutTaken { - digit_i: usize, - stick_map: u8, -} - -const HEX: [u8; 16] = [ - 0b1110111, // 0 - 0b0010010, // 1 - 0b1011101, // 2 - 0b1011011, // 3 - 0b0111010, // 4 - 0b1101011, // 5 - 0b1101111, // 6 - 0b1010010, // 7 - 0b1111111, // 8 - 0b1111011, // 9 - 0b1111110, // A - 0b0101111, // B - 0b1100101, // C - 0b0011111, // D - 0b1101101, // E - 0b1101100, // F -]; - fn main() { let args = Args::parse(); - let mut digits: Vec; - let max_swaps: u16; - { - let content = fs::read_to_string(args.filepath).unwrap(); - let mut lines = content.lines(); - let line = lines.next().unwrap(); - digits = Vec::with_capacity(line.len()); - for character in line.chars() { - digits.push(DigitHistory { - original_digit: character.to_digit(16).unwrap() as u8, - move_option: None, - }); - } - 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; - } - } - } - for digit in &digits { - print!("{:X}", digit.move_option.map_or(digit.original_digit, |m| m.digit)); - } + let (digits, number_of_swaps) = hexmax::largest_hex(&args.filepath); + println!("{}", hexmax::to_hex_str(&digits)); + 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() + .map(|digit| hexmax::HEX[digit.original_digit as usize]).collect(); + println!("Umlegungen:"); + swap_print(&digits_hex); println!(); - if args.debug {println!("genommen: {}, hingelegt: {}", total_taken, total_put);} - if args.swap_print { - let mut moves_put: Vec = Vec::with_capacity(total_put as usize); - let mut moves_taken: Vec = Vec::with_capacity(total_taken as usize); - 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]; - let to_hex = HEX[moved.digit as usize]; - let changed = from_hex ^ to_hex; - let put = changed & to_hex; - let taken = changed & from_hex; - for (put_or_taken, moves_put_or_taken) in [(put, &mut moves_put), (taken, &mut moves_taken)] { - for i in 0..u8::BITS { - let stick_map = put_or_taken & 1 << i; - if stick_map != 0 { - moves_put_or_taken.push(PutTaken { - digit_i: j, - stick_map, - }); - } - } - } - } - } - { - let mut digits_hex: Vec = digits.iter() - .map(|digit| HEX[digit.original_digit as usize]).collect(); - println!("Umlegungen:"); - swap_print(&digits_hex); - println!(); - let mut not_first = false; - for (move_put, move_taken) in moves_put.iter().zip(&moves_taken) { - if not_first {println!();} - for PutTaken {digit_i, stick_map} in [move_put, move_taken] { - digits_hex[*digit_i] ^= stick_map; - } - swap_print(&digits_hex); - not_first = true; - } + 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] { + digits_hex[*digit_i] ^= stick_map; } + swap_print(&digits_hex); + not_first = true; } } } -fn amount_put(from: u8, to: u8) -> u16 { - ((from ^ to) & to).count_ones() as u16 -} - fn swap_print(digits_hex: &[u8]) { print_vertical(digits_hex, 6); print_horizontal(digits_hex, 5); diff --git a/Aufgabe3-HexMax/tests/test.rs b/Aufgabe3-HexMax/tests/test.rs new file mode 100644 index 0000000..3d34cd6 --- /dev/null +++ b/Aufgabe3-HexMax/tests/test.rs @@ -0,0 +1,55 @@ +use hexmax; + +fn test(filepath: &str, expected_result: &str) { + assert_eq!(hexmax::to_hex_str(&hexmax::largest_hex(filepath).0), expected_result); +} + +#[test] +fn test_0() { + test("beispieldaten/hexmax0.txt", "EE4"); +} + +#[test] +fn test_1() { + test("beispieldaten/hexmax1.txt", "FFFEA97B55"); +} + +#[test] +fn test_2() { + test("beispieldaten/hexmax2.txt", "FFFFFFFFFFFFFFFFD9A9BEAEE8EDA8BDA989D9F8"); +} + +#[test] +fn test_3() { + test("beispieldaten/hexmax3.txt", + concat!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "FAA98BB8B9DFAFEAE888DD888AD8BA8EA8888")); +} + +#[test] +fn test_4() { + test("beispieldaten/hexmax4.txt", + concat!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB8DE88BAA8ADD888898E9BA8", + "8AD98988F898AB7AF7BDA8A61BA7D4AD8F888")); +} + +#[test] +fn test_5() { + test("beispieldaten/hexmax5.txt", + concat!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88EFA9EBE89EFA99FBDAA8", + "E8EAD88AB899F8E8F9AA9E9AD88988EDA9A99888EDAD989A8BAFD8A88888888", + "888888888888888888888888888888888888888888888888888888888888888", + "888888888888888888888888888888888888888888888888888888888888888", + "888888888888888888888888888888888888888888888888888888888888888", + "8888888888888888888888888888888888888888888888888888888")); +}