Files
bwinf40-runde2/Aufgabe3-HexMax/src/lib.rs
2022-03-18 20:02:51 +01:00

162 lines
5.6 KiB
Rust

use std::fs;
#[derive(Clone, Copy)]
struct Move {
digit: u8,
swaps: PutTaken,
}
pub struct DigitHistory {
pub original_digit: u8,
move_option: Option<Move>,
}
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
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_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)
}
}
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<ChangedSticks>, Vec<ChangedSticks>) {
let mut moves_put: Vec<ChangedSticks> = Vec::with_capacity(number_of_swaps);
let mut moves_taken: Vec<ChangedSticks> = 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(ChangedSticks {
digit_i: j,
stick_map,
});
}
}
}
}
}
(moves_put, moves_taken)
}
fn change_digits<'a, I: Iterator<Item = &'a mut DigitHistory>, 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<Move> = 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
}