use std::collections::HashSet; // BitSet implementation #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] struct BitSet { bits: u64, } impl BitSet { fn empty() -> Self { BitSet { bits: 0 } } fn value(&self) -> u64 { self.bits } fn add(&self, item: usize) -> Self { BitSet { bits: self.bits | (1 << item) } } fn add_range(&self, start: usize, count: usize) -> Self { let mask = ((1 << (start + count)) - 1) & !((1 << start) - 1); BitSet { bits: self.bits | mask } } fn contains(&self, item: usize) -> bool { (self.bits & (1 << item)) != 0 } fn shift_left_at(&self, index: usize) -> Self { let high_bits = (self.bits >> index) << (index + 1); let low_bits = self.bits & ((1 << index) - 1); BitSet { bits: high_bits | low_bits } } fn to_string(&self) -> String { format!("{:b}", self.bits) } } impl std::ops::BitAnd for BitSet { type Output = Self; fn bitand(self, rhs: Self) -> Self::Output { BitSet { bits: self.bits & rhs.bits } } } impl std::ops::BitOr for BitSet { type Output = Self; fn bitor(self, rhs: Self) -> Self::Output { BitSet { bits: self.bits | rhs.bits } } } fn generate(length: usize, runs: &[usize]) -> Vec { let mut list = Vec::new(); let initial = BitSet::empty(); let mut sums = vec![0; runs.len()]; for i in 1..runs.len() { sums[i] = sums[i - 1] + runs[i - 1] + 1; } let initial = runs.iter().enumerate() .fold(initial, |acc, (i, &run)| acc.add_range(sums[i], run)); let max = BitSet::empty().add(length); generate_recursive(&mut list, max, runs, &sums, initial, 0, 0); list } fn generate_recursive( result: &mut Vec, max: BitSet, runs: &[usize], sums: &[usize], mut current: BitSet, index: usize, mut shift: usize, ) { if index == runs.len() { result.push(current); return; } while current.value() < max.value() { generate_recursive(result, max, runs, sums, current, index + 1, shift); current = current.shift_left_at(sums[index] + shift); shift += 1; } } fn reduce(rows: &mut Vec>, columns: &mut Vec>) { let mut count = 1; while count > 0 { count = 0; // Check rows against columns for row_idx in 0..rows.len() { let all_on = rows[row_idx].iter().fold(rows[row_idx][0], |acc, &b| acc & b); let all_off = rows[row_idx].iter().fold(rows[row_idx][0], |acc, &b| acc | b); for col_idx in 0..columns.len() { // Remove column patterns where a cell should be on but isn't let before_len = columns[col_idx].len(); columns[col_idx].retain(|c| !(all_on.contains(col_idx) && !c.contains(row_idx))); count += before_len - columns[col_idx].len(); // Remove column patterns where a cell should be off but isn't let before_len = columns[col_idx].len(); columns[col_idx].retain(|c| !(!all_off.contains(col_idx) && c.contains(row_idx))); count += before_len - columns[col_idx].len(); } } // Check columns against rows for col_idx in 0..columns.len() { let all_on = columns[col_idx].iter().fold(columns[col_idx][0], |acc, &b| acc & b); let all_off = columns[col_idx].iter().fold(columns[col_idx][0], |acc, &b| acc | b); for row_idx in 0..rows.len() { // Remove row patterns where a cell should be on but isn't let before_len = rows[row_idx].len(); rows[row_idx].retain(|r| !(all_on.contains(row_idx) && !r.contains(col_idx))); count += before_len - rows[row_idx].len(); // Remove row patterns where a cell should be off but isn't let before_len = rows[row_idx].len(); rows[row_idx].retain(|r| !(!all_off.contains(row_idx) && r.contains(col_idx))); count += before_len - rows[row_idx].len(); } } } } fn solve(row_runs: &[Vec], column_runs: &[Vec]) { let column_len = column_runs.len(); let row_len = row_runs.len(); let mut rows: Vec> = row_runs.iter() .map(|row| generate(column_len, row)) .collect(); let mut columns: Vec> = column_runs.iter() .map(|column| generate(row_len, column)) .collect(); reduce(&mut rows, &mut columns); for row in rows { if row.len() != 1 { println!("{}", vec!['?'; column_len].into_iter().collect::().chars().intersperse(' ').collect::()); } else { let mut s = format!("{:0width$b}", row[0].value(), width = column_len) .replace('1', "#") .replace('0', "."); // Reverse the string let s: String = s.chars().rev().collect(); println!("{}", s.chars().intersperse(' ').collect::()); } } } fn parse_runs(input: &str) -> Vec> { input.split_whitespace() .map(|s| s.chars().map(|c| (c as u8 - b'A' + 1) as usize).collect()) .collect() } fn main() { let test_cases = [ ("C BA CB BB F AE F A B", "AB CA AE GA E C D C"), ("F CAC ACAC CN AAA AABB EBB EAA ECCC HCCC", "D D AE CD AE A DA BBB CC AAB BAA AAB DA AAB AAA BAB AAA CD BBA DA"), ("CA BDA ACC BD CCAC CBBAC BBBBB BAABAA ABAD AABB BBH BBBD ABBAAA CCEA AACAAB BCACC ACBH DCH ADBE ADBB DBE ECE DAA DB CC", "BC CAC CBAB BDD CDBDE BEBDF ADCDFA DCCFB DBCFC ABDBA BBF AAF BADB DBF AAAAD BDG CEF CBDB BBB FC"), ("E BCB BEA BH BEK AABAF ABAC BAA BFB OD JH BADCF Q Q R AN AAN EI H G", "E CB BAB AAA AAA AC BB ACC ACCA AGB AIA AJ AJ ACE AH BAF CAG DAG FAH FJ GJ ADK ABK BL CM") ]; for (row_letters, column_letters) in test_cases.iter() { let row_runs = parse_runs(row_letters); let column_runs = parse_runs(column_letters); solve(&row_runs, &column_runs); println!(); } } // Extension trait to add intersperse functionality trait Intersperse { fn intersperse(self, separator: char) -> InterspersedIter where Self: Sized + Iterator; } impl Intersperse for I where I: Iterator + Sized, { fn intersperse(self, separator: char) -> InterspersedIter { InterspersedIter { iter: self, separator, need_separator: false, } } } struct InterspersedIter { iter: I, separator: char, need_separator: bool, } impl Iterator for InterspersedIter where I: Iterator, { type Item = char; fn next(&mut self) -> Option { if self.need_separator { self.need_separator = false; return Some(self.separator); } match self.iter.next() { Some(val) => { self.need_separator = true; Some(val) } None => None, } } }