1use crate::util::grid::*;
10use crate::util::point::*;
11use std::mem::swap;
12
13const FLOOR: u8 = b'.';
14const DIRECTIONS: [Point; 8] = [
15 Point::new(-1, -1),
16 Point::new(0, -1),
17 Point::new(1, -1),
18 Point::new(-1, 0),
19 Point::new(1, 0),
20 Point::new(-1, 1),
21 Point::new(0, 1),
22 Point::new(1, 1),
23];
24
25struct Seat {
26 index: u16,
27 size: u8,
28 neighbors: [u16; 8],
29}
30
31impl Seat {
32 #[inline]
33 fn push(&mut self, index: u16) {
34 self.neighbors[self.size as usize] = index;
35 self.size += 1;
36 }
37}
38
39pub fn parse(input: &str) -> Grid<u8> {
40 Grid::parse(input)
41}
42
43pub fn part1(input: &Grid<u8>) -> u32 {
44 simulate(input, true, 4)
45}
46
47pub fn part2(input: &Grid<u8>) -> u32 {
48 simulate(input, false, 5)
49}
50
51pub fn simulate(input: &Grid<u8>, part_one: bool, limit: u8) -> u32 {
52 let width = input.width;
53 let height = input.height;
54 let mut seats = Vec::new();
55
56 for y in 0..height {
57 for x in 0..width {
58 let point = Point::new(x, y);
59 if input[point] == FLOOR {
60 continue;
61 }
62
63 let mut seat = Seat { index: (width * y + x) as u16, size: 0, neighbors: [0; 8] };
64
65 for direction in DIRECTIONS {
66 if part_one {
67 let next = point + direction;
68 if input.contains(next) && input[next] != FLOOR {
69 seat.push((width * next.y + next.x) as u16);
70 }
71 } else {
72 let mut next = point + direction;
73 while input.contains(next) {
74 if input[next] != FLOOR {
75 seat.push((width * next.y + next.x) as u16);
76 break;
77 }
78 next += direction;
79 }
80 }
81 }
82
83 seats.push(seat);
84 }
85 }
86
87 let mut current = vec![0; (width * height) as usize];
88 let mut next = vec![0; (width * height) as usize];
89 let mut change = true;
90
91 while change {
92 change = false;
93
94 for seat in &seats {
95 let index = seat.index as usize;
96 let mut total = 0;
97
98 for i in 0..seat.size {
99 total += current[seat.neighbors[i as usize] as usize];
100 }
101
102 if current[index] == 0 && total == 0 {
103 next[index] = 1;
104 change |= true;
105 } else if current[index] == 1 && total >= limit {
106 next[index] = 0;
107 change |= true;
108 } else {
109 next[index] = current[index];
110 }
111 }
112
113 swap(&mut current, &mut next);
114 }
115
116 current.iter().map(|&n| n as u32).sum()
117}