1use crate::util::parse::*;
9use crate::util::thread::*;
10
11pub struct Result {
12 size: usize,
13 x: usize,
14 y: usize,
15 power: i32,
16}
17
18pub fn parse(input: &str) -> Vec<Result> {
19 let grid_serial_number: i32 = input.signed();
20
21 let mut sat = vec![0; 301 * 301 + 32];
23
24 for y in 1..301 {
25 for x in 1..301 {
26 let rack_id = x + 10;
27 let power_level = ((rack_id * y + grid_serial_number) * rack_id / 100) % 10 - 5;
28
29 let index = (301 * y + x) as usize;
30 sat[index] = power_level + sat[index - 1] + sat[index - 301] - sat[index - 302];
31 }
32 }
33
34 let items: Vec<_> = (1..301).collect();
37 let result = spawn_parallel_iterator(&items, |iter| {
38 iter.map(|&size| square(&sat, size)).collect::<Vec<_>>()
39 });
40 result.into_iter().flatten().collect()
41}
42
43pub fn part1(input: &[Result]) -> String {
44 let Result { x, y, .. } = input.iter().find(|r| r.size == 3).unwrap();
45 format!("{x},{y}")
46}
47
48pub fn part2(input: &[Result]) -> String {
49 let Result { size, x, y, .. } = input.iter().max_by_key(|r| r.power).unwrap();
50 format!("{x},{y},{size}")
51}
52
53#[cfg(not(feature = "simd"))]
55fn square(sat: &[i32], size: usize) -> Result {
56 let mut max_power = i32::MIN;
57 let mut max_x = 0;
58 let mut max_y = 0;
59
60 for y in size..301 {
61 for x in size..301 {
62 let index = 301 * y + x;
63
64 let power =
65 sat[index] - sat[index - size] - sat[index - 301 * size] + sat[index - 302 * size];
66
67 if power > max_power {
68 max_power = power;
69 max_x = x - size + 1;
70 max_y = y - size + 1;
71 }
72 }
73 }
74
75 Result { size, x: max_x, y: max_y, power: max_power }
76}
77
78#[cfg(feature = "simd")]
80fn square(sat: &[i32], size: usize) -> Result {
81 use std::simd::cmp::SimdPartialOrd as _;
82 use std::simd::*;
83
84 const LANE_WIDTH: usize = 16;
85 type Vector = Simd<i32, LANE_WIDTH>;
86
87 let mut max_power = i32::MIN;
88 let mut max_x = 0;
89 let mut max_y = 0;
90
91 for y in size..301 {
92 for x in (size..301).step_by(LANE_WIDTH) {
93 let index = 301 * y + x;
94
95 let power: Vector = Simd::from_slice(&sat[index..])
96 - Simd::from_slice(&sat[index - size..])
97 - Simd::from_slice(&sat[index - 301 * size..])
98 + Simd::from_slice(&sat[index - 302 * size..]);
99
100 if power.simd_gt(Simd::splat(max_power)).any() {
101 let limit = 301 - x;
102 for (offset, power) in power.to_array().into_iter().enumerate().take(limit) {
103 if power > max_power {
104 max_power = power;
105 max_x = x - size + 1 + offset;
106 max_y = y - size + 1;
107 }
108 }
109 }
110 }
111 }
112
113 Result { size, x: max_x, y: max_y, power: max_power }
114}