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
|
const std = @import("std");
fn cast(n: usize) i32 {
return @intCast(n);
}
const Input = struct {
buf: []const u8,
w: usize,
h: usize,
pub fn at(self: Input, x: i32, y: i32) ?u8 {
if (x < 0 or x >= self.w or y < 0 or y >= self.h) return null;
return self.buf[@intCast(y * (@as(i32, @intCast(self.w)) + 1) + x)];
}
};
pub fn parse(_: std.mem.Allocator, data: []const u8) !Input {
const width = std.mem.indexOf(u8, data, "\n") orelse return error.InvalidInput;
const height = data.len / (width + 1);
std.debug.assert((width + 1) * height == data.len);
return .{ .buf = data, .w = width, .h = height };
}
test "part1" {
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
defer arena.deinit();
const output = try part1(arena.allocator(), try parse(arena.allocator(),
\\MMMSXXMASM
\\MSAMXMSMSA
\\AMXSXMAAMM
\\MSAMASMSMX
\\XMASAMXAMM
\\XXAMMXXAMA
\\SMSMSASXSS
\\SAXAMASAAA
\\MAMMMXMMMM
\\MXMXAXMASX
\\
));
std.debug.print("got {}\n", .{output});
std.debug.assert(output == 18);
}
pub fn part1(_: std.mem.Allocator, input: Input) !u32 {
var count: u32 = 0;
for (0..input.h) |y| for (0..input.w) |x| for ([_]@Vector(2, i32){
.{ 1, 0 },
.{ 1, -1 },
.{ 0, -1 },
.{ -1, -1 },
.{ -1, 0 },
.{ -1, 1 },
.{ 0, 1 },
.{ 1, 1 },
}) |dir| {
for (0.., "XMAS") |dist, c| {
if (input.at(cast(x) + dir[0] * cast(dist), cast(y) + cast(dist) * dir[1]) != c) {
break;
}
} else {
count += 1;
}
};
return count;
}
test "part2" {
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
defer arena.deinit();
const output = try part2(arena.allocator(), try parse(arena.allocator(),
\\MMMSXXMASM
\\MSAMXMSMSA
\\AMXSXMAAMM
\\MSAMASMSMX
\\XMASAMXAMM
\\XXAMMXXAMA
\\SMSMSASXSS
\\SAXAMASAAA
\\MAMMMXMMMM
\\MXMXAXMASX
\\
));
std.debug.print("got {}\n", .{output});
std.debug.assert(output == 9);
}
fn isOther(a: ?u8, b: ?u8) bool {
return switch (a orelse return false) {
'M' => b == 'S',
'S' => b == 'M',
else => false,
};
}
pub fn part2(_: std.mem.Allocator, input: Input) !u32 {
var count: u32 = 0;
for (0..input.h) |y| for (0..input.w) |x| {
if (input.at(cast(x), cast(y)) != 'A') continue;
if (!isOther(input.at(cast(x) - 1, cast(y) - 1), input.at(cast(x) + 1, cast(y) + 1))) continue;
if (!isOther(input.at(cast(x) + 1, cast(y) - 1), input.at(cast(x) - 1, cast(y) + 1))) continue;
count += 1;
};
return count;
}
|