110 lines
2.6 KiB
Rust
110 lines
2.6 KiB
Rust
|
use itertools::Itertools;
|
||
|
use std::fs::File;
|
||
|
use std::io::{BufRead, BufReader, Lines};
|
||
|
|
||
|
// BOILERPLATE
|
||
|
type InputIter = Lines<BufReader<File>>;
|
||
|
|
||
|
fn get_input() -> InputIter {
|
||
|
let f = File::open("input").unwrap();
|
||
|
let br = BufReader::new(f);
|
||
|
br.lines()
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
println!("Problem 1 solution: {}", problem1(get_input()));
|
||
|
println!("Problem 2 solution: {}", problem2(get_input()));
|
||
|
}
|
||
|
|
||
|
// PARSE
|
||
|
|
||
|
#[derive(Debug)]
|
||
|
struct SpringRow {
|
||
|
springs: Vec<char>,
|
||
|
spans: Vec<usize>,
|
||
|
}
|
||
|
|
||
|
impl From<&str> for SpringRow {
|
||
|
fn from(s: &str) -> Self {
|
||
|
let (springs_s, spans_s) = s.split_once(' ').unwrap();
|
||
|
SpringRow {
|
||
|
springs: springs_s.chars().collect(),
|
||
|
spans: spans_s.split(',').map(|x| x.parse().unwrap()).collect(),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl SpringRow {
|
||
|
fn possible_arrangements(&self) -> u64 {
|
||
|
let mut permutations = vec![self.springs.clone()];
|
||
|
while let Some(cur) = permutations.iter().position(|perm| perm.contains(&'?')) {
|
||
|
let perm = permutations.remove(cur);
|
||
|
let rep_pos = perm.iter().position(|c| *c == '?').unwrap();
|
||
|
|
||
|
let mut new_elem = perm.clone();
|
||
|
|
||
|
new_elem[rep_pos] = '.';
|
||
|
permutations.push(new_elem.clone());
|
||
|
new_elem[rep_pos] = '#';
|
||
|
permutations.push(new_elem);
|
||
|
}
|
||
|
|
||
|
permutations
|
||
|
.iter()
|
||
|
.filter_map(|perm| {
|
||
|
let groups: Vec<usize> = perm
|
||
|
.iter()
|
||
|
.group_by(|c| **c == '#')
|
||
|
.into_iter()
|
||
|
.filter_map(|(key, group)| if key { Some(group.count()) } else { None })
|
||
|
.collect();
|
||
|
if groups == self.spans {
|
||
|
Some(())
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
})
|
||
|
.count() as u64
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// PROBLEM 1 solution
|
||
|
|
||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||
|
let rows: Vec<SpringRow> = input
|
||
|
.map(|row| SpringRow::from(row.unwrap().as_str()))
|
||
|
.collect();
|
||
|
|
||
|
rows.iter().map(|row| row.possible_arrangements()).sum()
|
||
|
}
|
||
|
|
||
|
// PROBLEM 2 solution
|
||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||
|
0
|
||
|
}
|
||
|
|
||
|
#[cfg(test)]
|
||
|
mod tests {
|
||
|
use crate::*;
|
||
|
use std::io::Cursor;
|
||
|
|
||
|
const EXAMPLE: &str = &"???.### 1,1,3
|
||
|
.??..??...?##. 1,1,3
|
||
|
?#?#?#?#?#?#?#? 1,3,1,6
|
||
|
????.#...#... 4,1,1
|
||
|
????.######..#####. 1,6,5
|
||
|
?###???????? 3,2,1";
|
||
|
|
||
|
#[test]
|
||
|
fn problem1_example() {
|
||
|
let c = Cursor::new(EXAMPLE);
|
||
|
assert_eq!(problem1(c.lines()), 21);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn problem2_example() {
|
||
|
let c = Cursor::new(EXAMPLE);
|
||
|
assert_eq!(problem2(c.lines()), 0);
|
||
|
}
|
||
|
}
|