summary refs log tree commit diff
path: root/bonusaufgabe/src
diff options
context:
space:
mode:
Diffstat (limited to 'bonusaufgabe/src')
-rw-r--r--bonusaufgabe/src/main.rs304
1 files changed, 304 insertions, 0 deletions
diff --git a/bonusaufgabe/src/main.rs b/bonusaufgabe/src/main.rs
new file mode 100644
index 0000000..f3a0301
--- /dev/null
+++ b/bonusaufgabe/src/main.rs
@@ -0,0 +1,304 @@
+use bitvec::prelude::*;
+use std::borrow::Borrow;
+use std::env;
+use std::fmt;
+use std::fs;
+use std::marker::PhantomData;
+use std::mem;
+use std::ops::BitXor;
+use std::path::Display;
+use std::process;
+
+fn main() {
+    let task_file_name = match env::args().nth(1) {
+        Some(x) => x,
+        None => {
+            eprintln!("Nutzung: bonusaufgabe <dateiname>");
+            process::exit(1);
+        }
+    };
+    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");
+
+    match solve_task(task) {
+        Some(solution) => println!("{}", solution),
+        None => eprintln!("Keine Lösung gefunden"),
+    }
+}
+
+#[derive(Clone)]
+struct Card(Vec<bool>);
+
+struct Task {
+    cards: Vec<Card>,
+    num_pass_cards: usize,
+    bits_per_card: usize,
+}
+
+struct Solution {
+    real_cards: Vec<Card>,
+}
+
+fn solve_task(task: Task) -> Option<Solution> {
+    let Task {
+        cards,
+        num_pass_cards,
+        bits_per_card,
+    } = task;
+    let num_cards = cards.len();
+    let num_real_cards = num_pass_cards + 1;
+
+    let mut matrix: Vec<BitVec> = vec![BitVec::with_capacity(num_cards); bits_per_card];
+    for card in cards.iter() {
+        for (bit_idx, bit) in card.0.iter().enumerate() {
+            matrix[bit_idx].push(*bit);
+        }
+    }
+
+    let mut free_vars = Vec::new();
+    let mut basic_vars = Vec::new();
+
+    let mut current_row = 0;
+    let mut current_col = 0;
+    while current_row < bits_per_card && current_col < num_cards {
+        let pivot_row = match (current_row..bits_per_card).find(|row| matrix[*row][current_col]) {
+            Some(row) => row,
+            None => {
+                free_vars.push(current_col);
+                current_col += 1;
+                continue;
+            }
+        };
+        matrix.swap(current_row, pivot_row);
+        basic_vars.push((current_row, current_col));
+        for lower_row in (current_row + 1)..bits_per_card {
+            if matrix[lower_row][current_col] {
+                let current_row_cloned = matrix[current_row].clone();
+                matrix[lower_row] ^= current_row_cloned;
+            }
+        }
+        current_row += 1;
+        current_col += 1;
+    }
+    free_vars.extend(current_col..num_cards);
+
+    let num_basic_vars = basic_vars.len();
+    let num_free_vars = free_vars.len();
+
+    // Sanity Check: Nach dem Rangsatz immer erfüllt
+    assert_eq!(num_basic_vars + num_free_vars, num_cards);
+
+    for (pivot_row, pivot_col) in basic_vars.iter().rev() {
+        for upper_row in (0..*pivot_row).rev() {
+            if matrix[upper_row][*pivot_col] {
+                let pivot_row_cloned = matrix[*pivot_row].clone();
+                matrix[upper_row] ^= pivot_row_cloned;
+            }
+        }
+    }
+
+    print_matrix(&matrix);
+
+    let basic_vars_terms = basic_vars
+        .iter()
+        .map(|(basic_var_row, _basic_var_col)| {
+            free_vars
+                .iter()
+                .map(|free_var| matrix[*basic_var_row][*free_var])
+                .collect::<BitVec>()
+        })
+        .collect::<Vec<BitVec>>();
+
+    println!("num_real_cards {}", num_real_cards);
+    println!("num_cards {}", num_cards);
+    println!("num_free_vars {}", num_free_vars);
+    println!("num_basic_vars {}", num_basic_vars);
+
+    // std::process::exit(0);
+
+    let mut solution = None;
+
+    'outer: for num_ones_in_free_vars in 0..=(num_free_vars.min(num_real_cards)) {
+        let mut iterator = BitSubsetIterator::new(num_free_vars, num_ones_in_free_vars);
+        while let Some(free_var_values) = iterator.next() {
+            // print!("trying ");
+            // for b in free_var_values {
+            //     if *b {
+            //         print!("1");
+            //     } else {
+            //         print!("0");
+            //     }
+            // }
+            // println!("");
+
+            let basic_var_values = basic_vars_terms
+                .iter()
+                .map(|basic_var_term| {
+                    let basic_var_solution_term = basic_var_term.clone() & free_var_values;
+                    let basic_var_solution = basic_var_solution_term
+                        .iter()
+                        .fold(false, |acc, bit| acc ^ *bit);
+                    basic_var_solution
+                })
+                .collect::<BitVec>();
+            let num_ones_in_basic_vars = basic_var_values
+                .iter()
+                .filter(|solution_bit| **solution_bit)
+                .count();
+            let num_ones_in_solution = num_ones_in_free_vars + num_ones_in_basic_vars;
+
+            if num_ones_in_solution == num_real_cards {
+                let mut solution_vector = BitVec::<usize, Lsb0>::repeat(false, num_cards);
+
+                for (free_var_idx, free_var_val) in free_vars.iter().zip(free_var_values.iter()) {
+                    solution_vector.set(*free_var_idx, *free_var_val);
+                }
+                for ((_, basic_var_idx), basic_var_val) in
+                    basic_vars.iter().zip(basic_var_values.iter())
+                {
+                    solution_vector.set(*basic_var_idx, *basic_var_val);
+                }
+
+                assert_eq!(solution_vector.count_ones(), num_real_cards);
+                //TODO: more sanity checks
+
+                print!("solution free vars ");
+                for b in free_var_values {
+                    if *b {
+                        print!("1");
+                    } else {
+                        print!("0");
+                    }
+                }
+                println!("");
+
+                solution = Some(Solution {
+                    real_cards: solution_vector
+                        .into_iter()
+                        .enumerate()
+                        .filter(|(_card_idx, is_real)| *is_real)
+                        .map(|(real_card_idx, _)| (cards[real_card_idx]).clone())
+                        .collect(),
+                });
+
+                break 'outer;
+            }
+        }
+    }
+
+    solution
+}
+
+struct BitSubsetIterator {
+    fresh: bool,
+    state: BitVec<usize, Lsb0>,
+}
+
+impl BitSubsetIterator {
+    fn new(set_size: usize, subset_size: usize) -> Self {
+        let mut initial_state = BitVec::repeat(false, set_size);
+        initial_state.get_mut(0..subset_size).unwrap().fill(true);
+
+        Self {
+            fresh: true,
+            state: initial_state,
+        }
+    }
+
+    fn next(&mut self) -> Option<&BitSlice> {
+        if self.fresh {
+            self.fresh = false;
+            Some(self.state.borrow())
+        } else {
+            self.state
+                .iter_ones()
+                .enumerate()
+                .find(
+                    |(_num_prev_ones, one_idx)| match self.state.get(*one_idx + 1) {
+                        Some(bit) => !bit,
+                        None => false,
+                    },
+                )
+                .map(|(num_prev_ones, moveable_one_idx)| {
+                    self.state.set(moveable_one_idx, false);
+                    self.state.set(moveable_one_idx + 1, true);
+                    self.state.get_mut(0..num_prev_ones).unwrap().fill(true);
+                    self.state
+                        .get_mut(num_prev_ones..moveable_one_idx)
+                        .unwrap()
+                        .fill(false);
+                    self.state.borrow()
+                })
+        }
+    }
+}
+
+fn print_matrix(matrix: &[BitVec]) {
+    for row in matrix {
+        for col in row {
+            if *col {
+                print!("1");
+            } else {
+                print!("0");
+            }
+        }
+        println!("");
+    }
+}
+
+impl TryFrom<&str> for Task {
+    type Error = ();
+
+    fn try_from(value: &str) -> Result<Self, Self::Error> {
+        let mut lines = value.lines();
+        let first_line = lines.next().ok_or(())?;
+        let mut first_line_words = first_line.split_ascii_whitespace();
+
+        let total_num_cards_str = first_line_words.next().ok_or(())?;
+        let total_num_cards = str::parse::<usize>(total_num_cards_str).map_err(|_| ())?;
+        let num_pass_cards_str = first_line_words.next().ok_or(())?;
+        let num_pass_cards = str::parse::<usize>(num_pass_cards_str).map_err(|_| ())?;
+        let bits_per_card_str = first_line_words.next().ok_or(())?;
+        let bits_per_card = str::parse::<usize>(bits_per_card_str).map_err(|_| ())?;
+
+        let cards = lines
+            .into_iter()
+            .map(|line| {
+                Card(
+                    line.chars()
+                        .flat_map(|char| match char {
+                            '0' => Some(false),
+                            '1' => Some(true),
+                            _ => None,
+                        })
+                        .collect::<Vec<bool>>(),
+                )
+            })
+            .collect::<Vec<Card>>();
+
+        if cards.len() != total_num_cards {
+            return Err(());
+        }
+
+        Ok(Task {
+            cards,
+            num_pass_cards,
+            bits_per_card,
+        })
+    }
+}
+
+impl fmt::Display for Solution {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        for card in self.real_cards.iter() {
+            for bit in card.0.iter() {
+                match bit {
+                    true => write!(f, "1")?,
+                    false => write!(f, "0")?,
+                };
+            }
+            writeln!(f, "")?;
+        }
+        Ok(())
+    }
+}