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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
const XMAS: &str = "XMAS";
const MAS: &str = "MAS";
type Matrix = Vec<Vec<char>>;
type Position = (usize, usize);
type RowXmas = [Position; XMAS.len()];
type RowMas = [Position; MAS.len()];
fn check_xmas<'a, I>(m: &Matrix, it: I) -> bool
where
I: Iterator<Item = &'a Position>,
{
for (c, (i, j)) in XMAS.chars().zip(it) {
if m[*i][*j] != c {
return false;
}
}
true
}
fn offplus(x: usize, y: isize) -> usize {
(x as isize + y) as usize
}
fn rows_latdiag_from(p: Position, max_x: usize, max_y: usize) -> Vec<RowXmas> {
let mut rs: Vec<RowXmas> = vec![];
// Horizontal / vertical / diagonal
for (p0, (di, dj)) in [
(p, (0, 1)), // horizontal, left-to-right
(p, (1, 0)), // vertical, top-down
(p, (1, 1)), // diag from p, top-down and left-to-right
((p.0, p.1 + XMAS.len() - 1), (1, -1isize)), // the other diag, top-down and right-to-left
] {
// Bounds check
let max_off = XMAS.len();
if p0.0 + di * max_off > max_x
|| (dj > 0 && offplus(p0.1, dj * max_off as isize) > max_y)
|| p0.1 >= max_y
{
continue;
}
let mut p_acc = p0;
let mut ps = [(0, 0); XMAS.len()];
for idx in 0..ps.len() {
ps[idx].0 = p_acc.0;
ps[idx].1 = p_acc.1;
p_acc = (p_acc.0 + di, offplus(p_acc.1, dj));
}
rs.push(ps);
}
rs
}
pub fn p1(input: &str) -> String {
let m: Matrix = input.lines().map(|row| row.chars().collect()).collect();
let mut result = 0;
for i in 0..m.len() {
for j in 0..m[i].len() {
let p = (i, j);
for row in rows_latdiag_from(p, m.len(), m[i].len()) {
if check_xmas(&m, row.iter()) || check_xmas(&m, row.iter().rev()) {
result += 1;
}
}
}
}
result.to_string()
}
fn check_mas<'a, I>(m: &Matrix, it: I) -> bool
where
I: Iterator<Item = &'a Position>,
{
for (c, (i, j)) in MAS.chars().zip(it) {
if m[*i][*j] != c {
return false;
}
}
true
}
fn rows_diag_from(p: Position, max_x: usize, max_y: usize) -> Vec<RowMas> {
let mut rs: Vec<RowMas> = vec![];
// Horizontal / vertical / diagonal
for (p0, (di, dj)) in [
(p, (1, 1)), // diag from p, top-down and left-to-right
((p.0, p.1 + MAS.len() - 1), (1, -1isize)), // the other diag, top-down and right-to-left
] {
// Bounds check
let max_off = MAS.len();
if p0.0 + di * max_off > max_x
|| (dj > 0 && offplus(p0.1, dj * max_off as isize) > max_y)
|| p0.1 >= max_y
{
continue;
}
let mut p_acc = p0;
let mut ps = [(0, 0); MAS.len()];
for idx in 0..ps.len() {
ps[idx].0 = p_acc.0;
ps[idx].1 = p_acc.1;
p_acc = (p_acc.0 + di, offplus(p_acc.1, dj));
}
rs.push(ps);
}
rs
}
pub fn p2(input: &str) -> String {
let m: Matrix = input.lines().map(|row| row.chars().collect()).collect();
let mut result = 0;
for i in 0..=m.len() - MAS.len() {
for j in 0..=m[i].len() - MAS.len() {
let p = (i, j);
let rows = rows_diag_from(p, m.len(), m[i].len());
if rows.iter().all(|r| check_mas(&m, r.iter()) || check_mas(&m, r.iter().rev())) {
result += 1;
}
}
}
result.to_string()
}
|