a3 refactoring
This commit is contained in:
@ -7,3 +7,8 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "3.1.0", features = ["derive"] }
|
||||
|
||||
[dependencies.derive_more]
|
||||
version = "0.99.17"
|
||||
default-features = false
|
||||
features = ["add", "add_assign"]
|
||||
|
||||
@ -3,8 +3,7 @@ use std::fs;
|
||||
#[derive(Clone, Copy)]
|
||||
struct Move {
|
||||
digit: u8,
|
||||
put: u16,
|
||||
taken: u16,
|
||||
swaps: PutTaken,
|
||||
}
|
||||
|
||||
pub struct DigitHistory {
|
||||
@ -12,11 +11,22 @@ pub struct DigitHistory {
|
||||
move_option: Option<Move>,
|
||||
}
|
||||
|
||||
pub struct PutTaken {
|
||||
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
|
||||
@ -53,70 +63,27 @@ pub fn largest_hex(filepath: &str) -> (Vec<DigitHistory>, u16) {
|
||||
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;
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -125,9 +92,9 @@ pub fn to_hex_str(digits: &[DigitHistory]) -> String {
|
||||
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);
|
||||
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];
|
||||
@ -139,7 +106,7 @@ pub fn gen_swaps(digits: &[DigitHistory], number_of_swaps: usize) -> (Vec<PutTak
|
||||
for i in 0..u8::BITS {
|
||||
let stick_map = put_or_taken & 1 << i;
|
||||
if stick_map != 0 {
|
||||
moves_put_or_taken.push(PutTaken {
|
||||
moves_put_or_taken.push(ChangedSticks {
|
||||
digit_i: j,
|
||||
stick_map,
|
||||
});
|
||||
@ -150,3 +117,45 @@ pub fn gen_swaps(digits: &[DigitHistory], number_of_swaps: usize) -> (Vec<PutTak
|
||||
}
|
||||
(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
|
||||
}
|
||||
|
||||
@ -9,12 +9,17 @@ struct Args {
|
||||
/// Ausgabe der Umlegungen
|
||||
#[clap(short, long)]
|
||||
swap_print: bool,
|
||||
|
||||
/// Ausgabe der Anzahl der Umlegungen
|
||||
#[clap(short, long)]
|
||||
number_of_swaps_print: bool,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
let (digits, number_of_swaps) = hexmax::largest_hex(&args.filepath);
|
||||
println!("{}", hexmax::to_hex_str(&digits));
|
||||
if args.number_of_swaps_print {println!("Anzahl der Umlegungen: {}", number_of_swaps);}
|
||||
if args.swap_print {
|
||||
let (moves_put, moves_taken) = hexmax::gen_swaps(&digits, number_of_swaps as usize);
|
||||
let mut digits_hex: Vec<u8> = digits.iter()
|
||||
@ -25,7 +30,7 @@ fn main() {
|
||||
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] {
|
||||
for hexmax::ChangedSticks {digit_i, stick_map} in [move_put, move_taken] {
|
||||
digits_hex[*digit_i] ^= stick_map;
|
||||
}
|
||||
swap_print(&digits_hex);
|
||||
|
||||
2
Aufgabe3-HexMax/testdaten/0.txt
Normal file
2
Aufgabe3-HexMax/testdaten/0.txt
Normal file
@ -0,0 +1,2 @@
|
||||
8D5
|
||||
3
|
||||
Reference in New Issue
Block a user