Skip to content

Commit e1d04ee

Browse files
committed
2017 day 22
1 parent eba0a5f commit e1d04ee

File tree

2 files changed

+117
-0
lines changed

2 files changed

+117
-0
lines changed

crates/year2017/src/day22.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
use utils::grid;
2+
use utils::prelude::*;
3+
4+
/// Simulating virus spread through a grid.
5+
#[derive(Clone, Debug)]
6+
pub struct Day22 {
7+
size: usize,
8+
grid: Vec<State>,
9+
}
10+
11+
#[derive(Copy, Clone, Debug, PartialEq)]
12+
enum State {
13+
// The enum discriminants are set such that:
14+
// - The next direction can be found by adding the current state and direction (mod 4)
15+
// - The next state in part 1 is found by adding 2 (mod 4), cycling between Clean and Infected
16+
// - The next state in part 2 is found by adding 1 (mod 4)
17+
// They must also match the From implementation
18+
Clean = 3,
19+
Weakened = 0,
20+
Infected = 1,
21+
Flagged = 2,
22+
}
23+
24+
#[derive(Copy, Clone, Debug)]
25+
enum Direction {
26+
// Discriminants must match the From implementation
27+
Up = 0,
28+
Right,
29+
Down,
30+
Left,
31+
}
32+
33+
const PADDING: usize = 250;
34+
35+
impl Day22 {
36+
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
37+
let (rows, cols, grid) = grid::from_str(input, |b| match b {
38+
b'.' => Some(State::Clean),
39+
b'#' => Some(State::Infected),
40+
_ => None,
41+
})?;
42+
if rows != cols || rows % 2 == 0 {
43+
return Err(InputError::new(input, 0, "expected odd size square grid"));
44+
}
45+
Ok(Self { size: rows, grid })
46+
}
47+
48+
#[must_use]
49+
pub fn part1(&self) -> u32 {
50+
self.simulate(10_000, |state| State::from(state as usize + 2))
51+
}
52+
53+
#[must_use]
54+
pub fn part2(&self) -> u32 {
55+
self.simulate(10_000_000, |state| State::from(state as usize + 1))
56+
}
57+
58+
fn simulate(&self, bursts: u32, next_state: impl Fn(State) -> State) -> u32 {
59+
let size = self.size + (2 * PADDING);
60+
let mut grid = vec![State::Clean; size * size];
61+
62+
for row in 0..self.size {
63+
let offset = ((PADDING + row) * size) + PADDING;
64+
grid[offset..offset + self.size]
65+
.copy_from_slice(&self.grid[row * self.size..(row + 1) * self.size]);
66+
}
67+
68+
let direction_offsets = [-(size as isize), 1, size as isize, -1];
69+
let mut direction = Direction::Up;
70+
let mut index = grid.len() / 2;
71+
72+
let mut infected_transitions = 0;
73+
for _ in 0..bursts {
74+
let state = grid[index];
75+
let next = next_state(state);
76+
77+
direction = Direction::from(state as usize + direction as usize);
78+
grid[index] = next;
79+
index = index.wrapping_add_signed(direction_offsets[direction as usize]);
80+
81+
infected_transitions += u32::from(next == State::Infected);
82+
}
83+
84+
infected_transitions
85+
}
86+
}
87+
88+
impl From<usize> for State {
89+
#[inline]
90+
fn from(value: usize) -> Self {
91+
match value % 4 {
92+
3 => State::Clean,
93+
0 => State::Weakened,
94+
1 => State::Infected,
95+
2 => State::Flagged,
96+
_ => unreachable!(),
97+
}
98+
}
99+
}
100+
101+
impl From<usize> for Direction {
102+
#[inline]
103+
fn from(value: usize) -> Self {
104+
match value % 4 {
105+
0 => Direction::Up,
106+
1 => Direction::Right,
107+
2 => Direction::Down,
108+
3 => Direction::Left,
109+
_ => unreachable!(),
110+
}
111+
}
112+
}
113+
114+
examples!(Day22 -> (u32, u32) [
115+
{input: "..#\n#..\n...", part1: 5587, part2: 2511944},
116+
]);

crates/year2017/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,5 @@ utils::year!(2017 => year2017, ${
2525
19 => day19::Day19,
2626
20 => day20::Day20,
2727
21 => day21::Day21,
28+
22 => day22::Day22,
2829
});

0 commit comments

Comments
 (0)