Skip to content

Commit 1e2769b

Browse files
committed
Add day 23
1 parent 9f55fbc commit 1e2769b

File tree

5 files changed

+266
-2
lines changed

5 files changed

+266
-2
lines changed

benches/bench_days.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,4 @@ macro_rules! benches {
4848
};
4949
}
5050

51-
benches!(22);
51+
benches!(23);

src/day22.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use core::str;
21
use std::{arch::x86_64::*, mem::transmute};
32

43
use aoc_runner_derive::aoc;

src/day23.rs

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
use core::str;
2+
3+
use aoc_runner_derive::aoc;
4+
5+
const MAX: usize = 26 * 26;
6+
7+
const T_START: u16 = (b't' - b'a') as u16 * 26;
8+
const T_END: u16 = T_START + 26;
9+
10+
const T_START_REM: u16 = (-(T_START as i16)).rem_euclid(MAX as i16) as u16;
11+
12+
#[aoc(day23, part1)]
13+
pub fn part1(s: &str) -> u64 {
14+
let s = s.as_bytes();
15+
16+
let mut connections = [const { heapless::Vec::<u16, 16>::new() }; MAX];
17+
unsafe {
18+
let mut i = 0;
19+
while i < s.len() {
20+
let cp1 =
21+
(s.get_unchecked(i) - b'a') as u16 * 26 + (s.get_unchecked(i + 1) - b'a') as u16;
22+
let cp2 = (s.get_unchecked(i + 3) - b'a') as u16 * 26
23+
+ (s.get_unchecked(i + 4) - b'a') as u16;
24+
25+
connections
26+
.get_unchecked_mut(cp1 as usize)
27+
.push_unchecked(cp2);
28+
connections
29+
.get_unchecked_mut(cp2 as usize)
30+
.push_unchecked(cp1);
31+
32+
i += 6;
33+
}
34+
}
35+
36+
// println!(
37+
// "{}{}:",
38+
// ((c / 26) as u8 + b'a') as char,
39+
// ((c % 26) as u8 + b'a') as char,
40+
// );
41+
42+
let mut sum = 0;
43+
for c in T_START..T_END {
44+
for con in &connections[c as usize] {
45+
if ((*con + T_START_REM) % MAX as u16) < (c + T_START_REM) % MAX as u16 {
46+
continue;
47+
}
48+
for concon in &connections[*con as usize] {
49+
if ((*concon + T_START_REM) % MAX as u16) < (*con + T_START_REM) % MAX as u16 {
50+
continue;
51+
}
52+
for conconcon in &connections[*concon as usize] {
53+
if *conconcon == c {
54+
sum += 1;
55+
break;
56+
}
57+
}
58+
}
59+
}
60+
}
61+
62+
sum
63+
}
64+
65+
static mut SCRATCH: [u8; 16 * 3] = [0; 16 * 3];
66+
67+
#[aoc(day23, part2)]
68+
pub fn part2(s: &str) -> &'static str {
69+
let s = s.as_bytes();
70+
71+
let mut g = [[false; MAX]; MAX];
72+
73+
let mut vertecies = const {
74+
let mut vs = [(0u16, 0); MAX];
75+
let mut i = 0;
76+
while i < MAX {
77+
vs[i].0 = i as u16;
78+
i += 1;
79+
}
80+
vs
81+
};
82+
83+
unsafe {
84+
let mut i = 0;
85+
while i < s.len() {
86+
let cp1 =
87+
(s.get_unchecked(i) - b'a') as u16 * 26 + (s.get_unchecked(i + 1) - b'a') as u16;
88+
let cp2 = (s.get_unchecked(i + 3) - b'a') as u16 * 26
89+
+ (s.get_unchecked(i + 4) - b'a') as u16;
90+
91+
*g.get_unchecked_mut(cp2 as usize)
92+
.get_unchecked_mut(cp1 as usize) = true;
93+
*g.get_unchecked_mut(cp1 as usize)
94+
.get_unchecked_mut(cp2 as usize) = true;
95+
vertecies.get_unchecked_mut(cp1 as usize).1 += 1;
96+
vertecies.get_unchecked_mut(cp2 as usize).1 += 1;
97+
98+
i += 6;
99+
}
100+
}
101+
102+
vertecies.sort_unstable_by(|a, b| b.1.cmp(&a.1));
103+
let mut i = vertecies.len() - 1;
104+
while vertecies[i].1 == 0 {
105+
i -= 1;
106+
}
107+
let vertecies = &mut vertecies[..i + 1];
108+
109+
let max_degree = vertecies[0].1 as usize;
110+
111+
for i in 0..max_degree {
112+
vertecies[i].1 = i as u16;
113+
}
114+
for i in max_degree..vertecies.len() {
115+
vertecies[i].1 = max_degree as u16;
116+
}
117+
118+
let mut cs = [const { heapless::Vec::<u16, 16>::new() }; 16];
119+
120+
let mut q = heapless::Vec::<u16, 16>::new();
121+
let mut q_max = heapless::Vec::<u16, 16>::new();
122+
123+
expand(vertecies, &g, &mut q, &mut q_max, &mut cs);
124+
125+
q_max.sort_unstable();
126+
127+
unsafe {
128+
let mut i = 0;
129+
for p in q_max {
130+
SCRATCH[i + 0] = (p / 26) as u8 + b'a';
131+
SCRATCH[i + 1] = (p % 26) as u8 + b'a';
132+
SCRATCH[i + 2] = b',';
133+
i += 3;
134+
}
135+
136+
str::from_utf8_unchecked(&SCRATCH[..i - 1])
137+
}
138+
}
139+
140+
// Using this algorithm: https://web.archive.org/web/20160911054636/http://www.dcs.gla.ac.uk/~pat/jchoco/clique/indSetMachrahanish/papers/tomita2003.pdf
141+
fn expand(
142+
mut r: &mut [(u16, u16)],
143+
g: &[[bool; MAX]; MAX],
144+
q: &mut heapless::Vec<u16, 16>,
145+
q_max: &mut heapless::Vec<u16, 16>,
146+
cs: &mut [heapless::Vec<u16, 16>; 16],
147+
) {
148+
while let Some(((p, color), rest)) = r.split_last_mut() {
149+
let p = *p as usize;
150+
if q.len() + *color as usize + 1 > q_max.len() {
151+
q.push(p as u16).unwrap();
152+
153+
let mut new_r = heapless::Vec::<(u16, u16), 16>::new();
154+
for (i, _) in rest.iter() {
155+
if g[p][*i as usize] {
156+
new_r.push((*i, 0)).unwrap();
157+
}
158+
}
159+
160+
if !new_r.is_empty() {
161+
number_sort(new_r.as_mut_slice(), g, cs);
162+
expand(&mut new_r, g, q, q_max, cs);
163+
} else if q.len() > q_max.len() {
164+
q_max.clone_from(q);
165+
}
166+
q.pop();
167+
} else {
168+
return;
169+
}
170+
r = rest;
171+
}
172+
}
173+
174+
fn number_sort(
175+
r: &mut [(u16, u16)],
176+
g: &[[bool; MAX]; MAX],
177+
cs: &mut [heapless::Vec<u16, 16>; 16],
178+
) {
179+
let mut maxno = 0;
180+
cs[0].clear();
181+
cs[1].clear();
182+
183+
{
184+
let mut r = &*r;
185+
while let Some(((p, _), rest)) = r.split_first() {
186+
let p = *p as usize;
187+
let mut k = 0;
188+
189+
'outer: loop {
190+
for i in &cs[k] {
191+
if g[p][*i as usize] {
192+
k += 1;
193+
continue 'outer;
194+
}
195+
}
196+
break;
197+
}
198+
if k > maxno {
199+
maxno = k;
200+
cs[maxno + 1].clear();
201+
}
202+
cs[k].push(p as u16).unwrap();
203+
204+
r = rest;
205+
}
206+
}
207+
208+
let mut i = 0;
209+
for k in 0..=maxno {
210+
for j in &cs[k] {
211+
r[i] = (*j, k as u16);
212+
i += 1;
213+
}
214+
}
215+
}
216+
217+
#[cfg(test)]
218+
mod test {
219+
use super::*;
220+
221+
const EXAMPLE: &str = r"kh-tc
222+
qp-kh
223+
de-cg
224+
ka-co
225+
yn-aq
226+
qp-ub
227+
cg-tb
228+
vc-aq
229+
tb-ka
230+
wh-tc
231+
yn-cg
232+
kh-ub
233+
ta-co
234+
de-co
235+
tc-td
236+
tb-wq
237+
wh-td
238+
ta-ka
239+
td-qp
240+
aq-cg
241+
wq-ub
242+
ub-vc
243+
de-ta
244+
wq-aq
245+
wq-vc
246+
wh-yn
247+
ka-de
248+
kh-ta
249+
co-tc
250+
wh-qp
251+
tb-vc
252+
td-yn
253+
";
254+
255+
#[test]
256+
fn example_part1() {
257+
assert_eq!(part1(EXAMPLE), 7);
258+
}
259+
#[test]
260+
fn example_part2() {
261+
assert_eq!(part2(EXAMPLE), "co,de,ka,ta");
262+
}
263+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub mod day2;
1717
pub mod day20;
1818
pub mod day21;
1919
pub mod day22;
20+
pub mod day23;
2021
pub mod day3;
2122
pub mod day4;
2223
pub mod day5;

tests/test_days.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,5 @@ benches!(
5757
20 => ("1511", "1020507"),
5858
21 => ("188398", "230049027535970"),
5959
22 => ("20068964552", "2246"),
60+
23 => ("926", "az,ed,hz,it,ld,nh,pc,td,ty,ux,wc,yg,zz"),
6061
);

0 commit comments

Comments
 (0)