aoc/year2017/day22.rs
1//! # Sporifica Virus
2//!
3//! Brute force solution using a fixed size grid, relying on the properties of the input to never
4//! exceed the bounds. Some bit manipulation tricks are used to speeds things up slightly.
5use crate::util::grid::*;
6use crate::util::point::*;
7
8pub fn parse(input: &str) -> Grid<u8> {
9 Grid::parse(input)
10}
11
12pub fn part1(input: &Grid<u8>) -> usize {
13 simulate(input, 10_000, 2)
14}
15
16pub fn part2(input: &Grid<u8>) -> usize {
17 simulate(input, 10_000_000, 1)
18}
19
20fn simulate(input: &Grid<u8>, bursts: usize, delta: usize) -> usize {
21 // Assume that the carrier will never go outside the range [0, 512] in both x and y axis.
22 // starting at the center (256, 256).
23 let full = 512;
24 let half = 256;
25 // Right, Down, Left, Up
26 let offsets = [1, full, 0_usize.wrapping_sub(1), 0_usize.wrapping_sub(full)];
27
28 // Copy input
29 let mut grid = vec![1; full * full];
30 let offset = half - (input.width / 2) as usize;
31
32 for x in 0..input.width {
33 for y in 0..input.height {
34 if input[Point::new(x, y)] == b'#' {
35 let index = full * (offset + y as usize) + (offset + x as usize);
36 grid[index] = 3; // Infected
37 }
38 }
39 }
40
41 let mut index = full * half + half; // Center
42 let mut direction = 3; // Up
43 let mut result = 0;
44
45 for _ in 0..bursts {
46 // Change state by adding either `2` for part one (flipping between clean and infected)
47 // or `1` for part two (using all four states).
48 // Clean => 1
49 // Weakened => 2
50 // Infected => 3
51 // Flagged => 0
52 let current = grid[index] as usize;
53 let next = (current + delta) & 0x3;
54 grid[index] = next as u8;
55 // Infected nodes result in a value of 4 >> 2 = 1, all other nodes result in 0.
56 result += (next + 1) >> 2;
57 // Change direction by adding an index modulo 4 depending on node type.
58 // Clean => 1 + 2 => 3 (left)
59 // Weakened => 2 + 2 => 0 (straight)
60 // Infected => 3 + 2 => 1 (right)
61 // Flagged => 0 + 2 => 2 (reverse)
62 direction = (direction + current + 2) & 0x3;
63 index = index.wrapping_add(offsets[direction]);
64 }
65
66 result
67}