Skip to content

Commit 8ef2e63

Browse files
committed
Added day 18 documentation
1 parent d877b03 commit 8ef2e63

File tree

4 files changed

+69
-19
lines changed

4 files changed

+69
-19
lines changed

2024/18/ram_run/benchmarks/puzzle_benchmarks.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ const puzzle_input = @embedFile("puzzle_input");
66

77
// Benchmark of part 1
88
fn task_1(allocator: std.mem.Allocator) void {
9-
_ = ram_run.solution_1(puzzle_input, 1024, allocator) catch {};
9+
_ = ram_run.steps_to_the_exit(puzzle_input, 1024, allocator) catch {};
1010
}
1111

1212
// Benchmark of part 2
1313
fn task_2(allocator: std.mem.Allocator) void {
14-
const result = ram_run.solution_2(
14+
const result = ram_run.position_of_blocking_byte(
1515
puzzle_input,
1616
allocator,
1717
) catch return;

2024/18/ram_run/src/main.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,19 +60,19 @@ pub fn main() !void {
6060
bytes = try std.fmt.parseInt(usize, bytes_str, 10);
6161
}
6262

63-
const result_1 = ram_run.solution_1(
63+
const result_1 = ram_run.steps_to_the_exit(
6464
file_content,
6565
bytes,
6666
allocator,
6767
);
68-
try stdout.print("1. Solution: {!}\n", .{result_1});
68+
try stdout.print("Number of steps to the exit: {!}\n", .{result_1});
6969
try bw.flush();
7070

71-
const result_2 = try ram_run.solution_2(
71+
const result_2 = try ram_run.position_of_blocking_byte(
7272
file_content,
7373
allocator,
7474
);
7575
defer allocator.free(result_2);
76-
try stdout.print("2. Solution: {s}\n", .{result_2});
76+
try stdout.print("Position of blocking byte: {s}\n", .{result_2});
7777
try bw.flush();
7878
}

2024/18/ram_run/src/ram_run.zig

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,22 @@ const string = []const u8;
66
// Dijkstra module
77
const dijkstra = @import("./dijkstra.zig");
88

9-
/// Task 1 -
9+
/// Task 1 - Simulate the falling bytes and calculate the shortest path from
10+
/// the top-left corner of the grid to the bottom-right corner.
1011
///
1112
/// Arguments:
1213
/// - `contents`: Input file contents.
14+
/// - `bytes`: Number of fallen bytes.
1315
/// - `main_allocator`: Base allocator for everything.
1416
///
1517
/// Returns:
16-
/// - Solution for task 1.
17-
pub fn solution_1(contents: string, bytes: usize, main_allocator: Allocator) !u32 {
18+
/// - Length of the shortest path.
19+
pub fn steps_to_the_exit(contents: string, bytes: usize, main_allocator: Allocator) !u32 {
1820
var arena = std.heap.ArenaAllocator.init(main_allocator);
1921
defer arena.deinit();
2022

2123
const allocator = arena.allocator();
22-
const ram = try parse(contents, allocator);
24+
const ram = try parse_ram(contents, allocator);
2325
const end = ram.width * ram.height - 1;
2426

2527
const nodes = try dijkstra.dijkstra(
@@ -34,22 +36,24 @@ pub fn solution_1(contents: string, bytes: usize, main_allocator: Allocator) !u3
3436
return nodes.items[end].distance;
3537
}
3638

37-
/// Task 2 -
39+
/// Task 2 - Find the position of the byte that will ultimately block the path
40+
/// between the top-left corner of the grid to the bottom-right corner.
3841
///
3942
/// Arguments:
4043
/// - `contents`: Input file contents.
4144
/// - `main_allocator`: Base allocator for everything.
4245
///
4346
/// Returns:
44-
/// - Solution for task 2.
45-
pub fn solution_2(contents: string, main_allocator: Allocator) !string {
47+
/// - Position of the blocking byte as a string.
48+
pub fn position_of_blocking_byte(contents: string, main_allocator: Allocator) !string {
4649
var arena = std.heap.ArenaAllocator.init(main_allocator);
4750
defer arena.deinit();
4851

4952
const allocator = arena.allocator();
50-
const ram = try parse(contents, allocator);
53+
const ram = try parse_ram(contents, allocator);
5154
const end = ram.width * ram.height - 1;
5255

56+
// Bisection
5357
var upper_bound = ram.falling_bytes.items.len - 1;
5458
var lower_bound: usize = 0;
5559
while (lower_bound + 1 < upper_bound) {
@@ -69,6 +73,7 @@ pub fn solution_2(contents: string, main_allocator: Allocator) !string {
6973
}
7074
}
7175

76+
// Convert position to string (what a pain ...)
7277
const x_str_size = std.math.log10(@max(ram.falling_bytes.items[lower_bound].x, 1)) + 1;
7378
const y_str_size = std.math.log10(@max(ram.falling_bytes.items[lower_bound].y, 1)) + 1;
7479
const str_size = 1 + x_str_size + y_str_size;
@@ -82,13 +87,23 @@ pub fn solution_2(contents: string, main_allocator: Allocator) !string {
8287

8388
// -------------------------------------------------------------------------- \\
8489

90+
/// 2D Position in a grid.
8591
const Position = struct { x: usize, y: usize };
8692

93+
/// RAM object that represents a quadratic grid of cells and a list of falling
94+
/// bytes which will block certain cells.
8795
const RAM = struct {
8896
falling_bytes: ArrayList(Position),
8997
width: usize,
9098
height: usize,
9199

100+
/// Init the RAM grid of undefined size.
101+
///
102+
/// Arguments:
103+
/// - `allocator`: Allocator list of falling bytes.
104+
///
105+
/// Returns:
106+
/// - The RAM object.
92107
fn init(allocator: Allocator) RAM {
93108
return RAM{
94109
.falling_bytes = ArrayList(Position).init(allocator),
@@ -97,6 +112,17 @@ const RAM = struct {
97112
};
98113
}
99114

115+
/// Create a graph representation of the RAM grid when the given number of
116+
/// bytes have fallen. First create a full graph with all nodes and then
117+
/// remove connections for each falling byte.
118+
///
119+
/// Arguments:
120+
/// - `self`: The RAM object.
121+
/// - `bytes`: Number of fallen bytes.
122+
/// - `allocator`: Allocator for the adjacency matrix.
123+
///
124+
/// Returns:
125+
/// - The adjacency matrix of the graph.
100126
fn create_adjacency_matrix(self: RAM, bytes: usize, allocator: Allocator) !ArrayList(?u32) {
101127
const nodes = self.width * self.height;
102128
var matrix = try self.create_safe_adjacency_matrix(allocator);
@@ -117,6 +143,15 @@ const RAM = struct {
117143
return matrix;
118144
}
119145

146+
/// Create a graph representation of the RAM grid when no bytes have fallen
147+
/// yet.
148+
///
149+
/// Arguments:
150+
/// - `self`: The RAM object.
151+
/// - `allocator`: Allocator for the adjacency matrix.
152+
///
153+
/// Returns:
154+
/// - The adjacency matrix of the graph.
120155
fn create_safe_adjacency_matrix(self: RAM, allocator: Allocator) !ArrayList(?u32) {
121156
const nodes = self.width * self.height;
122157
var matrix = ArrayList(?u32).init(allocator);
@@ -133,6 +168,15 @@ const RAM = struct {
133168
return matrix;
134169
}
135170

171+
/// Check if a certain cell/node is a neighbour of another cell/node
172+
///
173+
/// Arguments:
174+
/// - `self`: The RAM object.
175+
/// - `node1`: Position of the first cell/node.
176+
/// - `node2`: Position of the second cell/node.
177+
///
178+
/// Returns:
179+
/// - True if the two cells/nodes are neighbours.
136180
fn is_neighbour_cell(self: RAM, node1: usize, node2: usize) bool {
137181
const x1 = node1 % self.width;
138182
const y1 = node1 / self.width;
@@ -141,6 +185,11 @@ const RAM = struct {
141185
return (y1 == y2 and (x1 == x2 + 1 or x1 + 1 == x2)) or (x1 == x2 and (y1 == y2 + 1 or y1 + 1 == y2));
142186
}
143187

188+
/// Print the current RAM grid.
189+
///
190+
/// Arguments:
191+
/// - `self`: The RAM object.
192+
/// - `bytes`: Number of bytes that have fallen.
144193
fn print(self: RAM, bytes: usize) void {
145194
for (0..self.height) |y| {
146195
for (0..self.width) |x| {
@@ -162,15 +211,16 @@ const RAM = struct {
162211
}
163212
};
164213

165-
/// Parse the file contents into a list of reports.
214+
/// Parse the file contents into a RAM grid of a crertain size and a list of
215+
/// positions of falling byte.
166216
///
167217
/// Arguments:
168218
/// - `contents`: Input file contents.
169219
/// - `allocator`: Allocator for the containers.
170220
///
171221
/// Returns:
172-
/// - Array list of report objects.
173-
fn parse(contents: string, allocator: Allocator) !RAM {
222+
/// - The RAM oject.
223+
fn parse_ram(contents: string, allocator: Allocator) !RAM {
174224
var ram = RAM.init(allocator);
175225

176226
var lines = std.mem.tokenize(u8, contents, "\r\n");

2024/18/ram_run/tests/example_tests.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ test "task_1" {
77
const example_input = @embedFile("example_input");
88
try testing.expectEqual(
99
22,
10-
ram_run.solution_1(example_input, 12, std.testing.allocator),
10+
ram_run.steps_to_the_exit(example_input, 12, std.testing.allocator),
1111
);
1212
}
1313

1414
// Test of part 2
1515
test "task_2" {
1616
const example_input = @embedFile("example_input");
17-
const result = try ram_run.solution_2(example_input, std.testing.allocator);
17+
const result = try ram_run.position_of_blocking_byte(example_input, std.testing.allocator);
1818
defer std.testing.allocator.free(result);
1919

2020
try testing.expectEqualStrings(

0 commit comments

Comments
 (0)