solution: day7

This commit is contained in:
Matej Janezic 2022-12-04 02:16:49 +01:00
parent 0000014030
commit 00000150f0
Signed by: janezicmatej
GPG Key ID: 4298E230ED37B2C0
2 changed files with 197 additions and 0 deletions

187
src/bin/07.rs Normal file
View File

@ -0,0 +1,187 @@
use hashbrown::{HashMap, HashSet};
use itertools::Itertools;
use lazy_static::lazy_static;
use regex::Regex;
use Gate::*;
use Operand::*;
#[derive(Debug, Eq, PartialEq, Hash)]
enum Operand {
Address(String),
Literal(u16),
}
impl Operand {
fn get(&self, map: &HashMap<String, u16>) -> u16 {
match self {
Address(x) => *map.get(x).unwrap(),
Literal(x) => *x,
}
}
}
impl From<&str> for Operand {
fn from(value: &str) -> Self {
match value.parse() {
Ok(x) => Literal(x),
Err(_) => Address(value.to_string()),
}
}
}
#[derive(Debug, Eq, PartialEq, Hash)]
enum Gate {
Write(Operand, Operand),
And(Operand, Operand, Operand),
Or(Operand, Operand, Operand),
LShift(Operand, u8, Operand),
RShift(Operand, u8, Operand),
Not(Operand, Operand),
}
impl Gate {
fn can_evaluate(&self, map: &HashMap<String, u16>) -> bool {
match self {
Write(Address(x), _) => map.contains_key(x),
Not(Address(x), _) => map.contains_key(x),
LShift(Address(x), _, _) => map.contains_key(x),
RShift(Address(x), _, _) => map.contains_key(x),
And(x, y, _) | Or(x, y, _) => {
let mut allow = true;
if let Address(xx) = x {
allow &= map.contains_key(xx);
};
if let Address(yy) = y {
allow &= map.contains_key(yy);
};
allow
}
_ => true,
}
}
}
impl From<&str> for Gate {
fn from(value: &str) -> Self {
lazy_static! {
static ref RE_SIGNAL: Regex = Regex::new(r"^(\w*) -> (\w*)$").unwrap();
static ref RE_NOT: Regex = Regex::new(r"NOT (\w*) -> (\w*)").unwrap();
static ref RE_GATE: Regex =
Regex::new(r"^(\w*) (AND|OR|LSHIFT|RSHIFT) (\w*) -> (\w*)$").unwrap();
}
if let Some(cap) = RE_SIGNAL.captures(value) {
return Write(Operand::from(&cap[1]), Operand::from(&cap[2]));
};
if let Some(cap) = RE_NOT.captures(value) {
return Not(Operand::from(&cap[1]), Operand::from(&cap[2]));
};
if let Some(cap) = RE_GATE.captures(value) {
match &cap[2] {
"AND" => {
return And(
Operand::from(&cap[1]),
Operand::from(&cap[3]),
Operand::from(&cap[4]),
)
}
"OR" => {
return Or(
Operand::from(&cap[1]),
Operand::from(&cap[3]),
Operand::from(&cap[4]),
)
}
"LSHIFT" => {
return LShift(
Operand::from(&cap[1]),
cap[3].parse().unwrap(),
Operand::from(&cap[4]),
);
}
"RSHIFT" => {
return RShift(
Operand::from(&cap[1]),
cap[3].parse().unwrap(),
Operand::from(&cap[4]),
);
}
_ => unreachable!(),
}
};
unreachable!()
}
}
pub fn part_one(input: &str) -> Option<u32> {
let mut map: HashMap<String, u16> = HashMap::new();
let mut set: HashSet<Gate> = HashSet::new();
for line in input.trim().split('\n') {
set.insert(Gate::from(line));
}
while !set.is_empty() {
for gate in set.drain_filter(|x| x.can_evaluate(&map)).collect_vec() {
match gate {
Write(a, Address(b)) => map.insert(b.to_string(), a.get(&map)),
And(a, b, Address(c)) => map.insert(c.to_string(), a.get(&map) & b.get(&map)),
Or(a, b, Address(c)) => map.insert(c.to_string(), a.get(&map) | b.get(&map)),
LShift(a, b, Address(c)) => map.insert(c.to_string(), a.get(&map) << b),
RShift(a, b, Address(c)) => map.insert(c.to_string(), a.get(&map) >> b),
Not(a, Address(b)) => map.insert(b.to_string(), !a.get(&map)),
_ => unreachable!(),
};
}
}
Some(*map.get("a").unwrap() as u32)
}
pub fn part_two(input: &str) -> Option<u32> {
let mut map: HashMap<String, u16> = HashMap::new();
let mut set: HashSet<Gate> = HashSet::new();
for line in input.trim().split('\n') {
let g = Gate::from(line);
if let Write(a, Address(b)) = g {
if b == "b" {
map.insert("b".to_string(), 46065);
} else {
set.insert(Write(a, Address(b)));
}
} else {
set.insert(g);
}
}
while !set.is_empty() {
for gate in set.drain_filter(|x| x.can_evaluate(&map)).collect_vec() {
match gate {
Write(a, Address(b)) => map.insert(b.to_string(), a.get(&map)),
And(a, b, Address(c)) => map.insert(c.to_string(), a.get(&map) & b.get(&map)),
Or(a, b, Address(c)) => map.insert(c.to_string(), a.get(&map) | b.get(&map)),
LShift(a, b, Address(c)) => map.insert(c.to_string(), a.get(&map) << b),
RShift(a, b, Address(c)) => map.insert(c.to_string(), a.get(&map) >> b),
Not(a, Address(b)) => map.insert(b.to_string(), !a.get(&map)),
_ => unreachable!(),
};
}
}
Some(*map.get("a").unwrap() as u32)
}
fn main() {
let input = &aoc::read_file("inputs", 7);
aoc::solve!(1, part_one, input);
aoc::solve!(2, part_two, input);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
let input = aoc::read_file("test_inputs", 7);
assert_eq!(part_one(&input), Some(65533));
}
#[test]
fn test_part_two() {
let input = aoc::read_file("test_inputs", 7);
assert_eq!(part_two(&input), Some(19470));
}
}

10
src/test_inputs/07.txt Normal file
View File

@ -0,0 +1,10 @@
123 -> x
456 -> y
x AND y -> d
x OR y -> e
x LSHIFT 2 -> f
y RSHIFT 2 -> g
NOT x -> h
NOT y -> i
2 -> b
NOT b -> a