summary refs log tree commit diff
path: root/aufgabe3/src/main.rs
diff options
context:
space:
mode:
authorMalte Voos <git@mal.tc>2022-08-20 14:12:11 +0200
committerMalte Voos <git@mal.tc>2022-08-20 14:12:11 +0200
commitd0c70ad88b11f412c9d8c6735b74cce1b1ff015b (patch)
tree2f0e9821a785e083abfe851ce919cadbefe001af /aufgabe3/src/main.rs
parent5f22745507a343163521fbe85cdc72ac144c319f (diff)
downloadbwinf402-main.tar.gz
bwinf402-main.zip
cleanup main
Diffstat (limited to 'aufgabe3/src/main.rs')
-rw-r--r--aufgabe3/src/main.rs224
1 files changed, 111 insertions, 113 deletions
diff --git a/aufgabe3/src/main.rs b/aufgabe3/src/main.rs
index 556ff9d..fbf554d 100644
--- a/aufgabe3/src/main.rs
+++ b/aufgabe3/src/main.rs
@@ -24,11 +24,20 @@ struct Task {
     max_moves: usize,
 }
 
-// Beschreibt den Zustand einer Siebensegmentanzeige.
+// Beschreibt den Zustand einer Siebensegmentanzeige als 8-Bit-Zahl.
+//
+// Die ersten sieben Bits (von rechts) geben jeweils an, ob das entsprechende
+// Segment der Siebensegmentanzeige "an" ist bzw. ein Stäbchen enthält: wenn
+// ja, ist das Bit eine 1; anderenfalls eine 0. Das letzte Bit ist immer eine
+// 0.
+//
 // Die Reihenfolge der Segmente entspricht dieser Abbildung:
 // https://en.wikipedia.org/wiki/Seven-segment_display#/media/File:7_Segment_Display_with_Labeled_Segments.svg
+//
+// Allgemein wird der Zustand der Siebensegmentanzeige also durch die Zahl
+// 0b0GFEDCBA repräsentiert.
 #[derive(Clone, Copy)]
-struct SevenSegmentDisplay([bool; 7]);
+struct SevenSegmentDisplay(u8);
 
 // Beschreibt den Zustand einer Reihe von Siebensegmentanzeigen.
 struct SevenSegmentDisplayRow {
@@ -68,8 +77,6 @@ fn solve_task(task: Task) -> Solution {
     }
 }
 
-static mut BACKTRACK: usize = 0;
-
 // Implementiert den ersten Teil des Algorithmus, der aus einer Aufgabe die
 // größtmögliche Hex-Zahl errechnet.
 fn solve_pt1(task: &Task) -> Vec<HexDigit> {
@@ -115,7 +122,6 @@ fn solve_pt1(task: &Task) -> Vec<HexDigit> {
             // '1' reduziert werden.
             || -segment_balance > occupied_segments_left as isize
         {
-            unsafe { BACKTRACK += 1 };
             return None;
         }
         // Es wird immer nur die erste Ziffer betrachtet, und die restlichen
@@ -126,22 +132,19 @@ fn solve_pt1(task: &Task) -> Vec<HexDigit> {
             // `segment_balance` gleich 0 ist (s.o.).
             None => match segment_balance {
                 0 => Some(Vec::new()),
-                _ => {
-                    unsafe { BACKTRACK += 1 };
-                    None
-                }
+                _ => None,
             },
             Some((digit, rest)) => {
                 // Die Anzahl der Stäbchen, aus der die erste Ziffer besteht.
-                let digit_num_segments = digit.num_segments();
+                let digit_num_sticks = digit.num_sticks();
                 // `vacant_segments_left` und `occupied_segments_left` müssen
                 // bezogen auf die restlichen Stäbchen angepasst werden.
                 // '8', die Ziffer bestehend aus den meisten Stäbchen, enthält
                 // 7 Stäbchen.
-                let new_vacant_segments_left = vacant_segments_left - (7 - digit_num_segments);
+                let new_vacant_segments_left = vacant_segments_left - (7 - digit_num_sticks);
                 // '1', die Ziffer bestehend aus den wenigsten Stäbchen,
                 // enthält 2 Stäbchen.
-                let new_occupied_segments_left = occupied_segments_left - (digit_num_segments - 2);
+                let new_occupied_segments_left = occupied_segments_left - (digit_num_sticks - 2);
 
                 // Es wird versucht, die erste Ziffer zu maximieren. Dafür
                 // werden alle möglichen Hex-Ziffern absteigend durchgegangen
@@ -155,7 +158,7 @@ fn solve_pt1(task: &Task) -> Vec<HexDigit> {
                     // alten und der neuen Anzahl an Stäbchen für die erste
                     // Ziffer.
                     let segment_num_difference =
-                        digit_num_segments as isize - candidate_digit.num_segments() as isize;
+                        digit_num_sticks as isize - candidate_digit.num_sticks() as isize;
                     // `num_required_segment_flips` ist die erforderliche
                     // Anzahl an "Stäbchen-Flips" (s.o.), um von der alten
                     // ersten Ziffer zur neuen zu kommen.
@@ -217,7 +220,6 @@ fn solve_pt1(task: &Task) -> Vec<HexDigit> {
                 // Der Pfad wird verworfen, da unter den gegebenen Bedingungen
                 // für keinen Wert der ersten Ziffer eine gültige neue
                 // Ziffernfolge gefunden werden konnte.
-                unsafe { BACKTRACK += 1 };
                 None
             }
         }
@@ -233,25 +235,22 @@ fn solve_pt1(task: &Task) -> Vec<HexDigit> {
     let (initial_vacant_segments, initial_occupied_segments) = task.number.digits.iter().fold(
         (0, 0),
         |(acc_vacant_segments, acc_occupied_segments), digit| {
-            let num_segments = digit.num_segments();
+            let num_sticks = digit.num_sticks();
             (
-                acc_vacant_segments + (7 - num_segments),
-                acc_occupied_segments + (num_segments - 2),
+                acc_vacant_segments + (7 - num_sticks),
+                acc_occupied_segments + (num_sticks - 2),
             )
         },
     );
 
-    let ret = solve_pt1_internal(
+    solve_pt1_internal(
         &task.number.digits,
         0,
         max_segment_flips,
         initial_vacant_segments,
         initial_occupied_segments,
     )
-    .unwrap();
-
-    println!("backtracks: {}", unsafe { BACKTRACK });
-    ret
+    .unwrap()
 }
 
 // Implementiert den zweiten Teil des Algorithmus, der aus der gegebenen
@@ -279,7 +278,7 @@ fn solve_pt2(start: &[HexDigit], end: &[HexDigit]) -> Vec<SevenSegmentDisplayRow
     // Siebensegmentanzeigen.
     struct Coordinates {
         display_idx: usize,
-        segment_idx: usize,
+        segment_idx: u8,
     }
 
     let mut current_state = start_state.clone();
@@ -298,18 +297,17 @@ fn solve_pt2(start: &[HexDigit], end: &[HexDigit]) -> Vec<SevenSegmentDisplayRow
         // In diesen beiden Arrays werden die Indizes der Segmente gespeichert,
         // die in dieser Siebensegmentanzeige "ein-" bzw. "ausgeschaltet"
         // werden müssen.
-        let mut on_flips = VecDeque::<usize>::new();
-        let mut off_flips = VecDeque::<usize>::new();
+        let mut on_flips = VecDeque::<u8>::new();
+        let mut off_flips = VecDeque::<u8>::new();
 
         for (segment_idx, (segment_start, segment_end)) in segments_start
-            .0
-            .iter()
-            .zip(segments_end.0.iter())
+            .into_iter()
+            .zip(segments_end.into_iter())
             .enumerate()
         {
             match (segment_start, segment_end) {
-                (false, true) => on_flips.push_back(segment_idx),
-                (true, false) => off_flips.push_back(segment_idx),
+                (false, true) => on_flips.push_back(segment_idx as u8),
+                (true, false) => off_flips.push_back(segment_idx as u8),
                 _ => {}
             }
         }
@@ -326,8 +324,8 @@ fn solve_pt2(start: &[HexDigit], end: &[HexDigit]) -> Vec<SevenSegmentDisplayRow
             .drain(..num_intra_display_moves)
             .zip(off_flips.drain(..num_intra_display_moves))
         {
-            current_state[display_idx].0[on_flip] = true;
-            current_state[display_idx].0[off_flip] = false;
+            current_state[display_idx].toggle(on_flip);
+            current_state[display_idx].toggle(off_flip);
             states.push(SevenSegmentDisplayRow {
                 displays: current_state.clone(),
             })
@@ -355,8 +353,8 @@ fn solve_pt2(start: &[HexDigit], end: &[HexDigit]) -> Vec<SevenSegmentDisplayRow
         .into_iter()
         .zip(unmatched_off_flips.into_iter())
     {
-        current_state[on_flip.display_idx].0[on_flip.segment_idx] = true;
-        current_state[off_flip.display_idx].0[off_flip.segment_idx] = false;
+        current_state[on_flip.display_idx].toggle(on_flip.segment_idx);
+        current_state[off_flip.display_idx].toggle(off_flip.segment_idx);
         states.push(SevenSegmentDisplayRow {
             displays: current_state.clone(),
         })
@@ -369,47 +367,82 @@ impl HexDigit {
     // Stellt eine Hex-Ziffer auf einer Siebensegmentanzeige dar.
     fn to_seven_segments(self) -> SevenSegmentDisplay {
         let segments = match self.0 {
-            0x0 => [true, true, true, true, true, true, false],
-            0x1 => [false, true, true, false, false, false, false],
-            0x2 => [true, true, false, true, true, false, true],
-            0x3 => [true, true, true, true, false, false, true],
-            0x4 => [false, true, true, false, false, true, true],
-            0x5 => [true, false, true, true, false, true, true],
-            0x6 => [true, false, true, true, true, true, true],
-            0x7 => [true, true, true, false, false, false, false],
-            0x8 => [true, true, true, true, true, true, true],
-            0x9 => [true, true, true, true, false, true, true],
-            0xA => [true, true, true, false, true, true, true],
-            0xB => [false, false, true, true, true, true, true],
-            0xC => [true, false, false, true, true, true, false],
-            0xD => [false, true, true, true, true, false, true],
-            0xE => [true, false, false, true, true, true, true],
-            0xF => [true, false, false, false, true, true, true],
+            0x0 => 0b0111111,
+            0x1 => 0b0000110,
+            0x2 => 0b1011011,
+            0x3 => 0b1001111,
+            0x4 => 0b1100110,
+            0x5 => 0b1101101,
+            0x6 => 0b1111101,
+            0x7 => 0b0000111,
+            0x8 => 0b1111111,
+            0x9 => 0b1101111,
+            0xA => 0b1110111,
+            0xB => 0b1111100,
+            0xC => 0b0111001,
+            0xD => 0b1011110,
+            0xE => 0b1111001,
+            0xF => 0b1110001,
             _ => unreachable!(),
         };
         SevenSegmentDisplay(segments)
     }
 
-    // Gibt die Anzahl der Stäbchen zurück, die für die Darstellung einer
+    // Gibt die Anzahl der Stäbchen zurück, die für die Darstellung dieser
     // Hex-Ziffer auf einer Siebensegmentanzeige benötigt werden.
-    fn num_segments(self) -> usize {
-        self.to_seven_segments()
-            .0
-            .into_iter()
-            .filter(|x| *x)
-            .count()
+    fn num_sticks(self) -> usize {
+        self.to_seven_segments().0.count_ones() as usize
     }
 
     // Gibt die Anzahl der "Stäbchen-Flips" zurück, die benötigt werden, um
-    // von der Siebensegmentdarstellung einer Hex-Ziffer zu der einer anderen
+    // von der Siebensegmentdarstellung dieser Hex-Ziffer zu der einer anderen
     // zu gelangen.
     fn num_required_segment_flips(self, other: Self) -> usize {
-        self.to_seven_segments()
-            .0
-            .into_iter()
-            .zip(other.to_seven_segments().0.into_iter())
-            .filter(|(segment_self, segment_other)| *segment_self != *segment_other)
-            .count()
+        (self.to_seven_segments().0 ^ other.to_seven_segments().0).count_ones() as usize
+    }
+}
+
+impl SevenSegmentDisplay {
+    // Gibt das `idx`-te Segment dieser Siebensegmentanzeige zurück.
+    fn get(self, idx: u8) -> bool {
+        self.0 & (1 << idx) != 0
+    }
+
+    // Schaltet das `idx`-te Segmente dieser Siebensegmentanzeige um.
+    fn toggle(&mut self, idx: u8) {
+        self.0 ^= 1 << idx;
+    }
+}
+
+// Iterator über die Segmente einer Siebensegmentanzeige.
+struct SevenSegmentDisplayIterator {
+    idx: u8,
+    display: SevenSegmentDisplay,
+}
+
+impl Iterator for SevenSegmentDisplayIterator {
+    type Item = bool;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.idx <= 7 {
+            let bit = self.display.get(self.idx);
+            self.idx += 1;
+            Some(bit)
+        } else {
+            None
+        }
+    }
+}
+
+impl IntoIterator for SevenSegmentDisplay {
+    type Item = bool;
+    type IntoIter = SevenSegmentDisplayIterator;
+
+    fn into_iter(self) -> Self::IntoIter {
+        SevenSegmentDisplayIterator {
+            idx: 0,
+            display: self,
+        }
     }
 }
 
@@ -425,46 +458,12 @@ fn main() {
     let task_str = fs::read_to_string(task_file_name).expect("Datei kann nicht gelesen werden");
     let task = Task::try_from(task_str.as_str()).expect("Datei enthält keine gültige Aufgabe");
 
-    // let start = time::Instant::now();
-    // let solution = solve_task(task);
-    // let elapsed = start.elapsed();
-
-    // println!("{}", solution);
-    // println!("Laufzeit ohne I/O: {:?}", elapsed);
-
-    println!("Gegebene Hex-Zahl: {}", &task.number);
-
-    let start_pt1 = time::Instant::now();
-    let greatest_reachable_number = solve_pt1(&task);
-    let elapsed_pt1 = start_pt1.elapsed();
-
-    println!(
-        "Größtmögliche Hex-Zahl: {}",
-        HexNumber {
-            digits: greatest_reachable_number.clone(),
-        }
-    );
-
-    println!();
-    println!("Laufzeit (Teil 1): {:?}", elapsed_pt1);
-    println!();
+    let start = time::Instant::now();
+    let solution = solve_task(task);
+    let elapsed = start.elapsed();
 
-    // let start_pt2 = time::Instant::now();
-    // let states = solve_pt2(&task.number.digits, &greatest_reachable_number);
-    // let elapsed_pt2 = start_pt2.elapsed();
-
-    // println!("Zwischenstände:");
-    // for state in &states {
-    //     print!("{}", state);
-    // }
-    // println!();
-
-    println!("Gegebene Maximalzahl an Umlegungen: {}", task.max_moves);
-    // println!("Anzahl genutzter Umlegungen: {}", states.len() - 1);
-
-    // println!();
-    // println!("Laufzeit (Teil 2): {:?}", elapsed_pt2);
-    // println!("Laufzeit (gesamt ohne I/O): {:?}", elapsed_pt1 + elapsed_pt2);
+    println!("{}", solution);
+    println!("Laufzeit ohne I/O: {:?}", elapsed);
 }
 
 // Liest eine Aufgabe im Format der Beispielaufgaben ein.
@@ -486,9 +485,9 @@ impl TryFrom<&str> for Task {
 impl Display for Solution {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         writeln!(f, "Gegebene Hex-Zahl: {}", self.initial)?;
-        // for state in &self.states {
-        //     state.fmt(f)?;
-        // }
+        for state in &self.states {
+            state.fmt(f)?;
+        }
         writeln!(f, "Größtmögliche Hex-Zahl: {}", self.r#final)?;
         writeln!(f, "Gegebene Maximalzahl an Umlegungen: {}", self.max_moves)?;
         writeln!(f, "Anzahl genutzter Umlegungen: {}", self.used_moves)?;
@@ -577,16 +576,15 @@ impl Display for HexNumber {
 // "Box Drawing" dar.
 impl SevenSegmentDisplay {
     fn to_unicode(&self) -> [[char; 2]; 3] {
-        let s = self.0;
         [
             [
-                match (s[0], s[5]) {
+                match (self.get(0), self.get(5)) {
                     (false, false) => ' ',
                     (false, true) => '╻',
                     (true, false) => '╺',
                     (true, true) => '┏',
                 },
-                match (s[0], s[1]) {
+                match (self.get(0), self.get(1)) {
                     (false, false) => ' ',
                     (false, true) => '╻',
                     (true, false) => '╸',
@@ -594,7 +592,7 @@ impl SevenSegmentDisplay {
                 },
             ],
             [
-                match (s[4], s[5], s[6]) {
+                match (self.get(4), self.get(5), self.get(6)) {
                     (false, false, false) => ' ',
                     (false, false, true) => '╺',
                     (false, true, false) => '╹',
@@ -604,7 +602,7 @@ impl SevenSegmentDisplay {
                     (true, true, false) => '┃',
                     (true, true, true) => '┣',
                 },
-                match (s[1], s[2], s[6]) {
+                match (self.get(1), self.get(2), self.get(6)) {
                     (false, false, false) => ' ',
                     (false, false, true) => '╸',
                     (false, true, false) => '╻',
@@ -616,13 +614,13 @@ impl SevenSegmentDisplay {
                 },
             ],
             [
-                match (s[3], s[4]) {
+                match (self.get(3), self.get(4)) {
                     (false, false) => ' ',
                     (false, true) => '╹',
                     (true, false) => '╺',
                     (true, true) => '┗',
                 },
-                match (s[2], s[3]) {
+                match (self.get(2), self.get(3)) {
                     (false, false) => ' ',
                     (false, true) => '╸',
                     (true, false) => '╹',