Compare commits
13 Commits
cdfecf821c
...
main
Author | SHA1 | Date | |
---|---|---|---|
48c96ce7ea
|
|||
342f4c1883
|
|||
881d0b08ad
|
|||
c1eb7761e3
|
|||
98456ed98d
|
|||
d6d4c0d056
|
|||
3bb3b3d6b6
|
|||
dd91259fe2
|
|||
8495969877
|
|||
190fc92842
|
|||
eb6c1f42cd
|
|||
512b05f624
|
|||
877101f9a2
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
**/target
|
**/target
|
||||||
|
input
|
||||||
|
201
20/Cargo.lock
generated
Normal file
201
20/Cargo.lock
generated
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day20"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"lazy-regex",
|
||||||
|
"num",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy-regex"
|
||||||
|
version = "3.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c"
|
||||||
|
dependencies = [
|
||||||
|
"lazy-regex-proc_macros",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy-regex-proc_macros"
|
||||||
|
version = "3.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.70"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
10
20/Cargo.toml
Normal file
10
20/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "day20"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
lazy-regex = "3.1.0"
|
||||||
|
num = "0.4.1"
|
58
20/input
Normal file
58
20/input
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
%hm -> cr
|
||||||
|
%qc -> nd
|
||||||
|
&dh -> rm
|
||||||
|
%ph -> zz
|
||||||
|
%ps -> kc, dt
|
||||||
|
%qb -> dt
|
||||||
|
%jl -> vt, tb
|
||||||
|
%fh -> dm, gr
|
||||||
|
broadcaster -> np, mg, vd, xr
|
||||||
|
%zz -> sq
|
||||||
|
&rm -> rx
|
||||||
|
%nd -> br
|
||||||
|
%nx -> vr, vt
|
||||||
|
%qf -> dt, dv
|
||||||
|
%np -> xm, ph
|
||||||
|
%dm -> nf, gr
|
||||||
|
%sq -> kj
|
||||||
|
%bv -> fp, xm
|
||||||
|
%br -> kt
|
||||||
|
%mg -> dz, gr
|
||||||
|
&dt -> vd, dv, dh, hm, ks, hd, kq
|
||||||
|
%ks -> qf
|
||||||
|
&qd -> rm
|
||||||
|
%xr -> vt, rn
|
||||||
|
%vr -> tg, vt
|
||||||
|
%lc -> xm
|
||||||
|
%tq -> gr, fh
|
||||||
|
%cr -> kq, dt
|
||||||
|
%vd -> dt, ks
|
||||||
|
%tb -> nx
|
||||||
|
%dz -> gr, fd
|
||||||
|
&gr -> dp, mg, fd, qn
|
||||||
|
%nf -> gr
|
||||||
|
%dv -> hm
|
||||||
|
%qj -> lc, xm
|
||||||
|
%kc -> dt, gf
|
||||||
|
%gf -> dt, qb
|
||||||
|
%vh -> xm, sv
|
||||||
|
%sr -> vt
|
||||||
|
%fp -> qg, xm
|
||||||
|
%kj -> vh
|
||||||
|
%pc -> tq, gr
|
||||||
|
%kq -> hd
|
||||||
|
%xd -> xg, gr
|
||||||
|
%tg -> sr, vt
|
||||||
|
&bb -> rm
|
||||||
|
%rn -> vt, qc
|
||||||
|
%hd -> ps
|
||||||
|
%qg -> xm, qj
|
||||||
|
&dp -> rm
|
||||||
|
%qn -> pc
|
||||||
|
%kt -> jl
|
||||||
|
%sv -> bv
|
||||||
|
&vt -> bb, nd, qc, xr, br, tb, kt
|
||||||
|
%fd -> mx
|
||||||
|
&xm -> zz, sv, sq, ph, kj, np, qd
|
||||||
|
%xg -> gr, qn
|
||||||
|
%mx -> gr, xd
|
362
20/src/main.rs
Normal file
362
20/src/main.rs
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
use std::collections::{BinaryHeap, HashMap, VecDeque};
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use lazy_regex::lazy_regex;
|
||||||
|
use num::integer::lcm;
|
||||||
|
|
||||||
|
// 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() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// PARSE
|
||||||
|
|
||||||
|
const MODULE_PATTERN: lazy_regex::Lazy<lazy_regex::Regex> = lazy_regex!("^([%&]?)([a-z]+) -> ([a-z, ]+)$");
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||||
|
enum PulseType {
|
||||||
|
Low,
|
||||||
|
High,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for PulseType {
|
||||||
|
fn from(value: bool) -> Self {
|
||||||
|
match value {
|
||||||
|
true => PulseType::High,
|
||||||
|
false => PulseType::Low,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PulseType> for bool {
|
||||||
|
fn from(value: PulseType) -> Self {
|
||||||
|
match value {
|
||||||
|
PulseType::High => true,
|
||||||
|
PulseType::Low => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for PulseType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
PulseType::Low => f.write_str("low"),
|
||||||
|
PulseType::High => f.write_str("high"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum ModuleKind {
|
||||||
|
FlipFlop,
|
||||||
|
Conjunction,
|
||||||
|
Broadcast,
|
||||||
|
Button,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Module {
|
||||||
|
name: String,
|
||||||
|
kind: Option<ModuleKind>,
|
||||||
|
inputs: Vec<String>,
|
||||||
|
outputs: Vec<String>,
|
||||||
|
on: bool,
|
||||||
|
last_input_states: Vec<PulseType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for Module {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
// the only states that change are 'on' and 'last_input_states', the rest are constant once created
|
||||||
|
self.on.hash(state);
|
||||||
|
self.last_input_states.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
fn new(name: String) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
kind: None,
|
||||||
|
inputs: Vec::new(),
|
||||||
|
outputs: Vec::new(),
|
||||||
|
on: false,
|
||||||
|
last_input_states: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn source_idx(&self, name: &str) -> usize {
|
||||||
|
self.inputs.iter().position(|in_name| in_name == name).unwrap()
|
||||||
|
}
|
||||||
|
fn with_kind(name: String, kind: ModuleKind) -> Self {
|
||||||
|
let mut m = Self::new(name);
|
||||||
|
m.kind = Some(kind);
|
||||||
|
m
|
||||||
|
}
|
||||||
|
fn and_destinations(mut self, destinations: &str) -> Self {
|
||||||
|
for dest in destinations.split(", ") {
|
||||||
|
self.outputs.push(dest.into());
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn and_source(mut self, source: String) -> Self {
|
||||||
|
self.add_source(source);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn add_source(&mut self, source: String) {
|
||||||
|
self.inputs.push(source);
|
||||||
|
self.last_input_states.push(PulseType::Low);
|
||||||
|
}
|
||||||
|
fn reset(&mut self) {
|
||||||
|
// relevant state is on and last_input_states
|
||||||
|
self.on = false;
|
||||||
|
for input in &mut self.last_input_states {
|
||||||
|
*input = PulseType::Low;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn state_space(&self) -> u128 {
|
||||||
|
match self.kind {
|
||||||
|
Some(ModuleKind::Broadcast) | Some(ModuleKind::Button) => 1,
|
||||||
|
Some(ModuleKind::FlipFlop) => 2,
|
||||||
|
Some(ModuleKind::Conjunction) => 1 << self.last_input_states.len(), // 2^n
|
||||||
|
None => 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Module {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
let Some(re_result) = MODULE_PATTERN.captures(s) else {
|
||||||
|
panic!("unparseable module: {}", s);
|
||||||
|
};
|
||||||
|
let (_, [kind, name, destinations]) = re_result.extract();
|
||||||
|
if name == "broadcaster" {
|
||||||
|
return Module::with_kind(name.into(), ModuleKind::Broadcast).and_destinations(destinations);
|
||||||
|
};
|
||||||
|
match kind {
|
||||||
|
"%" => Module::with_kind(name.into(), ModuleKind::FlipFlop).and_destinations(destinations),
|
||||||
|
"&" => Module::with_kind(name.into(), ModuleKind::Conjunction).and_destinations(destinations),
|
||||||
|
_ => panic!("invalid module kind {}", kind),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Job {
|
||||||
|
signal: PulseType,
|
||||||
|
targets: Vec<String>,
|
||||||
|
from: String,
|
||||||
|
priority: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Job {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.priority == other.priority
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Eq for Job {}
|
||||||
|
|
||||||
|
impl PartialOrd for Job {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
other.priority.partial_cmp(&self.priority)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Job {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.partial_cmp(other).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Machine {
|
||||||
|
modules: HashMap<String, Module>,
|
||||||
|
work_queue: BinaryHeap<Job>,
|
||||||
|
count_low: u64,
|
||||||
|
count_high: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for Machine {
|
||||||
|
fn from(mut lines: Lines<T>) -> Self {
|
||||||
|
let mut modules = HashMap::from([(
|
||||||
|
"button".into(),
|
||||||
|
Module::with_kind("button".into(), ModuleKind::Button).and_destinations("broadcaster"),
|
||||||
|
)]);
|
||||||
|
while let Some(Ok(line)) = lines.next() {
|
||||||
|
let mut module = Module::from(line.as_str());
|
||||||
|
for output in &module.outputs {
|
||||||
|
if let Some(output_mod) = modules.get_mut(output) {
|
||||||
|
// already exists, push to input list
|
||||||
|
output_mod.add_source(module.name.to_owned());
|
||||||
|
} else {
|
||||||
|
// forward declaration of 'unknown' modules
|
||||||
|
modules.insert(
|
||||||
|
output.clone(),
|
||||||
|
Module::new(output.clone()).and_source(module.name.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(existing_mod) = modules.get(&module.name) {
|
||||||
|
module.inputs = existing_mod.inputs.clone(); // might have been pre-prepared, the rest we take ours
|
||||||
|
module.last_input_states = existing_mod.last_input_states.clone();
|
||||||
|
}
|
||||||
|
modules.insert(module.name.clone(), module);
|
||||||
|
}
|
||||||
|
|
||||||
|
Machine {
|
||||||
|
modules,
|
||||||
|
work_queue: BinaryHeap::new(),
|
||||||
|
count_low: 0,
|
||||||
|
count_high: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Machine {
|
||||||
|
fn press_button(&mut self) {
|
||||||
|
self.send_pulse(PulseType::Low, "broadcaster", "button", 1);
|
||||||
|
}
|
||||||
|
fn send_pulse(&mut self, signal: PulseType, target: &str, from: &str, priority: usize) {
|
||||||
|
// count pulse when it is received
|
||||||
|
match signal {
|
||||||
|
PulseType::Low => self.count_low += 1,
|
||||||
|
PulseType::High => self.count_high += 1,
|
||||||
|
};
|
||||||
|
match self.modules[target].kind {
|
||||||
|
Some(ModuleKind::Button) | Some(ModuleKind::Broadcast) => {
|
||||||
|
self.send_all_outputs(PulseType::Low, target, priority)
|
||||||
|
}
|
||||||
|
Some(ModuleKind::FlipFlop) => match signal {
|
||||||
|
PulseType::High => (),
|
||||||
|
PulseType::Low => {
|
||||||
|
let new_state = !self.modules.get_mut(target).unwrap().on;
|
||||||
|
self.modules.get_mut(target).unwrap().on = new_state;
|
||||||
|
self.send_all_outputs(new_state.into(), target, priority)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(ModuleKind::Conjunction) => {
|
||||||
|
let target_m = self.modules.get_mut(target).unwrap();
|
||||||
|
let source_idx = target_m.source_idx(from);
|
||||||
|
target_m.last_input_states[source_idx] = signal;
|
||||||
|
if target_m.last_input_states.iter().all(|state| *state == PulseType::High) {
|
||||||
|
self.send_all_outputs(PulseType::Low, target, priority)
|
||||||
|
} else {
|
||||||
|
self.send_all_outputs(PulseType::High, target, priority)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn send_all_outputs(&mut self, signal: PulseType, from: &str, priority: usize) {
|
||||||
|
self.work_queue.push(Job {
|
||||||
|
signal,
|
||||||
|
targets: self.modules[from].outputs.iter().map(|op| op.to_owned()).collect(),
|
||||||
|
from: from.to_owned(),
|
||||||
|
priority: priority + 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn run(&mut self) {
|
||||||
|
while let Some(job) = self.work_queue.pop() {
|
||||||
|
for target in job.targets {
|
||||||
|
self.send_pulse(job.signal, &target, &job.from, job.priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the number of cycles it took until the target sends a low pulse, or None if the target node sent no low pulses but the job finished
|
||||||
|
fn time_to_state(&mut self, goal:&str, state: PulseType) -> Option<u64> {
|
||||||
|
while let Some(job) = self.work_queue.pop() {
|
||||||
|
if job.from == goal && job.signal == state {
|
||||||
|
return Some(self.count_high + self.count_low);
|
||||||
|
}
|
||||||
|
for target in job.targets {
|
||||||
|
self.send_pulse(job.signal, &target, &job.from, job.priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn reset(&mut self) {
|
||||||
|
for (_name, m) in &mut self.modules {
|
||||||
|
m.reset();
|
||||||
|
}
|
||||||
|
self.count_low = 0;
|
||||||
|
self.count_high = 0;
|
||||||
|
}
|
||||||
|
fn state_space(&self) -> u128 {
|
||||||
|
self.modules.values().map(|m| m.state_space()).product()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
const PROBLEM1_ITERATIONS: usize = 1000;
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let mut machine = Machine::from(input);
|
||||||
|
for _ in 0..PROBLEM1_ITERATIONS {
|
||||||
|
machine.press_button();
|
||||||
|
machine.run();
|
||||||
|
}
|
||||||
|
machine.count_low * machine.count_high
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u128 {
|
||||||
|
let mut machine = Machine::from(input);
|
||||||
|
println!("STATES: {}", machine.state_space());
|
||||||
|
// Find the rx module and look at its parent(s)
|
||||||
|
let rx = &machine.modules["rx"];
|
||||||
|
// my input has a single conjunction as parent, todo implement other possibilities
|
||||||
|
let con = &machine.modules[&rx.inputs[0]];
|
||||||
|
|
||||||
|
// for each input, find how long it takes for it to be High, so the conjunction sends a low to rx
|
||||||
|
let mut cycles: Vec<_> = Vec::new();
|
||||||
|
for input in con.inputs.clone() {
|
||||||
|
print!("searching distance to {}...", input);
|
||||||
|
machine.reset();
|
||||||
|
let mut button_count = 0;
|
||||||
|
loop {
|
||||||
|
machine.press_button();
|
||||||
|
button_count += 1;
|
||||||
|
if let Some(distance) = machine.time_to_state(&input, PulseType::High) {
|
||||||
|
println!("got {} pulses, {} button presses", distance, button_count);
|
||||||
|
cycles.push(button_count as u128);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cycles.iter().fold(1, |accum, cycle| lcm(accum, *cycle))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"broadcaster -> a
|
||||||
|
%a -> inv, con
|
||||||
|
&inv -> b
|
||||||
|
%b -> con
|
||||||
|
&con -> output";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1(c.lines()), 11687500);
|
||||||
|
}
|
||||||
|
}
|
465
21/Cargo.lock
generated
Normal file
465
21/Cargo.lock
generated
Normal file
@ -0,0 +1,465 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "approx"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytemuck"
|
||||||
|
version = "1.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "console"
|
||||||
|
version = "0.15.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
|
||||||
|
dependencies = [
|
||||||
|
"encode_unicode",
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"unicode-width",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"memoffset",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day21"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"indicatif",
|
||||||
|
"polyfit-rs",
|
||||||
|
"primes",
|
||||||
|
"rayon",
|
||||||
|
"test-case",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encode_unicode"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indicatif"
|
||||||
|
version = "0.17.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25"
|
||||||
|
dependencies = [
|
||||||
|
"console",
|
||||||
|
"instant",
|
||||||
|
"number_prefix",
|
||||||
|
"portable-atomic",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instant"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.151"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matrixmultiply"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nalgebra"
|
||||||
|
version = "0.31.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20bd243ab3dbb395b39ee730402d2e5405e448c75133ec49cc977762c4cba3d1"
|
||||||
|
dependencies = [
|
||||||
|
"approx",
|
||||||
|
"matrixmultiply",
|
||||||
|
"nalgebra-macros",
|
||||||
|
"num-complex",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
"simba",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nalgebra-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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-rational"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"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]]
|
||||||
|
name = "number_prefix"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "polyfit-rs"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab98d9704c7300e37472a6790a447eaf501d664a1889737faa53c26790d2b697"
|
||||||
|
dependencies = [
|
||||||
|
"nalgebra",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "portable-atomic"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "primes"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68a61082d8bceecd71a3870e9162002bb75f7ba9c7aa8b76227e887782fef9c8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.70"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rawpointer"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "safe_arch"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simba"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f3fd720c48c53cace224ae62bef1bbff363a70c68c4802a78b5cc6159618176"
|
||||||
|
dependencies = [
|
||||||
|
"approx",
|
||||||
|
"num-complex",
|
||||||
|
"num-traits",
|
||||||
|
"paste",
|
||||||
|
"wide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-case"
|
||||||
|
version = "3.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8"
|
||||||
|
dependencies = [
|
||||||
|
"test-case-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-case-core"
|
||||||
|
version = "3.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.42",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-case-macros"
|
||||||
|
version = "3.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.42",
|
||||||
|
"test-case-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wide"
|
||||||
|
version = "0.7.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c68938b57b33da363195412cfc5fc37c9ed49aa9cfe2156fde64b8d2c9498242"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"safe_arch",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.45.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
13
21/Cargo.toml
Normal file
13
21/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "day21"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
indicatif = "0.17.7"
|
||||||
|
polyfit-rs = "0.2.1"
|
||||||
|
primes = "0.3.0"
|
||||||
|
rayon = "1.8.0"
|
||||||
|
test-case = "3.3.1"
|
131
21/input
Normal file
131
21/input
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
...................................................................................................................................
|
||||||
|
..............#...#........#...............#.#.......#....##...........#.#..#......#.....#.........#..##...........................
|
||||||
|
.#..##..##..#......#.#.#...##......###...##......#.#..#...................#.....#..........#..#................#...#..........#....
|
||||||
|
.....................#..#.......#.....##.........#.......................................#........#....#.#..........#.#......#.#...
|
||||||
|
......##...#.....#.......#...#..###..........#..........#......................#........#.............#.....#........#....#........
|
||||||
|
.................##.................#...#.........#................................#........#...........#............#........#....
|
||||||
|
..............#.#....#........##.....##..........#.............##.............#...#......#..##..........#.........#.....#...#..#...
|
||||||
|
..#....#.......#...##..#......#.........#.#..#....#.#..............#........#...#...#...............#.#.....#..#..##......#...#....
|
||||||
|
...#......##...##..#...#..........#...#..........#..............#...#..........#..#..#..#........#.#.#.#.#...........###...........
|
||||||
|
.#.#.#...#.#...##............................................#......................#...#......#......##.#.........................
|
||||||
|
.##.#.........#...#..................##...........#............#..................###...#...........#.................#....#.......
|
||||||
|
.....................#...#.#................#................#.#........................#...#...##....##....#.#...#.........#...#..
|
||||||
|
...#.......#...#.........................#.#..................#........##..........................#......##....##............#....
|
||||||
|
......................#.....................#...............#.......#.#...................#...............#...#........#.##......#.
|
||||||
|
............................#..........................#........#....#.##..#.......#.##..#...#.#..#...............#.#..#....#......
|
||||||
|
.......................................................#.#..#.#....#......................#............#....#..#.......#.........#.
|
||||||
|
.....##........#...............#.......#...............#.#..........##..#...................#................#..#...#.#....#...###.
|
||||||
|
....#.....................##................#.......#.......#...#.#...#...............#................#...............##..........
|
||||||
|
....#........#..#.......#.#.#........................#.#...........#.......#..#.........#....#.......#........#.#.#................
|
||||||
|
......###.....#..#...........#.....#..#..#........#......#.#........###.....##............#..#...........#.........................
|
||||||
|
.....#...........#...................#..#..........#..#...###.#.........#.##...............#..##..........#.........#..............
|
||||||
|
.#.........#....#............#.##..........................##.....#........#....#.............#.......#...#..............##.#......
|
||||||
|
.#..#...#.......#...#.......##.......#.#.............................#...#...#.#...........#...#.................#.........#.#.#...
|
||||||
|
...#....................#.....##..............#.................#.................#............#......#....#.......#.........#.....
|
||||||
|
.......#...#.............#.##...#.#...................#.....#..#........#................................#.............#..#...##...
|
||||||
|
...#.###..............#....#........................#......#...#.........#......#.#....................#........#...#...#.......#..
|
||||||
|
............#.#...#...........................#....###.###...#........#..#........#...................##.....###......#........#...
|
||||||
|
.....#...#................#.##..##..................#....#.........#............##...................##................#.....#.....
|
||||||
|
.#....#..............##...#..................#......#..........##.#....#......##.#...............#....##..............#....#.......
|
||||||
|
....#.#.##...........##.....#...........#.........#...#........#..#.......#......#................#.#...#....#...#.................
|
||||||
|
.......#...#...#...#..#.......#..........#..................#..#........#..#.#.....#.#.....................##......................
|
||||||
|
.....##.........#.......##...#.............#.##.#.#...#.##.#...#......#...#....#.......#..#.........#...........#.##.###.#.....#...
|
||||||
|
...................#.#.......................#.....#.#......#.....##...#.#....#..#..........#...........#..##....#...#.......#.#...
|
||||||
|
.....#..#..#.........#...#.#.........#...#.#...##...#......##........#...............#.......#................#.....#...#.#........
|
||||||
|
........#.....###.....................#.........#.........#.........#....##............#..##.............#.........#..#.......#....
|
||||||
|
.#.........#....##..##.................#...#................................#...#.....#.........#.......#............#....#......#.
|
||||||
|
..#.........#.......#..................#..#.#...#........#.#.......#...##.#........#..........#.#..........#..#.....#.........#....
|
||||||
|
..#...............#...................##.#.......#...#..........#....................##.........#.................#..#......##..#..
|
||||||
|
.#........#.......#............##...........##........#.......................#................#....................#...###......#.
|
||||||
|
........###..........#..............#.............#..#.#.#............##...............#........#...#........#...................#.
|
||||||
|
...#............................#...##.##........#......#..#...................#.#.....#...#.##...............#........#...#.......
|
||||||
|
..#...##....................#.....##......#.......#..........#......#.........#...#..............#..............#..................
|
||||||
|
.....#..#....................#....###.....#..#.............#...#....#................#.....#.....................#........#........
|
||||||
|
.....#.#...#.....#..............##............#....##.#....#.#........##...........#....#.........................#....#......##...
|
||||||
|
....#..#.....##...........#.#.#.#............#....#.....#.........#........................##.......#.#..............##...#........
|
||||||
|
...............#..............#................................#....#........#.......#.......##......#.#............#......#....#..
|
||||||
|
.#......#....##........#.............#..#.#.............#...#..#.........#.........#................#..................#...........
|
||||||
|
.........#..............#....#......#.....##......#............#....#.........#....#...................#....#.........#......#..#..
|
||||||
|
..............................#....#.#........#.#.....#..#.................#....#...#..........#............##.......#.#.#....#....
|
||||||
|
.#..................#....#..#.......#.##..............#...#.......#................#...............................................
|
||||||
|
.#..##.........................#.....###......#....#......#.....#............#.#......##......##......##....#..........##.....#....
|
||||||
|
..........................##.#.....#..........................................#.#..#....#..#..................#...........#........
|
||||||
|
..##.....#.......#....#.........#..........#....................#.........#........###........................#..........#.........
|
||||||
|
.#.#...............#..........#.......#.....#....##.#..#.##...............#...#...#.#......#.......#.......#.#.............#....##.
|
||||||
|
..................#...............##.........##..#........#..#..........#.....................#............................#.......
|
||||||
|
.....#................#...##.......##.........#.....#.#....#.#........#...#..#....#..............#..#....#....#....#...............
|
||||||
|
..##.#........#...............#.#..#...................##...#......#.#...#..#.....##.................##...#.#...................#..
|
||||||
|
...#...............#......#.....#.......#......#.........#...#......#...#..#....#..#......#.......#.......#...#.##.#...........##..
|
||||||
|
..............##..........##..........#..##...............#...........##..#..#..#.#.......#...#.............#......................
|
||||||
|
..........#.#........................#...#.#..#.#...##..#.#.#.#.......#....#.#.#..............#...#...#........###..##...........#.
|
||||||
|
......................#...#.#..##.....#....#.....###.#..#.....#..........#........#...........##...#..#...........##..#............
|
||||||
|
..................................####.#..............#.................#........#.#............##......#.#..........#.............
|
||||||
|
..................#..........#.............................#...........#..#..#......#................#.......##...##..#............
|
||||||
|
....................#...#....#.#.#.##......#................#.................#...........#....#..........#....#...##.###..........
|
||||||
|
.................#.......#...#............###.###..#.......#......#.......#..##......#.#.....#.....................#...............
|
||||||
|
.................................................................S.................................................................
|
||||||
|
.......##...........#.........###.......#....###.#.#....#.#....#....#........#.......#...#...#.#.........#...................#.....
|
||||||
|
.......#...............#............#...#..#.......##...#...#.#............#.............#......##..........#..............#.......
|
||||||
|
.......##.........#.....................##...#...#.................#...#.......#..####......#.....#..............#..##.............
|
||||||
|
........#..#.............#.#..##..............#...#.............#.....#......#...#.#.......#...............##...##.................
|
||||||
|
.........#..#...#..#.#..#..#...................##......#.....#..#...##..............#......#..........#.##...#.#.##.#..............
|
||||||
|
..............#..........#....................................#.........#.......#..#............##................#................
|
||||||
|
...........#...#.....#.........#....#..###....#...#.......#....#...............##.....#.......#.#.....#.#....#.#..#................
|
||||||
|
..#...................#........###..............#.#................#...###...##.............#.###......#...#...#.....#..........#..
|
||||||
|
.#.#............#.....#....###......................................#..........................#..................#................
|
||||||
|
................#..#...#................#.................##.................##..........#.......#...#.............#...............
|
||||||
|
.....##...........#....#.......#......#.#.....#.....#................#.....#.........#..#.................#........#........#......
|
||||||
|
.#.#.............#..#.#..............#.....#..#.#.....#..#......#.........#.....#.#......#..#.......#.#......##............#..#....
|
||||||
|
...................#............#....#...........#........#...................#.....##..............#........###...............#...
|
||||||
|
......###..........###.#.......#.................................................#..#.........#.#...#.........#.#..........#.#.....
|
||||||
|
..#.................#..#..#...#............#...#...#..##.#....##..#..................##.....#......#.........................#...#.
|
||||||
|
......................#.#.....#.#...#.......##...........#...#....#.............#.......#.............#.#.#.#......................
|
||||||
|
......#..#.#..........#....#.........#......#................#.........##.#....#.......#........#.#....................#......#....
|
||||||
|
..#....#....#...............#..........#...#.#......#...................#.........#..#.#......#..#.........................##....#.
|
||||||
|
..............#..........##......#.##...#...#.#................#...#..#.......#.#.....#........#...###..##.........#..##.........#.
|
||||||
|
........##...........................##.......#.#..................#........#.......#.#........#.........................##....#...
|
||||||
|
..#.#...........#.......................#.#.....#....#.....#...............####...#..............#...#....................#.#......
|
||||||
|
.......#...#....#.#.......#####...##.....#.#.......#....#.#........#................................#.##..........##....#..#.......
|
||||||
|
.........#.....#................##.#..................#.....................#...#................#.###.#.......###....#............
|
||||||
|
............#.#....#........#....#..................#...##.............#............#.......#.....#..#............##...............
|
||||||
|
....#.....#..........#..............#...#...#........##.....#.#....#....#........##.............................#.#.......#........
|
||||||
|
..#..#.#.......#.................#................................#......##.#..#..............#.#................#...#.#...........
|
||||||
|
.....#.....#........................#..#................#......#.......#.........###.#.#.........#.........#.....#.......#.........
|
||||||
|
.......#.......................................#.......#...............#.#..###...#.#.##.......#...........#.#.....#.##........#...
|
||||||
|
......##.........#.................................#.........#........##.#................#.#...#.............#...#..#........#....
|
||||||
|
......#.....#.#.......#...........#..#...........#.........#..#.#.......#.........##.....#....#.#...............#...#...#....#...#.
|
||||||
|
..#...#.#....#....#..............................#..#...#.......#.#.#..##..................#...............#......#..###..#.#......
|
||||||
|
.....#...#..#......#.....##...............#..........#..#.#####.......#...........#...................#.....#...#.........#..#.#...
|
||||||
|
.................#.......#..................#........#.......##...##.#....#.#.............#.............#....#....#................
|
||||||
|
...........####..#.....#....#.............#.......#...#..#.....#.............#...#....#.............#.#....#.#.............#.......
|
||||||
|
...#..#..#...#...#.#.....#.......................#....#..###.###.....#.........#....................#....#..#............#.....#...
|
||||||
|
.#.##....##...#......#.#.....#......................#.##..................#........#..#................#.#.......#.............#...
|
||||||
|
....##........#.......#..#..#............#..#..#..#...#......###..#..#..#...##...............................#.#........#......#.#.
|
||||||
|
..#..#..........#..........#..#.#.............#.....#...........#.##.......#............................#...........#...#..........
|
||||||
|
..#.#..#...#....#.....#.....#...#................#.....#.....#....#..#...#..#....#....#.....................#....#.................
|
||||||
|
.......#........#...#.............#.................#...#.#.....#.#....#..........#......................#..#............#.........
|
||||||
|
....#........#........#..............#.........................#...................#..........#.........#..#.........#.............
|
||||||
|
................#........#.........#............................#.#.............#..##.......#......#..#.................#......#.#.
|
||||||
|
..#.....#.........#...#..#.#.........................#...#...#...........#.....#...........#........#.............#.....#........#.
|
||||||
|
....#...#....#......#....#...#..#.................#...##.....#.#............................##...#...#..##.#.....................#.
|
||||||
|
...#..##...............#............................#...........#......#.#.....#............#........#.##................#.........
|
||||||
|
................#..#.............#..#..............#.#....#...#.#...#...#.#.##.............................#..#...........#........
|
||||||
|
.......#.......#....###............#.#.#.....................#.#..#....#.................##.....#.#..........##..#......#..........
|
||||||
|
.......#..........##.#.......#.##...#...............##.....#..........#................#............#...#........#........#........
|
||||||
|
...###.#.............................#.....#.#............##..#...#.....###..........#...............................#.....#....#..
|
||||||
|
....###.#...#.......#.##........#......#..##.#..........#.#...#.#....#.#..............##....#..#...#...........#...#.#..#..........
|
||||||
|
.....#....#.#..##.....#..........#..#...##..............#.......#.......#.............#..#.....#.......#.....#...##...###.......#..
|
||||||
|
........##...#...##..#.#.....#..........................#.#.#..#..#...................#....#....#..#....#..........#....##.........
|
||||||
|
...........##.....#...#........##..#........#....#..........#..#...............................................#......#.#.......#..
|
||||||
|
...#..##.........##....#...........##...#.......##.........#........#...........#........#.#.##...........#....#.....###...#.......
|
||||||
|
...#...#........................#..#...#..#........................................#......#..#...#.#....#...........#..............
|
||||||
|
...#..#.......#..#......##...................#...............#.....#.#.............#.....#.........#.#..##.....#..........#..#.....
|
||||||
|
....###....#..#.....#.#........#.##.......##...#...............#...............###.###.#...#............##.....#.................#.
|
||||||
|
....#...#.........#.##............#.....#........#............................................##.#......#..##.........#....###..#..
|
||||||
|
............#...##..#..........#........#.......#.#..........................#..#.#.......#......#.......................##.#..#...
|
||||||
|
....#......#....#....#..#.....#........#......#....#..#.#..............................#..#....#............#....#.................
|
||||||
|
..#.............#...#......#...#.....................#.##...............................##...#.......#........................#.##.
|
||||||
|
....#....##........#..............#....#.......#.....................................#........#........#...##..........#...........
|
||||||
|
....#.#.##..#..#....................#.................#.##.............#....#....#.............###...#...#..##....#.....##.........
|
||||||
|
.............#.......#...............#........#.#.....#..#.#................#.....#..##.....#....#...............#....#......#...#.
|
||||||
|
...................................................................................................................................
|
230
21/src/main.rs
Normal file
230
21/src/main.rs
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
use core::panic;
|
||||||
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
|
use rayon::prelude::*;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// 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() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// PARSE
|
||||||
|
|
||||||
|
type Position = (isize, isize);
|
||||||
|
type WrappedPosition = (usize, usize);
|
||||||
|
type Offset = (isize, isize);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct MapTile {
|
||||||
|
c: char,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MapTile {
|
||||||
|
fn new(c: char) -> Self {
|
||||||
|
Self { c }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GardenMap {
|
||||||
|
map: Vec<Vec<MapTile>>,
|
||||||
|
start: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for GardenMap {
|
||||||
|
fn from(lines: Lines<T>) -> Self {
|
||||||
|
let map = lines
|
||||||
|
.map(|line| line.unwrap().chars().map(|c| MapTile::new(c)).collect())
|
||||||
|
.collect();
|
||||||
|
let mut new = Self { map, start: (0, 0) };
|
||||||
|
new.find_start();
|
||||||
|
new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ADJACENCIES: [Offset; 4] = [(-1, 0), (1, 0), (0, -1), (0, 1)];
|
||||||
|
|
||||||
|
impl GardenMap {
|
||||||
|
fn wrap_pos(&self, pos: &Position) -> WrappedPosition {
|
||||||
|
let (width, height) = (self.width() as isize, self.height() as isize);
|
||||||
|
(
|
||||||
|
if pos.0 < 0 {
|
||||||
|
(pos.0 + (-pos.0 / width + 1) * width) as usize % self.width()
|
||||||
|
} else {
|
||||||
|
pos.0 as usize % self.width()
|
||||||
|
},
|
||||||
|
if pos.1 < 0 {
|
||||||
|
(pos.1 + (-pos.1 / height + 1) * height) as usize % self.height()
|
||||||
|
} else {
|
||||||
|
pos.1 as usize % self.height()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn width(&self) -> usize {
|
||||||
|
self.map[0].len()
|
||||||
|
}
|
||||||
|
fn height(&self) -> usize {
|
||||||
|
self.map.len()
|
||||||
|
}
|
||||||
|
fn at(&self, pos: &Position) -> &MapTile {
|
||||||
|
let pos = self.wrap_pos(pos);
|
||||||
|
&self.map[pos.1][pos.0]
|
||||||
|
}
|
||||||
|
// return the valid 'moves' from pos
|
||||||
|
fn adjacent_to(&self, pos: &Position) -> Vec<Position> {
|
||||||
|
ADJACENCIES
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ofs| self.offset_pos(pos, ofs))
|
||||||
|
.filter(|pos| self.at(pos).c != '#')
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
fn offset_pos(&self, pos: &Position, ofs: &Offset) -> Option<Position> {
|
||||||
|
let new_pos = (pos.0 as isize + ofs.0, pos.1 as isize + ofs.1);
|
||||||
|
return Some((new_pos.0, new_pos.1));
|
||||||
|
}
|
||||||
|
fn find_start(&mut self) {
|
||||||
|
for (y, row) in self.map.iter().enumerate() {
|
||||||
|
for (x, tile) in row.iter().enumerate() {
|
||||||
|
if tile.c == 'S' {
|
||||||
|
self.start = (x as isize, y as isize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("didn't find the start square!");
|
||||||
|
}
|
||||||
|
fn reachable_after(&self, from: &Position, n: usize) -> u64 {
|
||||||
|
let bar = ProgressBar::new(n as u64).with_style(
|
||||||
|
ProgressStyle::with_template(
|
||||||
|
"[{elapsed_precise}/{eta_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {per_sec}",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
let mut visited_after: Vec<HashSet<Position>> = Vec::new();
|
||||||
|
visited_after.push(HashSet::from([*from]));
|
||||||
|
for i in 1..n+1 {
|
||||||
|
visited_after.push(
|
||||||
|
visited_after[i - 1]
|
||||||
|
.iter()
|
||||||
|
.flat_map(|last| self.adjacent_to(last))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
bar.inc(1);
|
||||||
|
// if primes::is_prime(i as u64) {
|
||||||
|
// println!("count after {} steps: {}", i, visited_after[i].len());
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
visited_after[n].len() as u64
|
||||||
|
}
|
||||||
|
fn reachable_count_after(&self, from: &Position, n: usize) -> u64 {
|
||||||
|
let dim = self.width() as f64;
|
||||||
|
let target_mod = (n % self.width()) as f64;
|
||||||
|
let x_values:Vec<f64> = vec![target_mod, target_mod + dim, target_mod + 2.*dim];
|
||||||
|
let y_values:Vec<f64> = x_values.iter().map(|n| self.reachable_after(from, *n as usize) as f64).collect();
|
||||||
|
|
||||||
|
let coeffs = polyfit_rs::polyfit_rs::polyfit(
|
||||||
|
&x_values,
|
||||||
|
&y_values,
|
||||||
|
2,
|
||||||
|
).unwrap();
|
||||||
|
println!("values: x: {:?} y: {:?}", x_values, y_values);
|
||||||
|
println!("coefficients: {:?}", coeffs);
|
||||||
|
|
||||||
|
let f_n= n as f64;
|
||||||
|
let result = coeffs[0] + coeffs[1] * f_n + coeffs[2] * f_n.powf(2.0);
|
||||||
|
|
||||||
|
result.round() as u64
|
||||||
|
}
|
||||||
|
fn draw_with_bounds(&self, from: &Position, to: &Position) {
|
||||||
|
for row in from.1..to.1 + 1 {
|
||||||
|
for col in from.0..to.0 + 1 {
|
||||||
|
print!("{}", self.at(&(col, row)).c);
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn print_visited(map: &GardenMap, visited: &Vec<Vec<bool>>) {
|
||||||
|
// for (y, row) in visited.iter().enumerate() {
|
||||||
|
// for (x, cell) in row.iter().enumerate() {
|
||||||
|
// print!("{}", if *cell { 'O' } else { map.at(&(x, y)).c });
|
||||||
|
// }
|
||||||
|
// println!();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1_impl<T: BufRead>(input: Lines<T>, n: usize) -> u64 {
|
||||||
|
let map = GardenMap::from(input);
|
||||||
|
// println!("map: {:?} start: {:?}", map.map, &map.start);
|
||||||
|
// map.draw_with_bounds(
|
||||||
|
// &(-(map.width() as isize), -(map.height() as isize)),
|
||||||
|
// &(map.width() as isize * 2 + 1, map.height() as isize * 2 + 1),
|
||||||
|
// );
|
||||||
|
map.reachable_count_after(&map.start, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
problem1_impl(input, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
problem1_impl(input, 26501365)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
use test_case::test_case;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"...........
|
||||||
|
.....###.#.
|
||||||
|
.###.##..#.
|
||||||
|
..#.#...#..
|
||||||
|
....#.#....
|
||||||
|
.##..S####.
|
||||||
|
.##..#...#.
|
||||||
|
.......##..
|
||||||
|
.##.#.####.
|
||||||
|
.##..##.##.
|
||||||
|
...........";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1_impl(c.lines(), 6), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case(6, 16)]
|
||||||
|
#[test_case(10, 50)]
|
||||||
|
#[test_case(50, 1594)]
|
||||||
|
#[test_case(100, 6536)]
|
||||||
|
#[test_case(500, 167004)]
|
||||||
|
fn problem2_example(n: usize, expect: u64) {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1_impl(c.lines(), n), expect);
|
||||||
|
}
|
||||||
|
}
|
128
22/Cargo.lock
generated
Normal file
128
22/Cargo.lock
generated
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day22"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"ndarray",
|
||||||
|
"petgraph",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matrixmultiply"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ndarray"
|
||||||
|
version = "0.15.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32"
|
||||||
|
dependencies = [
|
||||||
|
"matrixmultiply",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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-traits"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset",
|
||||||
|
"indexmap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rawpointer"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
11
22/Cargo.toml
Normal file
11
22/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "day22"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itertools = "0.12.0"
|
||||||
|
ndarray = "0.15.6"
|
||||||
|
petgraph = "0.6.4"
|
385
22/src/main.rs
Normal file
385
22/src/main.rs
Normal file
@ -0,0 +1,385 @@
|
|||||||
|
use itertools::Itertools;
|
||||||
|
use ndarray::prelude::*;
|
||||||
|
use petgraph::prelude::*;
|
||||||
|
use petgraph::visit::{IntoNodeReferences, Walker};
|
||||||
|
use std::collections::BinaryHeap;
|
||||||
|
use std::fmt::{Display, Write};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// 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() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// PARSE
|
||||||
|
|
||||||
|
#[derive(Hash, PartialEq, Eq, Clone, Debug)]
|
||||||
|
struct Coord {
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
z: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Coord {
|
||||||
|
type Err = Box<dyn std::error::Error>;
|
||||||
|
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
||||||
|
let (x, y, z) = value.split(',').next_tuple().unwrap();
|
||||||
|
Ok(Self {
|
||||||
|
x: x.parse()?,
|
||||||
|
y: y.parse()?,
|
||||||
|
z: z.parse()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||||
|
struct BrickBlock {
|
||||||
|
c1: Coord,
|
||||||
|
c2: Coord,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for BrickBlock {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"[{},{},{} - {},{},{}]",
|
||||||
|
self.c1.x, self.c1.y, self.c1.z, self.c2.x, self.c2.y, self.c2.z
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BrickBlock {
|
||||||
|
fn bottom_z_plane(&self) -> usize {
|
||||||
|
std::cmp::min(self.c1.z, self.c2.z)
|
||||||
|
}
|
||||||
|
fn top_z_plane(&self) -> usize {
|
||||||
|
std::cmp::max(self.c1.z, self.c2.z)
|
||||||
|
}
|
||||||
|
fn bottom_x_plane(&self) -> usize {
|
||||||
|
std::cmp::min(self.c1.x, self.c2.x)
|
||||||
|
}
|
||||||
|
fn top_x_plane(&self) -> usize {
|
||||||
|
std::cmp::max(self.c1.x, self.c2.x)
|
||||||
|
}
|
||||||
|
fn bottom_y_plane(&self) -> usize {
|
||||||
|
std::cmp::min(self.c1.y, self.c2.y)
|
||||||
|
}
|
||||||
|
fn top_y_plane(&self) -> usize {
|
||||||
|
std::cmp::max(self.c1.y, self.c2.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for BrickBlock {
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
let (c1, c2) = value.split_once('~').unwrap();
|
||||||
|
Self {
|
||||||
|
c1: c1.parse().unwrap(),
|
||||||
|
c2: c2.parse().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for BrickBlock {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(other.bottom_z_plane().cmp(&self.bottom_z_plane()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note this is a reversed ordering
|
||||||
|
impl Ord for BrickBlock {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.bottom_z_plane().cmp(&other.bottom_z_plane())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlockMap = Array3<MapTile>;
|
||||||
|
type MapTile = Option<BrickBlock>;
|
||||||
|
|
||||||
|
struct BlockPile {
|
||||||
|
blocks: Vec<BrickBlock>,
|
||||||
|
block_map: Array3<MapTile>,
|
||||||
|
bounds: (usize, usize, usize),
|
||||||
|
graph: Graph<BrickBlock, (), Directed, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockPile {
|
||||||
|
fn remove_block(&mut self, block: &BrickBlock) {
|
||||||
|
// loop over the (inclusive) bounding coordinates and remove them all from the map
|
||||||
|
self.block_map
|
||||||
|
.slice_mut(s![
|
||||||
|
block.bottom_x_plane()..block.top_x_plane() + 1,
|
||||||
|
block.bottom_y_plane()..block.top_y_plane() + 1,
|
||||||
|
block.bottom_z_plane()..block.top_z_plane() + 1,
|
||||||
|
])
|
||||||
|
.fill(None);
|
||||||
|
self.blocks.remove(self.blocks.iter().position(|b| b == block).unwrap());
|
||||||
|
}
|
||||||
|
fn add_block(&mut self, block: &BrickBlock) {
|
||||||
|
// loop over the (inclusive) bounding coordinates and remove them all from the map
|
||||||
|
self.block_map
|
||||||
|
.slice_mut(s![
|
||||||
|
block.bottom_x_plane()..block.top_x_plane() + 1,
|
||||||
|
block.bottom_y_plane()..block.top_y_plane() + 1,
|
||||||
|
block.bottom_z_plane()..block.top_z_plane() + 1,
|
||||||
|
])
|
||||||
|
.fill(Some(block.to_owned()));
|
||||||
|
self.blocks.push(block.clone());
|
||||||
|
}
|
||||||
|
fn blocks_directly_above(&self, block: &BrickBlock) -> Vec<BrickBlock> {
|
||||||
|
// find the top plane of the block
|
||||||
|
// get the array range of all squares at z_plane + 1 within the bounds of x & y
|
||||||
|
// i think there is a built in way in ndarray to do this...
|
||||||
|
let directly_above = self.block_map.slice(s![
|
||||||
|
block.bottom_x_plane()..block.top_x_plane() + 1,
|
||||||
|
block.bottom_y_plane()..block.top_y_plane() + 1,
|
||||||
|
block.top_z_plane() + 1..std::cmp::min(block.top_z_plane() + 2, self.bounds.2)
|
||||||
|
]);
|
||||||
|
|
||||||
|
directly_above.iter().filter_map(|v| v.clone()).unique().collect()
|
||||||
|
}
|
||||||
|
fn supported_by(&self, block: &BrickBlock) -> usize {
|
||||||
|
let z_plane = std::cmp::min(block.c1.z, block.c2.z);
|
||||||
|
// get the slice of tiles below us
|
||||||
|
let directly_below = self.block_map.slice(s![
|
||||||
|
block.bottom_x_plane()..block.top_x_plane() + 1,
|
||||||
|
block.bottom_y_plane()..block.top_y_plane() + 1,
|
||||||
|
z_plane - 1..z_plane // the layer below
|
||||||
|
]);
|
||||||
|
directly_below.iter().filter_map(|v| v.clone()).unique().count()
|
||||||
|
}
|
||||||
|
fn blocks_above_will_move_if_we_are_gone(&mut self, block: &BrickBlock) -> bool {
|
||||||
|
self.blocks_directly_above(&block)
|
||||||
|
.iter()
|
||||||
|
.map(|b| self.supported_by(b))
|
||||||
|
.any(|b| b == 1) // block we support will move if we are their only support
|
||||||
|
}
|
||||||
|
fn blocks_supported_by_at_all(&self, block: &BrickBlock) -> Vec<BrickBlock> {
|
||||||
|
self.blocks_directly_above(&block).iter().map(|b| b.clone()).collect()
|
||||||
|
}
|
||||||
|
/// Find the plane of the first block directly below us
|
||||||
|
fn supporting_plane(&self, block: &BrickBlock) -> Option<usize> {
|
||||||
|
// find the bottom plane of ourselves
|
||||||
|
let z_plane = std::cmp::min(block.c1.z, block.c2.z);
|
||||||
|
// get the slice of tiles below us
|
||||||
|
let directly_below = self.block_map.slice(s![
|
||||||
|
block.bottom_x_plane()..block.top_x_plane() + 1,
|
||||||
|
block.bottom_y_plane()..block.top_y_plane() + 1,
|
||||||
|
1..z_plane // don't include our own plane
|
||||||
|
]);
|
||||||
|
// find the highest top z value of those
|
||||||
|
let block_below = directly_below
|
||||||
|
.indexed_iter()
|
||||||
|
.filter_map(|(idx, v)| if let Some(val) = v { Some((idx, val)) } else { None })
|
||||||
|
.max_by_key(|(_idx, v)| v.top_z_plane());
|
||||||
|
|
||||||
|
if let Some(block) = block_below {
|
||||||
|
Some(block.1.top_z_plane())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drop_blocks(&mut self) {
|
||||||
|
// VecDeque doesn't sort and Vec isn't convenient for pushback and popfront, so eh... use a heap.
|
||||||
|
let mut blocks_to_move = BinaryHeap::from(self.blocks.clone());
|
||||||
|
while let Some(mut block) = blocks_to_move.pop() {
|
||||||
|
let z_move = match self.supporting_plane(&block) {
|
||||||
|
Some(z) if z + 1 != block.bottom_z_plane() => block.bottom_z_plane() - (z + 1),
|
||||||
|
None if block.bottom_z_plane() != 1 => block.bottom_z_plane() - 1,
|
||||||
|
_ => {
|
||||||
|
continue;
|
||||||
|
} // we are in position already with nothing below us
|
||||||
|
};
|
||||||
|
self.remove_block(&block);
|
||||||
|
block.c1.z -= z_move;
|
||||||
|
block.c2.z -= z_move;
|
||||||
|
self.add_block(&block);
|
||||||
|
blocks_to_move.push(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn build_graph(&mut self) {
|
||||||
|
self.blocks.sort_by_key(|b| b.bottom_z_plane());
|
||||||
|
for b in 0..self.blocks.len() {
|
||||||
|
self.graph.add_node(self.blocks[b].clone());
|
||||||
|
}
|
||||||
|
for b in 0..self.blocks.len() {
|
||||||
|
let block = &self.blocks[b];
|
||||||
|
let depends_on_us = self.blocks_supported_by_at_all(block);
|
||||||
|
for dependent in depends_on_us {
|
||||||
|
self.graph.add_edge(
|
||||||
|
b.into(),
|
||||||
|
self.blocks.iter().position(|b| b == &dependent).unwrap().into(),
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for BlockPile {
|
||||||
|
fn from(lines: Lines<T>) -> Self {
|
||||||
|
let blocks = lines.map(|line| BrickBlock::from(line.unwrap().as_str())).collect_vec();
|
||||||
|
let mut bounds = (0, 0, 0);
|
||||||
|
for block in &blocks {
|
||||||
|
bounds.0 = std::cmp::max(block.top_x_plane() + 1, bounds.0);
|
||||||
|
bounds.1 = std::cmp::max(block.top_y_plane() + 1, bounds.1);
|
||||||
|
bounds.2 = std::cmp::max(block.top_z_plane() + 1, bounds.2);
|
||||||
|
}
|
||||||
|
let mut new = BlockPile {
|
||||||
|
blocks: Vec::new(),
|
||||||
|
bounds,
|
||||||
|
block_map: BlockMap::from_elem(bounds, None),
|
||||||
|
graph: Graph::default(),
|
||||||
|
};
|
||||||
|
for block in blocks {
|
||||||
|
new.add_block(&block);
|
||||||
|
}
|
||||||
|
|
||||||
|
new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for BlockPile {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
for z in (0..self.bounds.2).rev() {
|
||||||
|
let z_plane = self.block_map.slice(s![.., .., z..z+1]);
|
||||||
|
if z_plane.iter().all(|b| b.is_none()) { continue };
|
||||||
|
for i in 0..self.bounds.0 {
|
||||||
|
// XZ view
|
||||||
|
let y = z_plane.slice(s![i..i + 1, .., ..]);
|
||||||
|
f.write_char(
|
||||||
|
match y.iter().enumerate().find_map(|(idx, val)| val.is_some().then(|| idx)) {
|
||||||
|
None => ' ',
|
||||||
|
Some(0) | Some(1) => '█',
|
||||||
|
Some(2) | Some(3) => '▓',
|
||||||
|
Some(4) | Some(5) => '▒',
|
||||||
|
Some(6) | Some(7) => '░',
|
||||||
|
_ => '░',
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
write!(f, " {} ", z)?;
|
||||||
|
for y in 0..self.bounds.1 {
|
||||||
|
let x = z_plane.slice(s![.., y..y + 1, ..]);
|
||||||
|
f.write_char(
|
||||||
|
match x.iter().enumerate().find_map(|(idx, val)| val.is_some().then(|| idx)) {
|
||||||
|
None => ' ',
|
||||||
|
Some(0) | Some(1) => '█',
|
||||||
|
Some(2) | Some(3) => '▓',
|
||||||
|
Some(4) | Some(5) => '▒',
|
||||||
|
Some(6) | Some(7) => '░',
|
||||||
|
_ => '░',
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
writeln!(f, " {}", z)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let mut pile = BlockPile::from(input);
|
||||||
|
println!("{}", pile);
|
||||||
|
println!("dropping blocks!");
|
||||||
|
pile.drop_blocks();
|
||||||
|
println!("{}", pile);
|
||||||
|
|
||||||
|
let blocks = pile.blocks.clone();
|
||||||
|
let removable: Vec<_> = blocks
|
||||||
|
.iter()
|
||||||
|
.filter(|b| !pile.blocks_above_will_move_if_we_are_gone(*b))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
removable.len() as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let mut pile = BlockPile::from(input);
|
||||||
|
pile.drop_blocks();
|
||||||
|
pile.build_graph();
|
||||||
|
|
||||||
|
println!("{}", pile);
|
||||||
|
|
||||||
|
let mut accum = 0;
|
||||||
|
let fixed_nodes = pile
|
||||||
|
.graph
|
||||||
|
.node_references()
|
||||||
|
.filter(|(_idx, b)| b.bottom_z_plane() == 1)
|
||||||
|
.map(|(idx, _b)| idx)
|
||||||
|
.collect_vec();
|
||||||
|
for node in pile.graph.node_indices() {
|
||||||
|
// remove links to node's neighbors
|
||||||
|
let dependents = pile.graph.neighbors(node).collect_vec();
|
||||||
|
let edges = pile.graph.edges(node).map(|v| v.id()).collect_vec();
|
||||||
|
for edge in edges {
|
||||||
|
pile.graph.remove_edge(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find how many nodes are reachable from z = 1 - these won't move
|
||||||
|
let safe_blocks = fixed_nodes
|
||||||
|
.iter()
|
||||||
|
.flat_map(|origin| {
|
||||||
|
Bfs::new(&pile.graph, *origin)
|
||||||
|
.iter(&pile.graph)
|
||||||
|
.map(|n| pile.graph[n].clone())
|
||||||
|
})
|
||||||
|
.unique()
|
||||||
|
.count();
|
||||||
|
// we are looking for the nodes that *will* disintegrate
|
||||||
|
accum += pile.graph.node_count() - safe_blocks;
|
||||||
|
// put the graph back how it was
|
||||||
|
for neigh in dependents {
|
||||||
|
pile.graph.add_edge(node, neigh, ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accum as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"1,0,1~1,2,1
|
||||||
|
0,0,2~2,0,2
|
||||||
|
0,2,3~2,2,3
|
||||||
|
0,0,4~0,2,4
|
||||||
|
2,0,5~2,2,5
|
||||||
|
0,1,6~2,1,6
|
||||||
|
1,1,8~1,1,9";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1(c.lines()), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem2_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem2(c.lines()), 7);
|
||||||
|
}
|
||||||
|
}
|
128
23/Cargo.lock
generated
Normal file
128
23/Cargo.lock
generated
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day23"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"ndarray",
|
||||||
|
"petgraph",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matrixmultiply"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ndarray"
|
||||||
|
version = "0.15.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32"
|
||||||
|
dependencies = [
|
||||||
|
"matrixmultiply",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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-traits"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset",
|
||||||
|
"indexmap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rawpointer"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
11
23/Cargo.toml
Normal file
11
23/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "day23"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itertools = "0.12.0"
|
||||||
|
ndarray = "0.15.6"
|
||||||
|
petgraph = "0.6.4"
|
326
23/src/main.rs
Normal file
326
23/src/main.rs
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
use itertools::Itertools;
|
||||||
|
use ndarray::prelude::*;
|
||||||
|
use petgraph::algo::all_simple_paths;
|
||||||
|
use petgraph::prelude::*;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::fmt::{Debug, Display, Write};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// 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() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// PARSE
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Node {
|
||||||
|
c: char,
|
||||||
|
pos: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Node {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "({},{})", self.pos.0, self.pos.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Node {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "({},{})", self.pos.0, self.pos.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Position = (usize, usize);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ForestMap {
|
||||||
|
map: Array2<char>,
|
||||||
|
indexes: HashMap<Position, NodeIndex>,
|
||||||
|
graph: StableDiGraph<Node, u64>,
|
||||||
|
start: Position,
|
||||||
|
end: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
const ADJACENCIES: [(isize, isize); 4] = [(-1, 0), (1, 0), (0, -1), (0, 1)];
|
||||||
|
|
||||||
|
fn offset_pos(map: &Array2<char>, pos: Position, ofs: (isize, isize)) -> Option<Position> {
|
||||||
|
let new_pos = (pos.0 as isize + ofs.0, pos.1 as isize + ofs.1);
|
||||||
|
if new_pos.0 >= 0
|
||||||
|
&& new_pos.0 < map.len_of(Axis(0)) as isize
|
||||||
|
&& new_pos.1 >= 0
|
||||||
|
&& new_pos.1 < map.len_of(Axis(1)) as isize
|
||||||
|
{
|
||||||
|
Some((new_pos.0 as usize, new_pos.1 as usize))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adjacent_to(map: &Array2<char>, pos: Position) -> Vec<Position> {
|
||||||
|
ADJACENCIES
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ofs| offset_pos(map, pos, *ofs))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for ForestMap {
|
||||||
|
fn from(lines: Lines<T>) -> Self {
|
||||||
|
let rows = lines.map(|line| line.unwrap().chars().collect_vec()).collect_vec();
|
||||||
|
let map = Array::from_shape_vec([rows[0].len(), rows.len()], rows.into_iter().flatten().collect_vec())
|
||||||
|
.unwrap()
|
||||||
|
.reversed_axes();
|
||||||
|
let start = (map.slice(s![.., 0]).iter().position(|c| *c == '.').unwrap(), 0);
|
||||||
|
let end = (
|
||||||
|
map.slice(s![.., map.len_of(Axis(1)) - 1])
|
||||||
|
.iter()
|
||||||
|
.position(|c| *c == '.')
|
||||||
|
.unwrap(),
|
||||||
|
map.len_of(Axis(1)) - 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut graph = StableGraph::default();
|
||||||
|
let mut indexes = HashMap::new();
|
||||||
|
for (pos, c) in map.indexed_iter() {
|
||||||
|
if *c != '#' {
|
||||||
|
indexes.insert(pos, graph.add_node(Node { c: *c, pos }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
map,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
graph,
|
||||||
|
indexes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ForestMap {
|
||||||
|
fn build_graph(&mut self) {
|
||||||
|
for (pos, c) in self.map.indexed_iter() {
|
||||||
|
match c {
|
||||||
|
'#' => continue,
|
||||||
|
'.' => {
|
||||||
|
adjacent_to(&self.map, pos).iter().for_each(|adj| {
|
||||||
|
if self.indexes.contains_key(&adj) {
|
||||||
|
self.graph.add_edge(self.indexes[&pos], self.indexes[adj], 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
'^' => {
|
||||||
|
if let Some(adj) = offset_pos(&self.map, pos, (0, -1)) {
|
||||||
|
if self.indexes.contains_key(&adj) {
|
||||||
|
self.graph.add_edge(self.indexes[&pos], self.indexes[&adj], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'>' => {
|
||||||
|
if let Some(adj) = offset_pos(&self.map, pos, (1, 0)) {
|
||||||
|
if self.indexes.contains_key(&adj) {
|
||||||
|
self.graph.add_edge(self.indexes[&pos], self.indexes[&adj], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'v' => {
|
||||||
|
if let Some(adj) = offset_pos(&self.map, pos, (0, 1)) {
|
||||||
|
if self.indexes.contains_key(&adj) {
|
||||||
|
self.graph.add_edge(self.indexes[&pos], self.indexes[&adj], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'<' => {
|
||||||
|
if let Some(adj) = offset_pos(&self.map, pos, (-1, 0)) {
|
||||||
|
if self.indexes.contains_key(&adj) {
|
||||||
|
self.graph.add_edge(self.indexes[&pos], self.indexes[&adj], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c => panic!("invalid map character {}", c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_graph2(&mut self) {
|
||||||
|
for (pos, c) in self.map.indexed_iter() {
|
||||||
|
match c {
|
||||||
|
'#' => continue,
|
||||||
|
'.' | '^' | '>' | 'v' | '<' => {
|
||||||
|
adjacent_to(&self.map, pos).iter().for_each(|adj| {
|
||||||
|
if self.indexes.contains_key(&adj) {
|
||||||
|
self.graph.add_edge(self.indexes[&pos], self.indexes[adj], 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
c => panic!("invalid map character {}", c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cull nodes that don't change the topology of the graph and combine their cost
|
||||||
|
fn simplify_graph(&mut self) {
|
||||||
|
let mut idxs: Vec<_> = self
|
||||||
|
.graph
|
||||||
|
.neighbors(self.indexes[&self.start])
|
||||||
|
.map(|idx| (self.indexes[&self.start], idx))
|
||||||
|
.collect();
|
||||||
|
let mut visited = HashSet::from([self.indexes[&self.start]]);
|
||||||
|
while let Some((last_idx, cur_idx)) = idxs.pop() {
|
||||||
|
if !visited.insert(cur_idx) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let our_neighbors = self.graph.neighbors(cur_idx).collect_vec();
|
||||||
|
|
||||||
|
// if we have exactly 2 neighbours, then one is where we came from, and we can shortcut this node with a
|
||||||
|
// pair of new edges A <-> C and break the existing 4 edges between them
|
||||||
|
if our_neighbors.len() == 2 {
|
||||||
|
let next_idx = our_neighbors.iter().find(|n| **n != last_idx).unwrap();
|
||||||
|
|
||||||
|
// remove the 4 existing edges
|
||||||
|
// careful of order of operations, as removing edges invalidates edge indexes
|
||||||
|
let forward_cost = self
|
||||||
|
.graph
|
||||||
|
.remove_edge(self.graph.find_edge(cur_idx, *next_idx).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
let last_forward_cost = self
|
||||||
|
.graph
|
||||||
|
.remove_edge(self.graph.find_edge(last_idx, cur_idx).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
let backward_cost = self
|
||||||
|
.graph
|
||||||
|
.remove_edge(self.graph.find_edge(cur_idx, last_idx).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
let next_backward_cost = self
|
||||||
|
.graph
|
||||||
|
.remove_edge(self.graph.find_edge(*next_idx, cur_idx).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
let new_forward_cost = forward_cost + last_forward_cost;
|
||||||
|
let new_backward_cost = backward_cost + next_backward_cost;
|
||||||
|
|
||||||
|
// add edge from last to next
|
||||||
|
self.graph.add_edge(last_idx, *next_idx, new_forward_cost);
|
||||||
|
self.graph.add_edge(*next_idx, last_idx, new_backward_cost);
|
||||||
|
|
||||||
|
self.graph.remove_node(cur_idx);
|
||||||
|
// push the next node
|
||||||
|
idxs.push((last_idx, *next_idx));
|
||||||
|
} else {
|
||||||
|
// don't do anything about nodes with > 2 edges, just push them onto the stack, if there are some
|
||||||
|
idxs.append(
|
||||||
|
&mut self
|
||||||
|
.graph
|
||||||
|
.neighbors(cur_idx)
|
||||||
|
.into_iter()
|
||||||
|
.map(|next_idx| (cur_idx, next_idx))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for ForestMap {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
for y in 0..self.map.len_of(Axis(1)) {
|
||||||
|
for c in self.map.index_axis(Axis(1), y) {
|
||||||
|
f.write_char(*c)?;
|
||||||
|
}
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let mut map = ForestMap::from(input);
|
||||||
|
map.build_graph();
|
||||||
|
// println!("{:?}", map);
|
||||||
|
let paths = all_simple_paths::<Vec<_>, _>(&map.graph, map.indexes[&map.start], map.indexes[&map.end], 0, None)
|
||||||
|
.collect_vec();
|
||||||
|
let longest = paths.iter().max_by_key(|path| path.len()).unwrap();
|
||||||
|
|
||||||
|
longest.len() as u64 - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calc_path_length(map: &ForestMap, path: &Vec<NodeIndex>) -> u64 {
|
||||||
|
path.iter().tuple_windows().fold(0, |accum, (prev, next)| {
|
||||||
|
accum + map.graph[map.graph.find_edge(*prev, *next).unwrap()]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let mut map = ForestMap::from(input);
|
||||||
|
map.build_graph2();
|
||||||
|
map.simplify_graph();
|
||||||
|
|
||||||
|
let paths = all_simple_paths::<Vec<_>, _>(&map.graph, map.indexes[&map.start], map.indexes[&map.end], 0, None)
|
||||||
|
.collect_vec();
|
||||||
|
let longest = paths.iter().max_by_key(|path| calc_path_length(&map, &path)).unwrap();
|
||||||
|
longest.iter().tuple_windows().fold(0, |accum, (prev, next)| {
|
||||||
|
accum + map.graph[map.graph.find_edge(*prev, *next).unwrap()]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"#.#####################
|
||||||
|
#.......#########...###
|
||||||
|
#######.#########.#.###
|
||||||
|
###.....#.>.>.###.#.###
|
||||||
|
###v#####.#v#.###.#.###
|
||||||
|
###.>...#.#.#.....#...#
|
||||||
|
###v###.#.#.#########.#
|
||||||
|
###...#.#.#.......#...#
|
||||||
|
#####.#.#.#######.#.###
|
||||||
|
#.....#.#.#.......#...#
|
||||||
|
#.#####.#.#.#########v#
|
||||||
|
#.#...#...#...###...>.#
|
||||||
|
#.#.#v#######v###.###v#
|
||||||
|
#...#.>.#...>.>.#.###.#
|
||||||
|
#####v#.#.###v#.#.###.#
|
||||||
|
#.....#...#...#.#.#...#
|
||||||
|
#.#########.###.#.#.###
|
||||||
|
#...###...#...#...#.###
|
||||||
|
###.###.#.###v#####v###
|
||||||
|
#...#...#.#.>.>.#.>.###
|
||||||
|
#.###.###.#.###.#.#v###
|
||||||
|
#.....###...###...#...#
|
||||||
|
#####################.#";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1(c.lines()), 94);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem2_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem2(c.lines()), 154);
|
||||||
|
}
|
||||||
|
}
|
134
24/Cargo.lock
generated
Normal file
134
24/Cargo.lock
generated
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day24"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"lazy-regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy-regex"
|
||||||
|
version = "3.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c"
|
||||||
|
dependencies = [
|
||||||
|
"lazy-regex-proc_macros",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy-regex-proc_macros"
|
||||||
|
version = "3.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.71"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
10
24/Cargo.toml
Normal file
10
24/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "day24"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itertools = "0.12.0"
|
||||||
|
lazy-regex = "3.1.0"
|
24
24/cheat.py
Normal file
24
24/cheat.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from z3 import *
|
||||||
|
|
||||||
|
rx, ry, rz = Ints('rx ry rz')
|
||||||
|
rvx, rvy, rvz = Ints('rvx rvy rvz')
|
||||||
|
t0, t1, t2 = Ints('t0 t1 t2')
|
||||||
|
answer = Int('answer')
|
||||||
|
|
||||||
|
solve(
|
||||||
|
rx + t0 * rvx == 225415405941969 + t0 * 23,
|
||||||
|
ry + t0 * rvy == 400648127977931 + t0 * -204,
|
||||||
|
rz + t0 * rvz == 79201130433258 + t0 * 617,
|
||||||
|
|
||||||
|
rx + t1 * rvx == 353783687623292 + t1 * -80,
|
||||||
|
ry + t1 * rvy == 138575899489956 + t1 * 156,
|
||||||
|
rz + t1 * rvz == 318416438572569 + t1 * 21,
|
||||||
|
|
||||||
|
rx + t2 * rvx == 215751176267772 + t2 * -120,
|
||||||
|
ry + t2 * rvy == 376619563956940 + t2 * 126,
|
||||||
|
rz + t2 * rvz == 230133299986253 + t2 * -352,
|
||||||
|
|
||||||
|
answer == rx + ry + rz,
|
||||||
|
)
|
205
24/src/main.rs
Normal file
205
24/src/main.rs
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
use itertools::Itertools;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::ops::Index;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// 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() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Vec3 {
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
z: f64,
|
||||||
|
}
|
||||||
|
impl Debug for Vec3 {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}, {}, {}", self.x, self.y, self.z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Vec2 {
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
}
|
||||||
|
impl Debug for Vec2 {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}, {}", self.x, self.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
|
||||||
|
struct Hailstone {
|
||||||
|
pos: Vec3,
|
||||||
|
vel: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hailstone {
|
||||||
|
fn xy_vel_angle(&self) -> f64 {
|
||||||
|
(self.vel.y / self.vel.x).atan()
|
||||||
|
}
|
||||||
|
fn xy_vel_abs(&self) -> f64 {
|
||||||
|
(self.vel.x.powi(2) + self.vel.y.powi(2)).sqrt()
|
||||||
|
}
|
||||||
|
fn xy_slope(&self) -> f64 {
|
||||||
|
self.vel.y / self.vel.x
|
||||||
|
}
|
||||||
|
fn y_crossing(&self) -> f64 {
|
||||||
|
self.pos.y - self.xy_slope() * self.pos.x
|
||||||
|
}
|
||||||
|
fn xy_poi(&self, other: &Hailstone) -> Option<Vec2> {
|
||||||
|
let our_slope = self.xy_slope();
|
||||||
|
let other_slope = other.xy_slope();
|
||||||
|
if our_slope == other_slope || our_slope * other_slope == -1. {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let our_yint = self.y_crossing();
|
||||||
|
let other_yint = other.y_crossing();
|
||||||
|
let ratio = (other_yint - our_yint) / (our_slope - other_slope);
|
||||||
|
Some(Vec2 {
|
||||||
|
x: ratio,
|
||||||
|
y: our_slope * ratio + our_yint,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn xy_point_future(&self, point: &Vec2) -> bool {
|
||||||
|
// a point will be in the past if the difference between its 'new' position and its 'start' position has a
|
||||||
|
// different sign than the velocity for any component
|
||||||
|
let diffs = [point.x - self.pos.x, point.y - self.pos.y];
|
||||||
|
// for (diff, vel) in diffs.iter().zip([self.vel.x, self.vel.y].iter()) {
|
||||||
|
// println!(" diff: {:?} vel: {:?} mul: {:?}", diff, vel, diff * vel > 0.);
|
||||||
|
// }
|
||||||
|
diffs.iter().zip([self.vel.x, self.vel.y].iter()).any(|(diff, vel)| diff * vel > 0.)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Hailstone {
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
let (pos, vel) = value.split_once("@").unwrap();
|
||||||
|
let [px, py, pz] = pos.split(",").map(|s| s.trim().parse::<f64>().unwrap()).collect_vec()[..] else {
|
||||||
|
panic!()
|
||||||
|
};
|
||||||
|
let [vx, vy, vz] = vel.split(",").map(|s| s.trim().parse::<f64>().unwrap()).collect_vec()[..] else {
|
||||||
|
panic!()
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
pos: Vec3 { x: px, y: py, z: pz },
|
||||||
|
vel: Vec3 { x: vx, y: vy, z: vz },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Hailstone {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:?} @ {:?}", self.pos, self.vel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Hailstones {
|
||||||
|
stones: Vec<Hailstone>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hailstones {
|
||||||
|
fn count_xy_pois(&self, bounds: (f64, f64)) -> u64 {
|
||||||
|
assert!(bounds.0 < bounds.1);
|
||||||
|
let mut stones = self.stones.clone();
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
while let Some(stone) = &stones.pop() {
|
||||||
|
for other in &stones {
|
||||||
|
let Some(poi) = stone.xy_poi(other) else { continue };
|
||||||
|
// println!("intersection: {:?} / {:?} @ {:?}", stone, other, poi);
|
||||||
|
if poi.x >= bounds.0 && poi.x <= bounds.1 && poi.y >= bounds.0 && poi.y <= bounds.1 && stone.xy_point_future(&poi) && other.xy_point_future(&poi) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for Hailstones {
|
||||||
|
type Output = Hailstone;
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
&self.stones[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for Hailstones {
|
||||||
|
fn from(value: Lines<T>) -> Self {
|
||||||
|
let mut stones = Vec::new();
|
||||||
|
for line in value {
|
||||||
|
stones.push(Hailstone::from(line.unwrap().as_str()));
|
||||||
|
}
|
||||||
|
Hailstones { stones }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
problem1_impl(input, (200000000000000., 400000000000000.))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn problem1_impl<T: BufRead>(input: Lines<T>, bounds: (f64, f64)) -> u64 {
|
||||||
|
let stones = Hailstones::from(input);
|
||||||
|
|
||||||
|
stones.count_xy_pois(bounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 = &"19, 13, 30 @ -2, 1, -2
|
||||||
|
18, 19, 22 @ -1, -1, -2
|
||||||
|
20, 25, 34 @ -2, -2, -4
|
||||||
|
12, 31, 28 @ -1, -2, -1
|
||||||
|
20, 19, 15 @ 1, -5, -3";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1_impl(c.lines(), (7., 27.)), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem2_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem2(c.lines()), 0);
|
||||||
|
}
|
||||||
|
}
|
266
25/Cargo.lock
generated
Normal file
266
25/Cargo.lock
generated
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "console"
|
||||||
|
version = "0.15.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
|
||||||
|
dependencies = [
|
||||||
|
"encode_unicode",
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"unicode-width",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day25"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"indicatif",
|
||||||
|
"itertools",
|
||||||
|
"petgraph",
|
||||||
|
"rayon",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encode_unicode"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indicatif"
|
||||||
|
version = "0.17.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25"
|
||||||
|
dependencies = [
|
||||||
|
"console",
|
||||||
|
"instant",
|
||||||
|
"number_prefix",
|
||||||
|
"portable-atomic",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instant"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.151"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "number_prefix"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset",
|
||||||
|
"indexmap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "portable-atomic"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.45.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
12
25/Cargo.toml
Normal file
12
25/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "day25"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
indicatif = "0.17.7"
|
||||||
|
itertools = "0.12.0"
|
||||||
|
petgraph = "0.6.4"
|
||||||
|
rayon = "1.8.0"
|
171
25/src/main.rs
Normal file
171
25/src/main.rs
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
use indicatif::{ProgressBar, ProgressIterator, ProgressStyle};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use petgraph::algo::connected_components;
|
||||||
|
use petgraph::dot::Dot;
|
||||||
|
use petgraph::prelude::*;
|
||||||
|
use petgraph::visit::{depth_first_search, DfsEvent, IntoEdgeReferences, IntoNodeIdentifiers, IntoNodeReferences};
|
||||||
|
use rayon::prelude::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// 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() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// PARSE
|
||||||
|
|
||||||
|
struct Circuit {
|
||||||
|
graph: UnGraph<String, String>,
|
||||||
|
nodes: HashMap<String, Node>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Node {
|
||||||
|
targets: Vec<String>,
|
||||||
|
index: Option<NodeIndex>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
fn with_index(mut self, index: NodeIndex) -> Self {
|
||||||
|
self.index = Some(index);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for Circuit {
|
||||||
|
fn from(lines: Lines<T>) -> Self {
|
||||||
|
let mut graph = UnGraph::default();
|
||||||
|
let mut nodes = HashMap::new();
|
||||||
|
for line in lines.map(|v| v.unwrap()) {
|
||||||
|
let (source, targets_s) = line.split_once(": ").unwrap();
|
||||||
|
let targets = targets_s.split_whitespace().map(|s| s.to_string()).collect_vec();
|
||||||
|
nodes.insert(
|
||||||
|
source.to_string(),
|
||||||
|
Node {
|
||||||
|
targets,
|
||||||
|
index: Some(graph.add_node(source.to_string())),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (name, node) in nodes.iter_mut() {
|
||||||
|
for target in &node.targets {
|
||||||
|
let target_idx = match graph.node_references().find(|n| n.1 == target).map(|n| n.0) {
|
||||||
|
Some(target) => target,
|
||||||
|
None => graph.add_node(target.to_string()),
|
||||||
|
};
|
||||||
|
graph.add_edge(node.index.unwrap(), target_idx, format!("{}-{}", name, target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { graph, nodes }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Circuit {
|
||||||
|
// returns the set of nodes on each side
|
||||||
|
fn find_critical_edges(&self, removals: usize) -> (Vec<String>, Vec<String>) {
|
||||||
|
let bar = ProgressBar::new(self.graph.edge_references().combinations(removals).try_len().unwrap() as u64)
|
||||||
|
.with_style(
|
||||||
|
ProgressStyle::with_template(
|
||||||
|
"[{elapsed_precise}/{eta_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {per_sec}",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
// for set in self.graph.edge_references().combinations(removals).progress_with(bar) {
|
||||||
|
|
||||||
|
let set = [("zcp", "zjm"), ("rsg", "nsk"), ("jks", "rfg")]
|
||||||
|
.iter()
|
||||||
|
.flat_map(|(src, dst)| {
|
||||||
|
self.graph.edge_references().filter(|e| self.graph[e.source()] == *src && self.graph[e.target()] == *dst || self.graph[e.target()] == *src && self.graph[e.source()] == *dst)
|
||||||
|
}).collect_vec();
|
||||||
|
let mut local_graph: StableUnGraph<_, _> = self.graph.clone().into();
|
||||||
|
for wire in &set {
|
||||||
|
local_graph.remove_edge(wire.id());
|
||||||
|
}
|
||||||
|
let local_graph = UnGraph::from(local_graph);
|
||||||
|
if connected_components(&local_graph) == 2 {
|
||||||
|
// each edge will have one leg in each component, so return the set of connected nodes
|
||||||
|
let mut left = Vec::new();
|
||||||
|
depth_first_search(&local_graph, Some(set[0].source()), |event| {
|
||||||
|
if let DfsEvent::Discover(n, t) = event {
|
||||||
|
left.push(local_graph[n].to_string());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let mut right = Vec::new();
|
||||||
|
depth_first_search(&local_graph, Some(set[0].target()), |event| {
|
||||||
|
if let DfsEvent::Discover(n, t) = event {
|
||||||
|
right.push(local_graph[n].to_string());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return (left, right);
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
panic!("no cutline found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let circuit = Circuit::from(input);
|
||||||
|
println!("{:?}", Dot::new(&circuit.graph));
|
||||||
|
let (left, right) = circuit.find_critical_edges(3);
|
||||||
|
(left.len() * right.len()) as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 = &"jqt: rhn xhk nvd
|
||||||
|
rsh: frs pzl lsr
|
||||||
|
xhk: hfx
|
||||||
|
cmg: qnr nvd lhk bvb
|
||||||
|
rhn: xhk bvb hfx
|
||||||
|
bvb: xhk hfx
|
||||||
|
pzl: lsr hfx nvd
|
||||||
|
qnr: nvd
|
||||||
|
ntq: jqt hfx bvb xhk
|
||||||
|
nvd: lhk
|
||||||
|
lsr: lhk
|
||||||
|
rzs: qnr cmg lsr rsh
|
||||||
|
frs: qnr lhk lsr";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1(c.lines()), 54);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem2_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem2(c.lines()), 0);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user