Skip to content

Commit e24d3e6

Browse files
committed
Optimize day 14 with bitwise operations
1 parent d0a6999 commit e24d3e6

File tree

1 file changed

+101
-85
lines changed

1 file changed

+101
-85
lines changed

src/day14.rs

Lines changed: 101 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,136 @@
11
#[allow(unused_imports)]
22
use super::prelude::*;
3-
type Input = Grid<u8>;
3+
type Input = (Box<[u128]>, Box<[u128]>);
44

55
pub fn input_generator(input: &str) -> Input {
6-
Grid::from_input_chars(input, |c, _, _| c as u8)
7-
}
6+
let (mut rocks, mut walls) = (vec![0], vec![!0]);
7+
let (mut rock_layer, mut wall_layer) = (0, 1);
88

9-
pub fn part1(input: &Input) -> usize {
10-
let mut input = input.clone();
11-
for y in 1..input.h() {
12-
for x in 0..input.w() {
13-
let mut y = y;
14-
while y > 0 && input[(x, y)] == b'O' && input[(x, y - 1)] == b'.' {
15-
input[(x, y)] = b'.';
16-
input[(x, y - 1)] = b'O';
17-
y -= 1;
9+
for b in input.bytes() {
10+
(rock_layer, wall_layer) = (rock_layer << 1, wall_layer << 1);
11+
match b {
12+
b'\n' => {
13+
rocks.push(rock_layer);
14+
walls.push(wall_layer | 1);
15+
(rock_layer, wall_layer) = (0, 1);
1816
}
17+
b'O' => rock_layer |= 1,
18+
b'#' => wall_layer |= 1,
19+
b'.' => {}
20+
_ => panic!(),
1921
}
2022
}
2123

22-
let mut tot = 0;
24+
rocks.push(0);
25+
walls.push(!0);
2326

24-
for y in 0..input.h() {
25-
for x in 0..input.w() {
26-
if input[(x, y)] == b'O' {
27-
tot += input.h() - y;
28-
}
27+
(rocks.into_boxed_slice(), walls.into_boxed_slice())
28+
}
29+
30+
fn move_north(rocks: &mut [u128], walls: &[u128]) {
31+
for i in 1..rocks.len() - 1 {
32+
let mut curr_rockl = take(&mut rocks[i]);
33+
let mut j = i;
34+
while curr_rockl != 0 {
35+
let stuck_rockl = curr_rockl & (walls[j - 1] | rocks[j - 1]);
36+
rocks[j] |= stuck_rockl;
37+
curr_rockl ^= stuck_rockl;
38+
j -= 1;
2939
}
3040
}
31-
tot
3241
}
3342

34-
pub fn part2(input: &Input) -> usize {
35-
let mut seen = FxHashMap::default();
36-
37-
let mut last_acc = vec![0; input.w()];
38-
let mut input = input.clone();
39-
40-
let mut curr = 0;
41-
while curr < 1000000000 {
42-
seen.insert(input.clone(), curr);
43-
44-
last_acc.fill(0);
45-
for y in 0..input.h() {
46-
for (x, last) in last_acc.iter_mut().enumerate() {
47-
if input[(x, y)] == b'O' {
48-
input[(x, y)] = b'.';
49-
input[(x, *last)] = b'O';
50-
*last += 1;
51-
} else if input[(x, y)] == b'#' {
52-
*last = y + 1;
53-
}
54-
}
43+
fn move_south(rocks: &mut [u128], walls: &[u128]) {
44+
for i in (1..rocks.len() - 1).rev() {
45+
let mut curr_rockl = take(&mut rocks[i]);
46+
let mut j = i;
47+
while curr_rockl != 0 {
48+
let stuck_rockl = curr_rockl & (walls[j + 1] | rocks[j + 1]);
49+
rocks[j] |= stuck_rockl;
50+
curr_rockl ^= stuck_rockl;
51+
j += 1;
5552
}
53+
}
54+
}
5655

57-
for y in 0..input.h() {
58-
let mut last = 0;
59-
for x in 0..input.w() {
60-
if input[(x, y)] == b'O' {
61-
input[(x, y)] = b'.';
62-
input[(last, y)] = b'O';
63-
last += 1;
64-
} else if input[(x, y)] == b'#' {
65-
last = x + 1;
66-
}
56+
fn move_west(rocks: &mut [u128], walls: &[u128]) {
57+
for i in 1..rocks.len() - 1 {
58+
let (mut curr_rockl, mut new_rockl) = (rocks[i], 0);
59+
let mut curr_stuck = walls[i];
60+
while curr_rockl != 0 {
61+
let mut new_stuck = curr_rockl & (curr_stuck >> 1);
62+
while new_stuck != 0 {
63+
curr_stuck |= new_stuck;
64+
new_stuck = (curr_rockl & (curr_stuck >> 1)) & !curr_stuck;
6765
}
66+
new_rockl |= curr_stuck & !walls[i];
67+
curr_rockl = (curr_rockl & !new_rockl) << 1;
6868
}
69+
rocks[i] = new_rockl;
70+
}
71+
}
6972

70-
last_acc.fill(input.h());
71-
for y in (0..input.h()).rev() {
72-
for (x, last) in last_acc.iter_mut().enumerate().rev() {
73-
if input[(x, y)] == b'O' {
74-
*last -= 1;
75-
input[(x, y)] = b'.';
76-
input[(x, *last)] = b'O';
77-
} else if input[(x, y)] == b'#' {
78-
*last = y;
79-
}
73+
fn move_east(rocks: &mut [u128], walls: &[u128]) {
74+
for i in 1..rocks.len() - 1 {
75+
let (mut curr_rockl, mut new_rockl) = (rocks[i], 0);
76+
let mut curr_stuck = walls[i];
77+
while curr_rockl != 0 {
78+
let mut new_stuck = curr_rockl & (curr_stuck << 1);
79+
while new_stuck != 0 {
80+
curr_stuck |= new_stuck;
81+
new_stuck = (curr_rockl & (curr_stuck << 1)) & !curr_stuck;
8082
}
83+
new_rockl |= curr_stuck & !walls[i];
84+
curr_rockl = (curr_rockl & !new_rockl) >> 1;
8185
}
86+
rocks[i] = new_rockl;
87+
}
88+
}
8289

83-
for y in (0..input.h()).rev() {
84-
let mut last = input.w();
85-
for x in (0..input.w()).rev() {
86-
if input[(x, y)] == b'O' {
87-
last -= 1;
88-
input[(x, y)] = b'.';
89-
input[(last, y)] = b'O';
90-
} else if input[(x, y)] == b'#' {
91-
last = x;
92-
}
93-
}
94-
}
90+
fn load_of(rocks: &[u128]) -> usize {
91+
rocks
92+
.iter()
93+
.enumerate()
94+
.map(|(i, rockl)| rockl.count_ones() as usize * (rocks.len() - i - 1))
95+
.sum()
96+
}
97+
98+
pub fn part1(input: &Input) -> usize {
99+
let (rocks, walls) = input;
100+
let mut rocks = rocks.clone();
101+
move_north(&mut rocks, walls);
102+
load_of(&rocks)
103+
}
104+
105+
pub fn part2(input: &Input) -> usize {
106+
let (rocks, walls) = input;
107+
let mut rocks = rocks.clone();
108+
109+
let mut seen = FxIndexMap::default();
110+
let mut curr = 0;
111+
while curr < 1000000000 {
112+
seen.insert(rocks.clone(), curr);
113+
114+
move_north(&mut rocks, walls);
115+
move_west(&mut rocks, walls);
116+
move_south(&mut rocks, walls);
117+
move_east(&mut rocks, walls);
95118

96119
curr += 1;
97120

98-
if let Some(&old) = seen.get(&input) {
121+
if let Some(&old) = seen.get(&rocks) {
99122
let cycle_len = curr - old;
100123
let cycle_offset = old;
101124
let answer = (1000000000 - cycle_offset) % cycle_len + cycle_offset;
102-
input = seen
103-
.drain()
125+
126+
rocks = seen
127+
.drain(..)
104128
.find(|&(_, i)| i == answer)
105-
.map(|(grid, _)| grid)
129+
.map(|(rocks, _)| rocks)
106130
.unwrap();
107131
break;
108132
}
109133
}
110134

111-
let mut tot = 0;
112-
for y in 0..input.h() {
113-
for x in 0..input.w() {
114-
if input[(x, y)] == b'O' {
115-
tot += input.h() - y;
116-
}
117-
}
118-
}
119-
tot
135+
load_of(&rocks)
120136
}

0 commit comments

Comments
 (0)