Skip to content

Commit df299e3

Browse files
committed
2018 day 20
1 parent 842a20f commit df299e3

File tree

4 files changed

+217
-0
lines changed

4 files changed

+217
-0
lines changed

crates/utils/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub mod multiversion;
1818
pub mod number;
1919
pub mod parser;
2020
pub mod simd;
21+
pub mod slice;
2122
#[cfg(target_family = "wasm")]
2223
pub mod wasm;
2324

crates/utils/src/slice.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//! Slice helpers.
2+
use std::cmp::Ordering;
3+
4+
/// Merges a sorted deduped [`Vec`] in place with a sorted deduped slice.
5+
///
6+
/// This is equivalent to a set union on sorted data.
7+
///
8+
/// Both inputs **must** be sorted and contain no duplicates.
9+
///
10+
/// # Examples
11+
/// ```
12+
/// # use utils::slice::merge_sorted_deduped_in_place;
13+
/// let mut v = vec![1, 3, 5];
14+
/// merge_sorted_deduped_in_place(&mut v, &[2, 3, 4]);
15+
/// assert_eq!(v, [1, 2, 3, 4, 5]);
16+
///
17+
/// // Elements at start and end
18+
/// let mut v = vec![1, 2, 3, 4, 5];
19+
/// merge_sorted_deduped_in_place(&mut v, &[0, 6]);
20+
/// assert_eq!(v, [0, 1, 2, 3, 4, 5, 6]);
21+
///
22+
/// // Complete overlap
23+
/// let mut v = vec![1, 2, 3];
24+
/// merge_sorted_deduped_in_place(&mut v, &[1, 2, 3]);
25+
/// assert_eq!(v, [1, 2, 3]);
26+
///
27+
/// // No overlap
28+
/// let mut v = vec![1, 2];
29+
/// merge_sorted_deduped_in_place(&mut v, &[3, 4]);
30+
/// assert_eq!(v, [1, 2, 3, 4]);
31+
///
32+
/// let mut v = vec![24, 53];
33+
/// merge_sorted_deduped_in_place(&mut v, &[6]);
34+
/// assert_eq!(v, [6, 24, 53]);
35+
///
36+
/// // Partial overlap
37+
/// let mut v = vec![10, 11, 12, 13];
38+
/// merge_sorted_deduped_in_place(&mut v, &[13, 14]);
39+
/// assert_eq!(v, [10, 11, 12, 13, 14]);
40+
///
41+
/// let mut v = vec![300, 400, 500];
42+
/// merge_sorted_deduped_in_place(&mut v, &[100, 200, 300]);
43+
/// assert_eq!(v, [100, 200, 300, 400, 500]);
44+
///
45+
/// // Empty inputs
46+
/// let mut v = Vec::new();
47+
/// merge_sorted_deduped_in_place(&mut v, &[5]);
48+
/// assert_eq!(v, [5]);
49+
///
50+
/// let mut v = vec![6];
51+
/// merge_sorted_deduped_in_place(&mut v, &[]);
52+
/// assert_eq!(v, [6]);
53+
///
54+
/// let mut v: Vec<u32> = Vec::new();
55+
/// merge_sorted_deduped_in_place(&mut v, &[]);
56+
/// assert_eq!(v, []);
57+
/// ```
58+
#[inline]
59+
pub fn merge_sorted_deduped_in_place<T: Copy + Ord + Default>(a: &mut Vec<T>, b: &[T]) {
60+
debug_assert!(a.windows(2).all(|w| w[0] < w[1]));
61+
debug_assert!(b.windows(2).all(|w| w[0] < w[1]));
62+
63+
let mut new = 0;
64+
let (mut i, mut j) = (0, 0);
65+
while i < a.len() && j < b.len() {
66+
match a[i].cmp(&b[j]) {
67+
Ordering::Less => i += 1,
68+
Ordering::Equal => {
69+
i += 1;
70+
j += 1;
71+
}
72+
Ordering::Greater => {
73+
new += 1;
74+
j += 1;
75+
}
76+
}
77+
}
78+
new += b.len() - j;
79+
80+
if new == 0 {
81+
return;
82+
}
83+
84+
let (mut i, mut j, mut write) = (a.len(), b.len(), a.len() + new);
85+
a.resize(a.len() + new, T::default());
86+
87+
while i > 0 && j > 0 {
88+
write -= 1;
89+
a[write] = match a[i - 1].cmp(&b[j - 1]) {
90+
Ordering::Less => {
91+
j -= 1;
92+
b[j]
93+
}
94+
Ordering::Equal => {
95+
i -= 1;
96+
j -= 1;
97+
a[i]
98+
}
99+
Ordering::Greater => {
100+
i -= 1;
101+
a[i]
102+
}
103+
}
104+
}
105+
106+
a[..j].copy_from_slice(&b[..j]);
107+
}

crates/year2018/src/day20.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
use utils::prelude::*;
2+
use utils::slice::merge_sorted_deduped_in_place;
3+
4+
/// Following a regex’s branching paths within a grid.
5+
#[derive(Clone, Debug)]
6+
pub struct Day20 {
7+
part1: u16,
8+
part2: u16,
9+
}
10+
11+
const WIDTH: usize = 109;
12+
13+
impl Day20 {
14+
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
15+
if input.as_bytes().first() != Some(&b'^') {
16+
return Err(InputError::new(input, 0, "expected '^'"));
17+
}
18+
if input.as_bytes().last() != Some(&b'$') {
19+
return Err(InputError::new(input, input.len() - 1, "expected '$'"));
20+
}
21+
22+
let mut grid = [0u16; WIDTH * WIDTH];
23+
let mut positions = vec![(WIDTH * WIDTH) / 2];
24+
let (mut start, mut end) = (Vec::new(), Vec::new());
25+
let mut stack = Vec::with_capacity(256);
26+
27+
for (i, &b) in input.as_bytes()[..input.len() - 1]
28+
.iter()
29+
.enumerate()
30+
.skip(1)
31+
{
32+
let dir = match b {
33+
b'N' => -(WIDTH as isize),
34+
b'E' => 1,
35+
b'S' => WIDTH as isize,
36+
b'W' => -1,
37+
b'(' => {
38+
stack.push((std::mem::take(&mut start), std::mem::take(&mut end)));
39+
start.clone_from(&positions);
40+
41+
continue;
42+
}
43+
b'|' => {
44+
if stack.is_empty() {
45+
return Err(InputError::new(input, i, "unexpected '|'"));
46+
}
47+
48+
merge_sorted_deduped_in_place(&mut end, &positions);
49+
positions.clone_from(&start);
50+
51+
continue;
52+
}
53+
b')' => {
54+
merge_sorted_deduped_in_place(&mut positions, &end);
55+
56+
let Some(entry) = stack.pop() else {
57+
return Err(InputError::new(input, i, "unexpected ')'"));
58+
};
59+
(start, end) = entry;
60+
61+
continue;
62+
}
63+
_ => {
64+
return Err(InputError::new(
65+
input,
66+
i,
67+
"expected 'N', 'E', 'S', 'W', '(', '|' or ')'",
68+
));
69+
}
70+
};
71+
72+
for p in positions.iter_mut() {
73+
let distance = grid[*p];
74+
*p = p.wrapping_add_signed(dir);
75+
if grid[*p] == 0 || distance + 1 < grid[*p] {
76+
grid[*p] = distance + 1;
77+
}
78+
}
79+
}
80+
81+
if !stack.is_empty() {
82+
return Err(InputError::new(input, input.len() - 1, "expected ')'"));
83+
}
84+
85+
Ok(Self {
86+
part1: grid.iter().max().copied().unwrap_or(0),
87+
part2: grid.iter().filter(|&&d| d >= 1000).count() as u16,
88+
})
89+
}
90+
91+
#[must_use]
92+
pub fn part1(&self) -> u16 {
93+
self.part1
94+
}
95+
96+
#[must_use]
97+
pub fn part2(&self) -> u16 {
98+
self.part2
99+
}
100+
}
101+
102+
examples!(Day20 -> (u16, u16) [
103+
{input: "^WNE$", part1: 3},
104+
{input: "^ENWWW(NEEE|SSE(EE|N))$", part1: 10},
105+
{input: "^ENNWSWW(NEWS|)SSSEEN(WNSE|)EE(SWEN|)NNN$", part1: 18},
106+
{input: "^ESSWWN(E|NNENN(EESS(WNSE|)SSS|WWWSSSSE(SW|NNNE)))$", part1: 23},
107+
{input: "^WSSEESWWWNW(S|NENNEEEENN(ESSSSW(NWSW|SSEN)|WSWWN(E|WWS(E|SS))))$", part1: 31},
108+
]);

crates/year2018/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ utils::year!(2018 => year2018, ${
2121
17 => day17::Day17,
2222
18 => day18::Day18,
2323
19 => day19::Day19,
24+
20 => day20::Day20,
2425
});

0 commit comments

Comments
 (0)