Day 24 (late)
This commit is contained in:
parent
12fde697d3
commit
9a43cb0f4a
|
@ -25,6 +25,7 @@ dependencies = [
|
||||||
"itertools 0.13.0",
|
"itertools 0.13.0",
|
||||||
"pest",
|
"pest",
|
||||||
"pest_derive",
|
"pest_derive",
|
||||||
|
"rand",
|
||||||
"raylib",
|
"raylib",
|
||||||
"rayon",
|
"rayon",
|
||||||
"regex",
|
"regex",
|
||||||
|
@ -129,6 +130,12 @@ version = "3.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
|
@ -1085,6 +1092,15 @@ version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prettyplease"
|
name = "prettyplease"
|
||||||
version = "0.2.25"
|
version = "0.2.25"
|
||||||
|
@ -1113,6 +1129,36 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "raylib"
|
name = "raylib"
|
||||||
version = "5.0.2"
|
version = "5.0.2"
|
||||||
|
@ -2027,6 +2073,27 @@ dependencies = [
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.90",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerofrom"
|
name = "zerofrom"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
|
|
@ -8,6 +8,7 @@ dotenvy = "0.15.7"
|
||||||
itertools = "0.13.0"
|
itertools = "0.13.0"
|
||||||
pest = "2.7.15"
|
pest = "2.7.15"
|
||||||
pest_derive = "2.7.15"
|
pest_derive = "2.7.15"
|
||||||
|
rand = "0.8.5"
|
||||||
raylib = "5.0.2"
|
raylib = "5.0.2"
|
||||||
rayon = "1.10.0"
|
rayon = "1.10.0"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
|
|
|
@ -0,0 +1,229 @@
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub fn day24() {
|
||||||
|
let (_values, mut connections) = input(&crate::input(24));
|
||||||
|
|
||||||
|
fn swap(connections: &mut Vec<Connection>, a_name: &str, b_name: &str) {
|
||||||
|
let a = connections
|
||||||
|
.iter()
|
||||||
|
.position(|connection| &connection.output == a_name)
|
||||||
|
.unwrap();
|
||||||
|
let b = connections
|
||||||
|
.iter()
|
||||||
|
.position(|connection| &connection.output == b_name)
|
||||||
|
.unwrap();
|
||||||
|
connections[a].output = b_name.to_string();
|
||||||
|
connections[b].output = a_name.to_string();
|
||||||
|
}
|
||||||
|
swap(&mut connections, "z06", "vwr");
|
||||||
|
swap(&mut connections, "z11", "tqm");
|
||||||
|
swap(&mut connections, "z16", "kfs");
|
||||||
|
swap(&mut connections, "hcm", "gfv");
|
||||||
|
|
||||||
|
fn wire_number(w: &str) -> u64 {
|
||||||
|
w.get(1..).unwrap().parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_start_wire(w: &str) -> bool {
|
||||||
|
w.starts_with("x") || w.starts_with("y")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn are_start_wires(a: &str, b: &str) -> Option<u64> {
|
||||||
|
if !is_start_wire(a) || !is_start_wire(b) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let a_n = wire_number(a);
|
||||||
|
let b_n = wire_number(b);
|
||||||
|
if a_n == b_n {
|
||||||
|
Some(a_n)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut carry_out_wires: HashMap<u64, String> = HashMap::new();
|
||||||
|
let mut second_carries: HashMap<u64, String> = HashMap::new();
|
||||||
|
for i in 0..45 {
|
||||||
|
// The first sum wire goes xi XOR yi
|
||||||
|
let first_sum = connections.iter().find(|connection| {
|
||||||
|
are_start_wires(&connection.a, &connection.b) == Some(i) && connection.f == xor
|
||||||
|
});
|
||||||
|
let first_sum = match first_sum {
|
||||||
|
Some(x) => &x.output,
|
||||||
|
None => panic!("First sum for {i} does not exist."),
|
||||||
|
};
|
||||||
|
// The first carry wire goes xi AND yi
|
||||||
|
let first_carry = connections.iter().find(|connection| {
|
||||||
|
are_start_wires(&connection.a, &connection.b) == Some(i) && connection.f == and
|
||||||
|
});
|
||||||
|
let first_carry = match first_carry {
|
||||||
|
Some(x) => &x.output,
|
||||||
|
None => panic!("First carry for {i} does not exist."),
|
||||||
|
};
|
||||||
|
// If this is 0, the first carry is the carry_out and the first sum is the output (and skip the rest)
|
||||||
|
if i == 0 {
|
||||||
|
if wire_number(&first_sum) != i || !first_sum.starts_with("z") {
|
||||||
|
panic!("The first output wire is wrong.");
|
||||||
|
}
|
||||||
|
carry_out_wires.insert(0, first_carry.clone());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// The output wire goes [first_sum] XOR [prev carry_out] -> zi
|
||||||
|
let prev_carry_out = carry_out_wires.get(&(i - 1)).unwrap();
|
||||||
|
let output = &connections
|
||||||
|
.iter()
|
||||||
|
.find(|connection| {
|
||||||
|
let p1 = &connection.a == first_sum
|
||||||
|
&& &connection.b == prev_carry_out
|
||||||
|
&& connection.f == xor;
|
||||||
|
let p2 = &connection.b == first_sum
|
||||||
|
&& &connection.a == prev_carry_out
|
||||||
|
&& connection.f == xor;
|
||||||
|
p1 || p2
|
||||||
|
})
|
||||||
|
.expect(&format!("Couldn't find an output for {i}. Previous carry-out was {prev_carry_out} and first_sum was {first_sum}."))
|
||||||
|
.output;
|
||||||
|
if !output.starts_with("z") || wire_number(&output) != i {
|
||||||
|
println!(
|
||||||
|
"The output for {i} should be z{i} but is instead {}",
|
||||||
|
output
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// The second carry wire goes [first_sum] AND [prev carry_out]
|
||||||
|
let second_carry = &connections
|
||||||
|
.iter()
|
||||||
|
.find(|connection| {
|
||||||
|
let p1 = &connection.a == first_sum
|
||||||
|
&& &connection.b == prev_carry_out
|
||||||
|
&& connection.f == and;
|
||||||
|
let p2 = &connection.b == first_sum
|
||||||
|
&& &connection.a == prev_carry_out
|
||||||
|
&& connection.f == and;
|
||||||
|
p1 || p2
|
||||||
|
})
|
||||||
|
.expect(&format!("Couldn't find a second carry for {i}."))
|
||||||
|
.output;
|
||||||
|
second_carries.insert(i, second_carry.clone());
|
||||||
|
// The carry_out goes [first_carry OR second_carry]
|
||||||
|
let carry_out = &connections
|
||||||
|
.iter()
|
||||||
|
.find(|connection| {
|
||||||
|
let p1 = &connection.a == first_carry
|
||||||
|
&& &connection.b == second_carry
|
||||||
|
&& connection.f == or;
|
||||||
|
let p2 = &connection.b == first_carry
|
||||||
|
&& &connection.a == second_carry
|
||||||
|
&& connection.f == or;
|
||||||
|
p1 || p2
|
||||||
|
})
|
||||||
|
.expect(&format!("Couldn't find a carry out for {i}."))
|
||||||
|
.output;
|
||||||
|
carry_out_wires.insert(i, carry_out.clone());
|
||||||
|
}
|
||||||
|
// Finally, make sure z45 is carry_out of 44
|
||||||
|
if carry_out_wires.get(&44).unwrap() != "z45" {
|
||||||
|
println!(
|
||||||
|
"The final carry out should be z45 but is instead {}",
|
||||||
|
carry_out_wires.get(&44).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_system_with_inputs(connections: &Vec<Connection>, x: u64, y: u64) -> u64 {
|
||||||
|
let mut values: HashMap<String, bool> = HashMap::new();
|
||||||
|
for b in 0..45 {
|
||||||
|
values.insert(format!("x{:02}", b), ((1 << b) & x) != 0);
|
||||||
|
values.insert(format!("y{:02}", b), ((1 << b) & y) != 0);
|
||||||
|
}
|
||||||
|
run_system(&values, connections)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_system(values: &HashMap<String, bool>, connections: &Vec<Connection>) -> u64 {
|
||||||
|
let mut values = values.clone();
|
||||||
|
let mut connections = connections.clone();
|
||||||
|
let mut remaining_connections = vec![];
|
||||||
|
while !connections.is_empty() {
|
||||||
|
for connection in connections {
|
||||||
|
if values.contains_key(&connection.a) && values.contains_key(&connection.b) {
|
||||||
|
values.insert(
|
||||||
|
connection.output.to_string(),
|
||||||
|
(connection.f)(values[&connection.a], values[&connection.b]),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
remaining_connections.push(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connections = remaining_connections;
|
||||||
|
remaining_connections = vec![];
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut number: u64 = 0;
|
||||||
|
for (wire, value) in values.iter() {
|
||||||
|
if wire.starts_with("z") {
|
||||||
|
let place: u64 = wire.get(1..).unwrap().parse().unwrap();
|
||||||
|
number = number | ((*value as u64) << place);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
number
|
||||||
|
}
|
||||||
|
|
||||||
|
type Gate = fn(bool, bool) -> bool;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Connection {
|
||||||
|
a: String,
|
||||||
|
b: String,
|
||||||
|
f: Gate,
|
||||||
|
output: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Connection {
|
||||||
|
fn new(a: String, b: String, f: Gate, output: String) -> Self {
|
||||||
|
Self { a, b, f, output }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input(s: &str) -> (HashMap<String, bool>, Vec<Connection>) {
|
||||||
|
let (values_input, gates_input) = s.split("\n\n").collect_tuple().unwrap();
|
||||||
|
let mut values: HashMap<String, bool> = values_input
|
||||||
|
.lines()
|
||||||
|
.map(|line| {
|
||||||
|
let (name, value) = line.split(": ").collect_tuple().unwrap();
|
||||||
|
let value = match value {
|
||||||
|
"0" => false,
|
||||||
|
"1" => true,
|
||||||
|
_ => panic!(),
|
||||||
|
};
|
||||||
|
(name.to_string(), value)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let mut connections: Vec<Connection> = gates_input
|
||||||
|
.lines()
|
||||||
|
.map(|line| {
|
||||||
|
let parts: Vec<&str> = line.split(" ").collect();
|
||||||
|
let (a, gate, b, c) = (parts[0], parts[1], parts[2], parts[4]);
|
||||||
|
let gate = match gate {
|
||||||
|
"AND" => and,
|
||||||
|
"OR" => or,
|
||||||
|
"XOR" => xor,
|
||||||
|
_ => panic!(),
|
||||||
|
};
|
||||||
|
Connection::new(a.to_string(), b.to_string(), gate, c.to_string())
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
(values, connections)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn and(a: bool, b: bool) -> bool {
|
||||||
|
a && b
|
||||||
|
}
|
||||||
|
|
||||||
|
fn or(a: bool, b: bool) -> bool {
|
||||||
|
a || b
|
||||||
|
}
|
||||||
|
|
||||||
|
fn xor(a: bool, b: bool) -> bool {
|
||||||
|
a ^ b
|
||||||
|
}
|
|
@ -30,7 +30,9 @@ mod day20;
|
||||||
mod day21;
|
mod day21;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod day22;
|
mod day22;
|
||||||
|
#[allow(dead_code)]
|
||||||
mod day23;
|
mod day23;
|
||||||
|
mod day24;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod day3;
|
mod day3;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -47,7 +49,7 @@ mod day8;
|
||||||
mod day9;
|
mod day9;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
day23::day23();
|
day24::day24();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(day: u8) -> String {
|
pub fn input(day: u8) -> String {
|
||||||
|
|
Loading…
Reference in New Issue