diff --git a/Aufgabe3-HexMax/Cargo.toml b/Aufgabe3-HexMax/Cargo.toml new file mode 100644 index 0000000..cb42a53 --- /dev/null +++ b/Aufgabe3-HexMax/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "hexmax" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "3.1.0", features = ["derive"] } diff --git a/Aufgabe3-HexMax/src/main.rs b/Aufgabe3-HexMax/src/main.rs new file mode 100644 index 0000000..c07e814 --- /dev/null +++ b/Aufgabe3-HexMax/src/main.rs @@ -0,0 +1,210 @@ +use clap::Parser; +use std::fs; + +#[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)); + } + 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; + } + } + } + } +} + +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); + print_vertical(digits_hex, 3); + print_horizontal(digits_hex, 2); + print_vertical(digits_hex, 0); +} + +fn print_helper(digits_hex: &[u8], run: F) { + let mut not_first = false; + for digit in digits_hex { + if not_first {print!(" ")} + run(*digit); + not_first = true; + } + println!(); +} + +fn print_stick(digit: u8, i: u8, stick_char: char) -> char { + if digit >> i & 1 == 1 {stick_char} else {' '} +} + +fn print_horizontal(digits_hex: &[u8], i: u8) { + print_helper(digits_hex, |digit| + print!("{} {}", print_stick(digit, i, '|'), print_stick(digit, i - 1, '|')) + ); +} + +fn print_vertical(digits_hex: &[u8], i: u8) { + print_helper(digits_hex, |digit| print!(" {} ", print_stick(digit, i, '_'))); +}