aboutsummaryrefslogtreecommitdiffstats
path: root/day14
diff options
context:
space:
mode:
Diffstat (limited to 'day14')
-rw-r--r--day14/example.txt10
-rw-r--r--day14/solution.zig181
2 files changed, 191 insertions, 0 deletions
diff --git a/day14/example.txt b/day14/example.txt
new file mode 100644
index 0000000..5a24dce
--- /dev/null
+++ b/day14/example.txt
@@ -0,0 +1,10 @@
1O....#....
2O.OO#....#
3.....##...
4OO.#O....O
5.O.....O#.
6O.#..O.#.#
7..O..#O..O
8.......O..
9#....###..
10#OO..#....
diff --git a/day14/solution.zig b/day14/solution.zig
new file mode 100644
index 0000000..5509bdc
--- /dev/null
+++ b/day14/solution.zig
@@ -0,0 +1,181 @@
1const std = @import("std");
2const print = std.debug.print;
3const assert = std.debug.assert;
4const ArrayList = std.ArrayList;
5const HashMap = std.HashMap;
6const mem = std.mem;
7
8const fin = mem.trim(u8, @embedFile("./input.txt"), &std.ascii.whitespace);
9var gpa = std.heap.GeneralPurposeAllocator(.{}){};
10const allocator = gpa.allocator();
11
12const Map = []const []u8;
13
14fn column_wise(map: Map, begin: isize, end: isize, step: isize) u64 {
15 const h = map.len;
16 const w = map[0].len;
17 var ans: u64 = 0;
18
19 for (0..w) |j| {
20 var next_free = begin;
21 var i = begin;
22 while (i != end) : (i += step) {
23 switch (map[@bitCast(i)][j]) {
24 '.' => {},
25 'O' => {
26 ans += h - @as(u64, @bitCast(next_free));
27 map[@bitCast(i)][j] = '.';
28 map[@bitCast(next_free)][j] = 'O';
29 next_free += step;
30 },
31 '#' => {
32 next_free = i + step;
33 },
34 else => unreachable,
35 }
36 }
37 }
38
39 return ans;
40}
41
42fn row_wise(map: Map, begin: isize, end: isize, step: isize) u64 {
43 const h = map.len;
44 var ans: u64 = 0;
45
46 for (0..h) |i| {
47 var next_free = begin;
48 var j = begin;
49 while (j != end) : (j += step) {
50 switch (map[i][@bitCast(j)]) {
51 '.' => {},
52 'O' => {
53 ans += h - i;
54 map[i][@bitCast(j)] = '.';
55 map[i][@bitCast(next_free)] = 'O';
56 next_free += step;
57 },
58 '#' => {
59 next_free = j + step;
60 },
61 else => unreachable,
62 }
63 }
64 }
65
66 return ans;
67}
68
69fn north(map: Map) u64 {
70 const h = map.len;
71 return column_wise(map, 0, @bitCast(h), 1);
72}
73
74fn west(map: Map) u64 {
75 const w = map[0].len;
76 return row_wise(map, 0, @bitCast(w), 1);
77}
78
79fn south(map: Map) u64 {
80 const h = map.len;
81 return column_wise(map, @bitCast(h - 1), -1, -1);
82}
83
84fn east(map: Map) u64 {
85 const w = map[0].len;
86 return row_wise(map, @bitCast(w - 1), -1, -1);
87}
88
89fn round(map: Map) u64 {
90 _ = north(map);
91 _ = west(map);
92 _ = south(map);
93 return east(map);
94}
95
96const MapCtx = struct {
97 pub fn hash(_: @This(), map: []const []u8) u64 {
98 var h: u64 = 0;
99
100 for (map, 0..) |row, i| {
101 for (row, 0..) |c, j| {
102 if (c == 'O') {
103 h ^= @shlExact(i, 16) | (j);
104 }
105 }
106 }
107 h *= 1231231557;
108 h ^= (h >> 32);
109 return h;
110 }
111
112 pub fn eql(_: @This(), lhs: []const []u8, rhs: []const []u8) bool {
113 for (lhs, rhs) |l, r| {
114 if (!mem.eql(u8, l, r)) {
115 return false;
116 }
117 }
118
119 return true;
120 }
121};
122
123fn mapdup(map: []const []const u8) Map {
124 const h = map.len;
125 const w = map[0].len;
126 const new = allocator.alloc([]u8, h) catch unreachable;
127
128 for (new, map) |*row, srcrow| {
129 row.* = allocator.alloc(u8, w) catch unreachable;
130 @memcpy(row.*, srcrow);
131 }
132
133 return new;
134}
135
136fn part1(map: []const []const u8) void {
137 const ans = north(mapdup(map));
138
139 print("{d}\n", .{ans});
140}
141
142fn part2(map_: []const []const u8) void {
143 var ans: u64 = 0;
144 var visited = HashMap(Map, u64, MapCtx, 80).init(allocator);
145 const map = mapdup(map_);
146 const reps = 1_000_000_000;
147 var upto: u64 = 0;
148
149 for (0..reps) |p| {
150 ans = round(map);
151 if (visited.get(map)) |s| {
152 const start = s;
153 const period = p - s;
154 upto = (reps - start - 1) % period;
155 break;
156 }
157 visited.put(mapdup(map), p) catch unreachable;
158 }
159
160 for (0..upto) |_| {
161 ans = round(map);
162 }
163
164 print("{d}\n", .{ans});
165}
166
167pub fn solve(map: []const []const u8) void {
168 part1(map);
169 part2(map);
170}
171
172pub fn main() !void {
173 var splitLines = mem.splitScalar(u8, fin, '\n');
174 var map = ArrayList([]const u8).init(allocator);
175
176 while (splitLines.next()) |line| {
177 try map.append(line);
178 }
179
180 solve(map.items);
181}