Compare commits
2 Commits
e3f0f932e4
...
a19a3258c2
Author | SHA1 | Date | |
---|---|---|---|
a19a3258c2 | |||
d3c11dcbed |
128
Cargo.lock
generated
128
Cargo.lock
generated
@ -10,12 +10,23 @@ dependencies = [
|
|||||||
"aoc-runner-derive",
|
"aoc-runner-derive",
|
||||||
"array2d",
|
"array2d",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"num",
|
||||||
"prev-iter",
|
"prev-iter",
|
||||||
|
"regex",
|
||||||
"rust-crypto",
|
"rust-crypto",
|
||||||
"strum",
|
"strum",
|
||||||
"strum_macros",
|
"strum_macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aoc-runner"
|
name = "aoc-runner"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -51,6 +62,12 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d8b39cb2c1bf5a7c0dd097aa95ab859cf87dab5a4328900f5388942dc1889f74"
|
checksum = "d8b39cb2c1bf5a7c0dd097aa95ab859cf87dab5a4328900f5388942dc1889f74"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
@ -96,6 +113,88 @@ version = "0.2.151"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prev-iter"
|
name = "prev-iter"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@ -167,6 +266,35 @@ dependencies = [
|
|||||||
"rand_core 0.3.1",
|
"rand_core 0.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-crypto"
|
name = "rust-crypto"
|
||||||
version = "0.2.36"
|
version = "0.2.36"
|
||||||
|
@ -15,3 +15,5 @@ array2d = "0.3.0"
|
|||||||
strum = "0.25.0"
|
strum = "0.25.0"
|
||||||
strum_macros = "0.25"
|
strum_macros = "0.25"
|
||||||
prev-iter = "0.1.2"
|
prev-iter = "0.1.2"
|
||||||
|
regex = "1.10.2"
|
||||||
|
num = "0.4.1"
|
245
src/day19.rs
Normal file
245
src/day19.rs
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use regex::{Regex, Match};
|
||||||
|
|
||||||
|
enum Rule {
|
||||||
|
ACCEPTED,
|
||||||
|
REJECTED,
|
||||||
|
GOTO(String),
|
||||||
|
GT(String, usize, String),
|
||||||
|
LT(String, usize, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
#[aoc_generator(day19, part1)]
|
||||||
|
fn parse(input: &str) -> (HashMap<String, Vec<Rule>>, Vec<HashMap<String, usize>>) {
|
||||||
|
let (workflows_input, ratings_input) = input.split_once("\n\n").unwrap();
|
||||||
|
let workflows = parse_workflows(workflows_input);
|
||||||
|
|
||||||
|
// screw it im using regex
|
||||||
|
let rer = Regex::new(r"^\{x=(\d+),m=(\d+),a=(\d+),s=(\d+)\}$").unwrap();
|
||||||
|
let ratings: Vec<HashMap<String, usize>> = ratings_input.lines().map(|line| {
|
||||||
|
let caps = rer.captures(line).unwrap();
|
||||||
|
let x = parse_usize(caps.get(1));
|
||||||
|
let m = parse_usize(caps.get(2));
|
||||||
|
let a = parse_usize(caps.get(3));
|
||||||
|
let s = parse_usize(caps.get(4));
|
||||||
|
|
||||||
|
let mut vals = HashMap::new();
|
||||||
|
vals.insert("x".to_string(), x);
|
||||||
|
vals.insert("m".to_string(), m);
|
||||||
|
vals.insert("a".to_string(), a);
|
||||||
|
vals.insert("s".to_string(), s);
|
||||||
|
vals
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
(workflows, ratings)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_usize(g: Option<Match>) -> usize {
|
||||||
|
g.map_or(0, |m| m.as_str().parse().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_workflows(workflows_input: &str) -> HashMap<String, Vec<Rule>> {
|
||||||
|
let mut workflows: HashMap<String, Vec<Rule>> = HashMap::new();
|
||||||
|
let rew = Regex::new(r"^(.+)\{(.+)\}$").unwrap();
|
||||||
|
workflows_input.lines().for_each(|line| {
|
||||||
|
let caps = rew.captures(line).unwrap();
|
||||||
|
let key = caps.get(1).unwrap().as_str();
|
||||||
|
let rules_str = caps.get(2).unwrap().as_str();
|
||||||
|
|
||||||
|
let rules = rules_str.split(",").map(|expr| {
|
||||||
|
if expr == "A" {
|
||||||
|
return Rule::ACCEPTED;
|
||||||
|
}
|
||||||
|
if expr == "R" {
|
||||||
|
return Rule::REJECTED;
|
||||||
|
}
|
||||||
|
if !expr.contains(":") {
|
||||||
|
return Rule::GOTO(expr.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let (rule, to) = expr.split_once(":").unwrap();
|
||||||
|
|
||||||
|
return if rule.contains(">") {
|
||||||
|
let (prop, val) = rule.split_once(">").unwrap();
|
||||||
|
Rule::GT(prop.to_string(), val.parse().unwrap(), to.to_string())
|
||||||
|
} else if rule.contains("<") {
|
||||||
|
let (prop, val) = rule.split_once("<").unwrap();
|
||||||
|
Rule::LT(prop.to_string(), val.parse().unwrap(), to.to_string())
|
||||||
|
} else {
|
||||||
|
panic!("Unknown rule {}", rule)
|
||||||
|
};
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
workflows.insert(key.to_string(), rules);
|
||||||
|
});
|
||||||
|
workflows
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day19, part1)]
|
||||||
|
fn part1((workflows, ratings): &(HashMap<String, Vec<Rule>>, Vec<HashMap<String, usize>>)) -> usize {
|
||||||
|
let mut accepted: Vec<HashMap<String, usize>> = vec!();
|
||||||
|
'outer: for rating in ratings {
|
||||||
|
let mut wf_key = "in";
|
||||||
|
'middle: loop {
|
||||||
|
if wf_key == "A" {
|
||||||
|
accepted.push(rating.clone());
|
||||||
|
continue 'outer;
|
||||||
|
} else if wf_key == "R" {
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rules = workflows.get(wf_key).unwrap();
|
||||||
|
for rule in rules {
|
||||||
|
match rule {
|
||||||
|
Rule::ACCEPTED => {
|
||||||
|
accepted.push(rating.clone());
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
Rule::REJECTED => {
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
Rule::GOTO(new_wf_key) => {
|
||||||
|
wf_key = new_wf_key;
|
||||||
|
continue 'middle;
|
||||||
|
}
|
||||||
|
Rule::GT(prop, val, to) => {
|
||||||
|
if rating.get(prop.as_str()).unwrap() > val {
|
||||||
|
wf_key = to;
|
||||||
|
continue 'middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::LT(prop, val, to) => {
|
||||||
|
if rating.get(prop.as_str()).unwrap() < val {
|
||||||
|
wf_key = to;
|
||||||
|
continue 'middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accepted.iter().map(|rating| rating.values().sum::<usize>()).sum::<usize>()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[aoc_generator(day19, part2)]
|
||||||
|
fn parse_part2(input: &str) -> HashMap<String, Vec<Rule>> {
|
||||||
|
let (workflows_input, _) = input.split_once("\n\n").unwrap();
|
||||||
|
parse_workflows(workflows_input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day19, part2)]
|
||||||
|
fn part2(workflows: &HashMap<String, Vec<Rule>>) -> usize {
|
||||||
|
let mut stack: Vec<((usize, usize), (usize, usize), (usize, usize), (usize, usize), &str, usize)> =
|
||||||
|
vec! {((1, 4000), (1, 4000), (1, 4000), (1, 4000), "in", 0)};
|
||||||
|
let mut accepted: Vec<((usize, usize), (usize, usize), (usize, usize), (usize, usize))> = vec!();
|
||||||
|
while let Some(range) = stack.pop() {
|
||||||
|
let (x, m, a, s, wf_key, rule_key) = range;
|
||||||
|
if wf_key == "A" {
|
||||||
|
accepted.push((x, m, a, s));
|
||||||
|
continue;
|
||||||
|
} else if wf_key == "R" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if x.0 > x.1 || m.0 > m.1 || a.0 > a.1 || s.0 > s.1 { continue }
|
||||||
|
|
||||||
|
let rules = workflows.get(wf_key).unwrap();
|
||||||
|
let rule = &rules[rule_key];
|
||||||
|
match rule {
|
||||||
|
Rule::ACCEPTED => {
|
||||||
|
accepted.push((x, m, a, s));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Rule::REJECTED => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Rule::GOTO(new_wf_key) => {
|
||||||
|
stack.push((x, m, a, s, new_wf_key, 0));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Rule::GT(prop, val, to) => {
|
||||||
|
match prop.as_str() {
|
||||||
|
"x" => {
|
||||||
|
stack.push(((val + 1, x.1), m, a, s, to.as_str(), 0));
|
||||||
|
stack.push(((x.0, *val), m, a, s, wf_key, rule_key + 1));
|
||||||
|
}
|
||||||
|
"m" => {
|
||||||
|
stack.push((x, (val + 1, m.1), a, s, to.as_str(), 0));
|
||||||
|
stack.push((x, (m.0, *val), a, s, wf_key, rule_key + 1));
|
||||||
|
}
|
||||||
|
"a" => {
|
||||||
|
stack.push((x, m, (val + 1, a.1), s, to.as_str(), 0));
|
||||||
|
stack.push((x, m, (a.0, *val), s, wf_key, rule_key + 1));
|
||||||
|
}
|
||||||
|
"s" => {
|
||||||
|
stack.push((x, m, a, (val + 1, s.1), to.as_str(), 0));
|
||||||
|
stack.push((x, m, a, (s.0, *val), wf_key, rule_key + 1));
|
||||||
|
}
|
||||||
|
_ => { panic!("unknown prop {}", prop) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::LT(prop, val, to) => {
|
||||||
|
match prop.as_str() {
|
||||||
|
"x" => {
|
||||||
|
stack.push(((x.0, val - 1), m, a, s, to.as_str(), 0));
|
||||||
|
stack.push(((*val, x.1), m, a, s, wf_key, rule_key + 1));
|
||||||
|
}
|
||||||
|
"m" => {
|
||||||
|
stack.push((x, (m.0, val - 1), a, s, to.as_str(), 0));
|
||||||
|
stack.push((x, (*val, m.1), a, s, wf_key, rule_key + 1));
|
||||||
|
}
|
||||||
|
"a" => {
|
||||||
|
stack.push((x, m, (a.0, val - 1), s, to.as_str(), 0));
|
||||||
|
stack.push((x, m, (*val, a.1), s, wf_key, rule_key + 1));
|
||||||
|
}
|
||||||
|
"s" => {
|
||||||
|
stack.push((x, m, a, (s.0, val - 1), to.as_str(), 0));
|
||||||
|
stack.push((x, m, a, (*val, s.1), wf_key, rule_key + 1));
|
||||||
|
}
|
||||||
|
_ => { panic!("unknown prop {}", prop) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accepted.iter().map(|(x, m, a, s)| {
|
||||||
|
(x.1 - x.0 + 1) * (m.1 - m.0 + 1) * (a.1 - a.0 + 1) * (s.1 - s.0 + 1)
|
||||||
|
}).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const EX: &str = r"px{a<2006:qkq,m>2090:A,rfg}
|
||||||
|
pv{a>1716:R,A}
|
||||||
|
lnx{m>1548:A,A}
|
||||||
|
rfg{s<537:gd,x>2440:R,A}
|
||||||
|
qs{s>3448:A,lnx}
|
||||||
|
qkq{x<1416:A,crn}
|
||||||
|
crn{x>2662:A,R}
|
||||||
|
in{s<1351:px,qqz}
|
||||||
|
qqz{s>2770:qs,m<1801:hdj,R}
|
||||||
|
gd{a>3333:R,R}
|
||||||
|
hdj{m>838:A,pv}
|
||||||
|
|
||||||
|
{x=787,m=2655,a=1222,s=2876}
|
||||||
|
{x=1679,m=44,a=2067,s=496}
|
||||||
|
{x=2036,m=264,a=79,s=2244}
|
||||||
|
{x=2461,m=1339,a=466,s=291}
|
||||||
|
{x=2127,m=1623,a=2188,s=1013}";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(part1(&parse(EX)), 19114);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(part2(&parse_part2(EX)), 167409079868000);
|
||||||
|
}
|
||||||
|
}
|
220
src/day20.rs
Normal file
220
src/day20.rs
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use num::Integer;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum Module {
|
||||||
|
FlipFlop { state: bool, dests: Vec<String> },
|
||||||
|
Conjunction { state: HashMap<String, bool>, dests: Vec<String> },
|
||||||
|
Broadcast { dests: Vec<String> },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc_generator(day20)]
|
||||||
|
fn parse(input: &str) -> HashMap<String, Module> {
|
||||||
|
let mut input: HashMap<_, _> = input.lines().map(|line| {
|
||||||
|
let (name, dests) = line.split_once("->").unwrap();
|
||||||
|
let dests = parse_destinations(dests);
|
||||||
|
let module = parse_module(name.trim(), dests);
|
||||||
|
(name.trim_matches(['&', '%', ' '].as_slice()).to_string(), module)
|
||||||
|
}).collect();
|
||||||
|
collect_inputs(&mut input);
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_module(name: &str, dests: Vec<String>) -> Module {
|
||||||
|
match name {
|
||||||
|
"broadcaster" => Module::Broadcast { dests },
|
||||||
|
name if name.starts_with('%') => Module::FlipFlop { state: false, dests },
|
||||||
|
name if name.starts_with('&') => Module::Conjunction { state: HashMap::new(), dests },
|
||||||
|
_ => panic!("Invalid Module {}", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_inputs(modules: &mut HashMap<String, Module>) {
|
||||||
|
for (name, module) in modules.clone() {
|
||||||
|
let dests = match module {
|
||||||
|
Module::FlipFlop { state: _, dests: dest } => dest,
|
||||||
|
Module::Conjunction { state: _, dests: dest } => dest,
|
||||||
|
Module::Broadcast { dests: dest } => dest,
|
||||||
|
};
|
||||||
|
|
||||||
|
for dest_name in dests {
|
||||||
|
if let Some(dest_mod) = modules.get_mut(&dest_name) {
|
||||||
|
match dest_mod {
|
||||||
|
Module::Conjunction { state, dests: _ } => state.insert(name.to_string(), false),
|
||||||
|
_ => continue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_destinations(dests: &str) -> Vec<String> {
|
||||||
|
dests.split(',')
|
||||||
|
.map(|x| x.trim().to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day20, part1)]
|
||||||
|
fn part1(modules: &HashMap<String, Module>) -> usize {
|
||||||
|
let mut modules = modules.clone();
|
||||||
|
let mut high: usize = 0;
|
||||||
|
let mut low: usize = 0;
|
||||||
|
for _ in 0..1000 {
|
||||||
|
let (high_pulses, low_pulses) = push_the_button(&mut modules);
|
||||||
|
high += high_pulses;
|
||||||
|
low += low_pulses;
|
||||||
|
}
|
||||||
|
|
||||||
|
high * low
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_the_button(modules: &mut HashMap<String, Module>) -> (usize, usize) {
|
||||||
|
let mut process_queue: VecDeque<(String, bool, String)> = VecDeque::new();
|
||||||
|
process_queue.push_back(("broadcaster".to_string(), false, "".to_string()));
|
||||||
|
let mut low_pulses: usize = 0;
|
||||||
|
let mut high_pulses: usize = 0;
|
||||||
|
|
||||||
|
while let Some((module_name, input, sender)) = process_queue.pop_front() {
|
||||||
|
match input {
|
||||||
|
true => high_pulses += 1,
|
||||||
|
false => low_pulses += 1,
|
||||||
|
}
|
||||||
|
if let Some(module) = modules.get_mut(&module_name) {
|
||||||
|
match module {
|
||||||
|
Module::FlipFlop { state, dests } => {
|
||||||
|
if !input {
|
||||||
|
let flipped = !(*state);
|
||||||
|
*state = flipped;
|
||||||
|
for dest in dests {
|
||||||
|
process_queue.push_back((dest.clone(), state.clone(), module_name.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Module::Conjunction { state, dests } => {
|
||||||
|
let stored = state.get_mut(&sender.to_string()).unwrap();
|
||||||
|
*stored = input;
|
||||||
|
|
||||||
|
let mut send = true;
|
||||||
|
if state.values().all(|x| *x) {
|
||||||
|
send = false;
|
||||||
|
}
|
||||||
|
for dest in dests {
|
||||||
|
process_queue.push_back((dest.clone(), send, module_name.clone()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Module::Broadcast { dests } => {
|
||||||
|
for dest in dests {
|
||||||
|
process_queue.push_back((dest.clone(), input, module_name.clone()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (high_pulses, low_pulses)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day20, part2)]
|
||||||
|
fn part2(og_modules: &HashMap<String, Module>) -> usize {
|
||||||
|
let mut lcm = vec![];
|
||||||
|
let before = ["tr", "xm", "dr", "nh"];
|
||||||
|
|
||||||
|
for module_name in before {
|
||||||
|
let mut modules = og_modules.clone();
|
||||||
|
let mut count: usize = 1;
|
||||||
|
while !push_the_button_part2(&mut modules, module_name.to_string()) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
lcm.push(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{:?}", lcm);
|
||||||
|
|
||||||
|
let lcm = lcm.iter()
|
||||||
|
.cloned()
|
||||||
|
.reduce(|a, b| a.lcm(&b))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
lcm
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_the_button_part2(modules: &mut HashMap<String, Module>, to_find: String) -> bool {
|
||||||
|
let mut process_queue: VecDeque<(String, bool, String)> = VecDeque::new();
|
||||||
|
process_queue.push_back(("broadcaster".to_string(), false, "".to_string()));
|
||||||
|
|
||||||
|
while let Some((module_name, input, sender)) = process_queue.pop_front() {
|
||||||
|
if module_name == to_find && input == false {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if let Some(module) = modules.get_mut(&module_name) {
|
||||||
|
match module {
|
||||||
|
Module::FlipFlop { state, dests } => {
|
||||||
|
if !input {
|
||||||
|
let flipped = !(*state);
|
||||||
|
*state = flipped;
|
||||||
|
for dest in dests {
|
||||||
|
process_queue.push_back((dest.clone(), state.clone(), module_name.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Module::Conjunction { state, dests } => {
|
||||||
|
let stored = state.get_mut(&sender.to_string()).unwrap();
|
||||||
|
*stored = input;
|
||||||
|
|
||||||
|
let mut send = true;
|
||||||
|
if state.values().all(|x| *x) {
|
||||||
|
send = false;
|
||||||
|
}
|
||||||
|
for dest in dests {
|
||||||
|
process_queue.push_back((dest.clone(), send, module_name.clone()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Module::Broadcast { dests } => {
|
||||||
|
for dest in dests {
|
||||||
|
process_queue.push_back((dest.clone(), input, module_name.clone()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const EX_1: &str = r"broadcaster -> a, b, c
|
||||||
|
%a -> b
|
||||||
|
%b -> c
|
||||||
|
%c -> inv
|
||||||
|
&inv -> a";
|
||||||
|
|
||||||
|
const EX_2: &str = r"broadcaster -> a
|
||||||
|
%a -> inv, con
|
||||||
|
&inv -> b
|
||||||
|
%b -> con
|
||||||
|
&con -> rx";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example1() {
|
||||||
|
assert_eq!(part1(&parse(EX_1)), 32000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example2() {
|
||||||
|
assert_eq!(part1(&parse(EX_2)), 11687500);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(part2(&parse(EX_2)), 1);
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
mod day20;
|
||||||
|
mod day19;
|
||||||
mod day18;
|
mod day18;
|
||||||
mod day17;
|
mod day17;
|
||||||
mod day16;
|
mod day16;
|
||||||
|
Loading…
Reference in New Issue
Block a user