This commit is contained in:
2022-02-27 20:00:18 +01:00
parent 98ba52e566
commit a9cf3d041a
3 changed files with 223 additions and 159 deletions

152
Aufgabe3-HexMax/src/lib.rs Normal file
View File

@ -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<Move>,
}
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<DigitHistory>, u16) {
let mut digits: Vec<DigitHistory>;
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<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;
}
}
}
(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<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);
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)
}

View File

@ -1,182 +1,39 @@
use clap::Parser; use clap::Parser;
use std::fs; use hexmax;
#[derive(Parser)] #[derive(Parser)]
struct Args { struct Args {
/// Dateipfad der Eingabedatei /// Dateipfad der Eingabedatei
filepath: String, filepath: String,
/// Ausgabe von Debuginformationen
#[clap(short, long)]
debug: bool,
/// Ausgabe der Umlegungen /// Ausgabe der Umlegungen
#[clap(short, long)] #[clap(short, long)]
swap_print: bool, 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() { fn main() {
let args = Args::parse(); let args = Args::parse();
let mut digits: Vec<DigitHistory>; let (digits, number_of_swaps) = hexmax::largest_hex(&args.filepath);
let max_swaps: u16; println!("{}", hexmax::to_hex_str(&digits));
{ if args.swap_print {
let content = fs::read_to_string(args.filepath).unwrap(); let (moves_put, moves_taken) = hexmax::gen_swaps(&digits, number_of_swaps as usize);
let mut lines = content.lines(); let mut digits_hex: Vec<u8> = digits.iter()
let line = lines.next().unwrap(); .map(|digit| hexmax::HEX[digit.original_digit as usize]).collect();
digits = Vec::with_capacity(line.len()); println!("Umlegungen:");
for character in line.chars() { swap_print(&digits_hex);
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!(); println!();
if args.debug {println!("genommen: {}, hingelegt: {}", total_taken, total_put);} let mut not_first = false;
if args.swap_print { for (move_put, move_taken) in moves_put.iter().zip(&moves_taken) {
let mut moves_put: Vec<PutTaken> = Vec::with_capacity(total_put as usize); if not_first {println!();}
let mut moves_taken: Vec<PutTaken> = Vec::with_capacity(total_taken as usize); for hexmax::PutTaken {digit_i, stick_map} in [move_put, move_taken] {
for (j, DigitHistory {original_digit, move_option}) in digits.iter().enumerate() { digits_hex[*digit_i] ^= stick_map;
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;
}
} }
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]) { fn swap_print(digits_hex: &[u8]) {
print_vertical(digits_hex, 6); print_vertical(digits_hex, 6);
print_horizontal(digits_hex, 5); print_horizontal(digits_hex, 5);

View File

@ -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"));
}