Skip to content

Commit

Permalink
I'm sorry.
Browse files Browse the repository at this point in the history
  • Loading branch information
Icerath committed Dec 25, 2024
1 parent 0992946 commit 7017239
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 3 deletions.
2 changes: 1 addition & 1 deletion benches/bench_today.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ macro_rules! bench_day {
};
}

bench_day!(day23);
bench_day!(day24);
170 changes: 170 additions & 0 deletions src/day24.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#![expect(clippy::cast_possible_truncation, static_mut_refs, clippy::items_after_statements)]
use std::hint::{assert_unchecked, unreachable_unchecked};
use tinyvec::ArrayVec;

pub fn part1(input: &str) -> u64 {
unsafe { part1_inner(input.as_bytes()) }
}

pub fn part2(input: &str) -> &'static str {
unsafe { part2_inner(input.as_bytes()) }
}

macro_rules! parse_gate_connections {
($input: ident) => {{
assert_unchecked($input.len() >= 18);
let lhs = compress_gate($input);
let op = $input[4];
$input = match op {
b'O' => &$input[7..],
b'A' | b'X' => &$input[8..],
_ => unreachable_unchecked(),
};
let rhs = compress_gate($input);
let output = compress_gate(&$input[7..]);
$input = &$input[11..];
(lhs, op, rhs, output)
}};
}

static mut IDS: [Option<u16>; ZEDS[0] as usize + 1] = [None; ZEDS[0] as usize + 1];
static mut GATES: [Option<bool>; ZEDS[0] as usize + 1] = [None; ZEDS[0] as usize + 1];
static mut OPS: [(u16, u8, u16); ZEDS[0] as usize + 1] = [(0, 0, 0); ZEDS[0] as usize + 1];

unsafe fn part1_inner(mut input: &[u8]) -> u64 {
let mut num_gates = 0;
while *input.get_unchecked(0) != b'\n' {
assert_unchecked(input.len() >= 8);
*IDS.get_unchecked_mut(compress_gate(input) as usize) = Some(num_gates as u16);
*GATES.get_unchecked_mut(num_gates) = Some(input[5] == b'1');
num_gates += 1;
input = &input[7..];
}
input = input.get_unchecked(1..);

let mut id = num_gates as u16;
while !input.is_empty() {
let (lhs, op, rhs, output) = parse_gate_connections!(input);
let lhs = *IDS.get_unchecked_mut(lhs as usize).get_or_insert(id);
let rhs = *IDS.get_unchecked_mut(rhs as usize).get_or_insert(id + 1);
let output = *IDS.get_unchecked_mut(output as usize).get_or_insert(id + 2);
id += 3;

*OPS.get_unchecked_mut(output as usize) = (lhs, op, rhs);
}
let mut result = 0u64;
for key in ZEDS {
let Some(key) = *IDS.get_unchecked(key as usize) else { continue };
result <<= 1;
result |= dfs(key) as u64;
}

result
}

unsafe fn dfs(key: u16) -> bool {
if let Some(value) = *GATES.get_unchecked(key as usize) {
return value;
}
let (lhs, op, rhs) = *OPS.get_unchecked(key as usize);
let value = match op {
b'O' => dfs(lhs) | dfs(rhs),
b'A' => dfs(lhs) & dfs(rhs),
b'X' => dfs(lhs) ^ dfs(rhs),
_ => unreachable_unchecked(),
};
*GATES.get_unchecked_mut(key as usize).insert(value)
}

pub const PART1_OUT: u64 = 42_049_478_636_360;
pub const PART2_OUT: &str = "cph,gws,hgj,nnt,npf,z13,z19,z33";

static mut XORS: [bool; ZEDS[0] as usize + 1] = [false; ZEDS[0] as usize + 1];
static mut ORS: [bool; ZEDS[0] as usize + 1] = [false; ZEDS[0] as usize + 1];

unsafe fn part2_inner(mut input: &[u8]) -> &'static str {
static mut GATES: [(u16, u8, u16, u16); 1024] = [(0, 0, 0, 0); 1024];
while *input.get_unchecked(7) != b'\n' {
input = input.get_unchecked(7..);
}
input = input.get_unchecked(8..);

let mut num_gates = 0;
while !input.is_empty() {
let (lhs, op, rhs, output) = parse_gate_connections!(input);
GATES[num_gates] = (lhs, op, rhs, output);
num_gates += 1;
macro_rules! insert {
($lookup: ident) => {{
*$lookup.get_unchecked_mut(lhs as usize) = true;
*$lookup.get_unchecked_mut(rhs as usize) = true;
}};
}
match op {
b'X' => insert!(XORS),
b'O' => insert!(ORS),
_ => {}
};
}

let mut swapped = ArrayVec::<[u16; 8]>::new();
for &(lhs, op, rhs, output) in GATES.get_unchecked(..num_gates) {
match op {
b'O' if first_char(output) == b'z' && output != Z45 => swapped.push(output),
b'A' if lhs != X00 && rhs != X00 && !ORS.get_unchecked(output as usize) => {
swapped.push(output);
}
b'X' if first_char(lhs) == b'x' || first_char(rhs) == b'x' => {
if lhs != X00 && rhs != X00 && !XORS.get_unchecked(output as usize) {
swapped.push(output);
}
}
b'X' if first_char(output) != b'z' => swapped.push(output),
_ => {}
}
}
let mut swapped: Vec<_> = swapped.into_iter().map(gate_string).collect();
swapped.sort_unstable();
static mut OUTPUT: [u8; 31] = [b','; 31];
for (i, s) in swapped.iter().enumerate() {
*OUTPUT.get_unchecked_mut(i * 4) = s[0];
*OUTPUT.get_unchecked_mut(i * 4 + 1) = s[1];
*OUTPUT.get_unchecked_mut(i * 4 + 2) = s[2];
}
std::str::from_utf8_unchecked(&OUTPUT)
}

const X00: u16 = unsafe { compress_gate(b"x00") };
const Z45: u16 = unsafe { compress_gate(b"z45") };

fn gate_string(key: u16) -> [u8; 3] {
let c1 = key / (36 * 36);
let c1 = b'a' + c1 as u8;
let remaining = key % (36 * 36);
let c2 = (remaining / 36) as u8;
let c2 = if c2 < 26 { b'a' + c2 } else { b'0' + (c2 - 26) };
let c3 = (remaining % 36) as u8;
let c3 = if c3 < 26 { b'a' + c3 } else { b'0' + (c3 - 26) };
[c1, c2, c3]
}

#[inline(always)]
const unsafe fn compress_gate(c: &[u8]) -> u16 {
assert_unchecked(c.len() >= 3);
let c1 = c[0] - b'a';
let c2 = if c[1].is_ascii_digit() { c[1] - b'0' + 26 } else { c[1] - b'a' };
let c3 = if c[2].is_ascii_digit() { c[2] - b'0' + 26 } else { c[2] - b'a' };
c1 as u16 * 36 * 36 + c2 as u16 * 36 + c3 as u16
}

const fn first_char(gate: u16) -> u8 {
(gate / (36 * 36)) as u8 + b'a'
}

const ZEDS: [u16; 64] = [
33581, 33580, 33579, 33578, 33551, 33550, 33549, 33548, 33547, 33546, 33545, 33544, 33543, 33542, 33515,
33514, 33513, 33512, 33511, 33510, 33509, 33508, 33507, 33506, 33479, 33478, 33477, 33476, 33475, 33474,
33473, 33472, 33471, 33470, 33443, 33442, 33441, 33440, 33439, 33438, 33437, 33436, 33435, 33434, 33407,
33406, 33405, 33404, 33403, 33402, 33401, 33400, 33399, 33398, 33371, 33370, 33369, 33368, 33367, 33366,
33365, 33364, 33363, 33362,
];
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
// pub mod day20;
// pub mod day21;
// pub mod day22;
pub mod day23;
// pub mod day23;
pub mod day24;
#[cfg(test)]
mod tests;
2 changes: 1 addition & 1 deletion src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ macro_rules! test_day {
};
}

test_day!(day23);
test_day!(day24);

#[cfg(test)]
static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());

0 comments on commit 7017239

Please sign in to comment.