advent-of-code/2021/day08/src/main.rs
2022-01-09 09:33:52 +01:00

233 lines
7.3 KiB
Rust

use std::collections::HashMap;
use std::collections::HashSet;
use std::io::stdin;
use std::io::BufRead;
const SEGMENTS: [char; 7] = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
fn main() {
println!("Hello, world!");
let arg = std::env::args().nth(1).unwrap_or("part2".to_string());
match arg.as_str() {
"part1" => part1(),
_ => part2(),
};
}
fn part1() {
println!("Part1");
let mut lines = Vec::new();
let mut cur_line = String::new();
for line in stdin().lock().lines() {
let line = line.unwrap().replace("_", "");
cur_line += &line;
let last_char = line.chars().rev().nth(0).unwrap();
let is_wrapping = last_char == '|';
if !is_wrapping {
lines.push(cur_line);
cur_line = String::new()
} else {
cur_line.push(' ');
}
}
dbg!(&lines);
let mut count = 0;
let interesting_lengths = HashSet::from([2, 3, 4, 7]);
for line in lines {
let second_part = line.split('|').nth(1).unwrap();
let count_interesting = second_part
.split_whitespace()
.filter(|s| interesting_lengths.contains(&s.len()))
.count();
count += count_interesting;
dbg!(second_part);
dbg!(count_interesting);
}
dbg!(count);
}
fn part2() {
println!("Part2");
let mut lines = Vec::new();
let mut cur_line = String::new();
for line in stdin().lock().lines() {
let line = line.unwrap().replace("_", "");
cur_line += &line;
let last_char = line.chars().rev().nth(0).unwrap();
let is_wrapping = last_char == '|';
if !is_wrapping {
lines.push(cur_line);
cur_line = String::new()
} else {
cur_line.push(' ');
}
}
dbg!(&lines);
let sum: i32 = lines.iter().map(|l| identify_numbers(l)).sum();
dbg!(sum);
}
fn identify_numbers(line: &str) -> i32 {
let mut number_map = HashMap::new();
number_map.insert("abcefg".to_string(), 0);
number_map.insert("cf".to_string(), 1);
number_map.insert("acdeg".to_string(), 2);
number_map.insert("acdfg".to_string(), 3);
number_map.insert("bcdf".to_string(), 4);
number_map.insert("abdfg".to_string(), 5);
number_map.insert("abdefg".to_string(), 6);
number_map.insert("acf".to_string(), 7);
number_map.insert("abcdefg".to_string(), 8);
number_map.insert("abcdfg".to_string(), 9);
let mut possibilities = HashMap::new();
for segment in SEGMENTS {
possibilities.insert(segment, HashSet::from(SEGMENTS));
}
let words: Vec<String> = line
.split(&[' ', '|'][..])
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect();
let mut word_cycle = words.iter().cycle();
let mut last_hint = 0;
let mut unclear: usize = possibilities.values().map(|set| set.len()).sum();
while unclear > SEGMENTS.len() {
let word = &word_cycle.next().unwrap();
dbg!(word);
if word.len() == 2 {
let should_be = HashSet::from(['c', 'f']);
let should_not_be = &HashSet::from(SEGMENTS) - &should_be;
let word_chars: HashSet<char> = word.chars().collect();
let word_inverse = &HashSet::from(SEGMENTS) - &word_chars;
for a in word_chars {
for b in &should_not_be {
possibilities.get_mut(&a).unwrap().remove(&b);
}
}
for a in word_inverse {
for b in &should_be {
possibilities.get_mut(&a).unwrap().remove(&b);
}
}
}
if word.len() == 3 {
let should_be = HashSet::from(['a', 'c', 'f']);
let should_not_be = &HashSet::from(SEGMENTS) - &should_be;
let word_chars: HashSet<char> = word.chars().collect();
let word_inverse = &HashSet::from(SEGMENTS) - &word_chars;
for a in word_chars {
for b in &should_not_be {
possibilities.get_mut(&a).unwrap().remove(&b);
}
}
for a in word_inverse {
for b in &should_be {
possibilities.get_mut(&a).unwrap().remove(&b);
}
}
}
if word.len() == 4 {
let should_be = HashSet::from(['b', 'c', 'd', 'f']);
let should_not_be = &HashSet::from(SEGMENTS) - &should_be;
let word_chars: HashSet<char> = word.chars().collect();
let word_inverse = &HashSet::from(SEGMENTS) - &word_chars;
for a in word_chars {
for b in &should_not_be {
possibilities.get_mut(&a).unwrap().remove(&b);
}
}
for a in word_inverse {
for b in &should_be {
possibilities.get_mut(&a).unwrap().remove(&b);
}
}
}
if word.len() == 5 {
let should_be = HashSet::from(['b', 'c', 'e', 'f']);
let should_not_be = &HashSet::from(SEGMENTS) - &should_be;
let word_chars: HashSet<char> = word.chars().collect();
let word_inverse = &HashSet::from(SEGMENTS) - &word_chars;
for a in word_inverse {
for b in &should_not_be {
possibilities.get_mut(&a).unwrap().remove(&b);
}
}
}
if word.len() == 6 {
let should_be = HashSet::from(['c', 'd', 'e']);
let should_not_be = &HashSet::from(SEGMENTS) - &should_be;
let word_chars: HashSet<char> = word.chars().collect();
let word_inverse = &HashSet::from(SEGMENTS) - &word_chars;
for a in word_inverse {
for b in &should_not_be {
possibilities.get_mut(&a).unwrap().remove(&b);
}
}
}
last_hint += 1;
let new_unclear = possibilities.values().map(|set| set.len()).sum();
if new_unclear < unclear {
last_hint = 0
}
let clear: HashSet<char> = possibilities
.values()
.filter(|set| set.len() == 1)
.fold(HashSet::<char>::new(), |acc, ele| {
acc.union(ele).copied().collect()
});
for val in possibilities.values_mut() {
if val.len() > 1 {
for c in &clear {
val.remove(&c);
}
}
}
unclear = new_unclear;
println!("{:?}", possibilities);
if last_hint > words.len() {
panic!("Loop detected. Cannot deduce segments");
}
}
println!("{:?}", possibilities);
let signal_map: HashMap<char, char> = possibilities
.iter()
.map(|(key, set)| (*key, *set.iter().next().unwrap()))
.collect();
println!("signal map: {:?}", signal_map);
let mut num = 0;
let mut multiplier = 1;
for word in words.iter().rev().take(4) {
let mut signal: Vec<char> = word.chars().map(|c| *signal_map.get(&c).unwrap()).collect();
signal.sort();
let signal: String = signal.iter().collect();
dbg!(&signal);
let digit = number_map.get(&signal).unwrap();
num += digit * multiplier;
multiplier *= 10;
dbg!(digit);
}
dbg!(num);
return num;
}