1use std::ops::{BitAnd, BitOr, Not};
19
20#[derive(Clone, Copy, Default)]
22pub struct U256 {
23 left: u128,
24 right: u128,
25}
26
27impl U256 {
28 fn bit_set(&mut self, offset: usize) {
29 if offset < 128 {
30 self.right |= 1 << offset;
31 } else {
32 self.left |= 1 << (offset - 128);
33 }
34 }
35
36 fn non_zero(&self) -> bool {
37 self.left != 0 || self.right != 0
38 }
39
40 fn left_roll(&self, width: usize) -> U256 {
42 if width <= 128 {
43 let mask = !(1 << width);
44 let right = ((self.right << 1) & mask) | (self.right >> (width - 1));
45 U256 { left: self.left, right }
46 } else {
47 let mask = !(1 << (width - 128));
48 let left = ((self.left << 1) & mask) | (self.right >> 127);
49 let right = (self.right << 1) | (self.left >> (width - 129));
50 U256 { left, right }
51 }
52 }
53
54 fn right_roll(&self, width: usize) -> U256 {
56 if width <= 128 {
57 let right = (self.right >> 1) | ((self.right & 1) << (width - 1));
58 U256 { left: self.left, right }
59 } else {
60 let left = (self.left >> 1) | ((self.right & 1) << (width - 129));
61 let right = (self.right >> 1) | ((self.left & 1) << 127);
62 U256 { left, right }
63 }
64 }
65}
66
67impl BitAnd for U256 {
69 type Output = U256;
70
71 fn bitand(self, rhs: U256) -> U256 {
72 U256 { left: self.left & rhs.left, right: self.right & rhs.right }
73 }
74}
75
76impl BitOr for U256 {
77 type Output = U256;
78
79 fn bitor(self, rhs: U256) -> U256 {
80 U256 { left: self.left | rhs.left, right: self.right | rhs.right }
81 }
82}
83
84impl Not for U256 {
85 type Output = U256;
86
87 fn not(self) -> U256 {
88 U256 { left: !self.left, right: !self.right }
89 }
90}
91
92#[derive(Clone)]
93pub struct State {
94 width: usize,
95 height: usize,
96 across: Vec<U256>,
97 down: Vec<U256>,
98}
99
100pub fn parse(input: &str) -> State {
102 let raw: Vec<&[u8]> = input.lines().map(str::as_bytes).collect();
103 let width = raw[0].len();
104 let height = raw.len();
105 let mut across = Vec::new();
106 let mut down = Vec::new();
107
108 for row in raw {
109 let mut next_across = U256::default();
110 let mut next_down = U256::default();
111
112 for (offset, &col) in row.iter().enumerate() {
113 match col {
114 b'>' => next_across.bit_set(offset),
115 b'v' => next_down.bit_set(offset),
116 _ => (),
117 }
118 }
119
120 across.push(next_across);
121 down.push(next_down);
122 }
123
124 State { width, height, across, down }
125}
126
127pub fn part1(input: &State) -> usize {
128 let State { width, height, mut across, mut down } = input.clone();
129 let mut changed = true;
130 let mut count = 0;
131
132 while changed {
133 changed = false;
134 count += 1;
135
136 for i in 0..height {
139 let candidates = across[i].left_roll(width);
140 let moved = candidates & !(across[i] | down[i]);
141 changed |= moved.non_zero();
142 let stay = across[i] & !moved.right_roll(width);
143 across[i] = moved | stay;
144 }
145
146 let last_mask = across[0] | down[0];
148 let mut moved = down[height - 1] & !last_mask;
149
150 for i in 0..(height - 1) {
151 changed |= moved.non_zero();
152 let mask = across[i + 1] | down[i + 1];
153 let stay = down[i] & mask;
154 let next_moved = down[i] & !mask;
155 down[i] = moved | stay;
156 moved = next_moved;
157 }
158
159 changed |= moved.non_zero();
160 let stay = down[height - 1] & last_mask;
161 down[height - 1] = moved | stay;
162 }
163
164 count
165}
166
167pub fn part2(_input: &State) -> &'static str {
168 "n/a"
169}