1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use crate::input::Input;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
#[derive(Copy, Clone, Eq, PartialEq)]
enum NodeFlag {
Weakened,
Infected,
Flagged,
}
const fn turn(direction: (i32, i32), right: bool) -> (i32, i32) {
if right {
(-direction.1, direction.0)
} else {
(direction.1, -direction.0)
}
}
const fn reverse(direction: (i32, i32)) -> (i32, i32) {
(-direction.0, -direction.1)
}
pub fn solve(input: &mut Input) -> Result<u32, String> {
let mut map = HashMap::new();
let mut cols = -1;
let mut rows = -1;
for (line_idx, line) in input.text.lines().enumerate() {
rows += 1;
for (char_idx, char) in line.chars().enumerate() {
if rows == 0 {
cols += 1;
}
if char == '#' {
map.insert((char_idx as i32, line_idx as i32), NodeFlag::Infected);
}
}
}
let mut carrier_position = (cols / 2 + cols % 2, rows / 2 + rows % 2);
let mut carrier_direction = (0, -1);
let mut bursts_causing_infection = 0;
for _burst in 0..input.part_values(10_000, 10_000_000) {
match map.entry(carrier_position) {
Entry::Vacant(entry) => {
carrier_direction = turn(carrier_direction, false);
if input.is_part_one() {
bursts_causing_infection += 1;
entry.insert(NodeFlag::Infected);
} else {
entry.insert(NodeFlag::Weakened);
}
}
Entry::Occupied(mut entry) => {
match entry.get() {
NodeFlag::Weakened => {
bursts_causing_infection += 1;
entry.insert(NodeFlag::Infected);
}
NodeFlag::Infected => {
carrier_direction = turn(carrier_direction, true);
if input.is_part_one() {
entry.remove();
} else {
entry.insert(NodeFlag::Flagged);
}
}
NodeFlag::Flagged => {
carrier_direction = reverse(carrier_direction);
entry.remove();
}
}
}
}
carrier_position = (
carrier_position.0 + carrier_direction.0,
carrier_position.1 + carrier_direction.1,
);
}
Ok(bursts_causing_infection)
}
#[test]
pub fn tests() {
use crate::{test_part_one, test_part_two};
let real_input = include_str!("day22_input.txt");
test_part_one!(real_input => 5246);
test_part_two!(real_input => 2_512_059);
}