This commit is contained in:
2022-02-27 16:06:04 +01:00
parent 95480f78e4
commit 98ba52e566
2 changed files with 219 additions and 0 deletions

View File

@ -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"] }

210
Aufgabe3-HexMax/src/main.rs Normal file
View File

@ -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<Move>,
}
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<DigitHistory>;
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<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 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<PutTaken> = Vec::with_capacity(total_put as usize);
let mut moves_taken: Vec<PutTaken> = 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<u8> = 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<F: Fn(u8)>(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, '_')));
}