Skip to content

Commit

Permalink
[2024] Added Day 20 documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
ACSimon33 committed Dec 26, 2024
1 parent 99bd63f commit 777a008
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 166 deletions.
4 changes: 2 additions & 2 deletions 2024/20/race_condition/benchmarks/puzzle_benchmarks.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ const puzzle_input = @embedFile("puzzle_input");

// Benchmark of part 1
fn task_1(allocator: std.mem.Allocator) void {
_ = race_condition.solution_1(puzzle_input, 100, allocator) catch {};
_ = race_condition.amount_of_shortcuts(puzzle_input, 2, 100, allocator) catch {};
}

// Benchmark of part 2
fn task_2(allocator: std.mem.Allocator) void {
_ = race_condition.solution_2(puzzle_input, 100, allocator) catch {};
_ = race_condition.amount_of_shortcuts(puzzle_input, 20, 100, allocator) catch {};
}

pub fn main() !void {
Expand Down
13 changes: 9 additions & 4 deletions 2024/20/race_condition/src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,26 @@ pub fn main() !void {
var min_shortcut: usize = undefined;
if (matches.getSingleValue("shortcut")) |shortcut| {
min_shortcut = try std.fmt.parseInt(usize, shortcut, 10);
} else {
try app.displayHelp();
return;
}

const result_1 = race_condition.solution_1(
const result_1 = race_condition.amount_of_shortcuts(
file_content,
2,
min_shortcut,
allocator,
);
try stdout.print("1. Solution: {!}\n", .{result_1});
try stdout.print("Amount of shortcuts with a range of 2: {!}\n", .{result_1});
try bw.flush();

const result_2 = race_condition.solution_2(
const result_2 = race_condition.amount_of_shortcuts(
file_content,
20,
min_shortcut,
allocator,
);
try stdout.print("2. Solution: {!}\n", .{result_2});
try stdout.print("Amount of shortcuts with a range of 20: {!}\n", .{result_2});
try bw.flush();
}
233 changes: 101 additions & 132 deletions 2024/20/race_condition/src/race_condition.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,183 +3,159 @@ const Allocator = std.mem.Allocator;
const ArrayList = std.ArrayList;
const string = []const u8;

/// Task 1 -
/// Task 1 & 2 - Calculate the amount of possible shortcuts that are possible
/// with the given shortcut range and are larger than the given
/// shortcut length.
///
/// Arguments:
/// - `contents`: Input file contents.
/// - `shortcut_range`: Range for that collision detection is disabled.
/// - `min_shortcut`: Minimal shortcut length.
/// - `main_allocator`: Base allocator for everything.
///
/// Returns:
/// - Solution for task 1.
pub fn solution_1(contents: string, min_shortcut: usize, main_allocator: Allocator) !u32 {
/// - Amount of possible shortcuts.
pub fn amount_of_shortcuts(
contents: string,
shortcut_range: usize,
min_shortcut: usize,
main_allocator: Allocator,
) !u32 {
var arena = std.heap.ArenaAllocator.init(main_allocator);
defer arena.deinit();

const allocator = arena.allocator();
const racetrack = try parse(contents, allocator);
return racetrack.count_shortcuts(shortcut_range, min_shortcut);
}

var shortcuts: u32 = 0;
for (racetrack.track.items, 0..) |position_1, distance1| {
const x = position_1 % racetrack.width;
const y = position_1 / racetrack.width;

if (x > 1 and racetrack.grid.items[position_1 - 1] == null) {
if (racetrack.grid.items[position_1 - 2]) |distance2| {
if (distance2 > distance1 + min_shortcut + 1) {
shortcuts += 1;
}
}
}
// -------------------------------------------------------------------------- \\

if (x < racetrack.width - 2 and racetrack.grid.items[position_1 + 1] == null) {
if (racetrack.grid.items[position_1 + 2]) |distance2| {
if (distance2 > distance1 + min_shortcut + 1) {
shortcuts += 1;
}
}
}
const Racetrack = struct {
track: ArrayList(usize),
grid: ArrayList(?usize),
width: usize,
height: usize,

if (y > 1 and racetrack.grid.items[position_1 - racetrack.width] == null) {
if (racetrack.grid.items[position_1 - 2 * racetrack.width]) |distance2| {
if (distance2 > distance1 + min_shortcut + 1) {
shortcuts += 1;
}
}
}
/// Initialize a racetrack object with a grid with the given size.
///
/// Arguments:
/// - `width`: Width of the grid.
/// - `height`: Height of the grid.
/// - `allocator`: Allocator for the containers.
///
/// Returns:
/// - Racetrack object.
fn init(width: usize, height: usize, allocator: Allocator) !Racetrack {
var grid = ArrayList(?usize).init(allocator);
try grid.resize(width * height);

if (y < racetrack.height - 2 and racetrack.grid.items[position_1 + racetrack.width] == null) {
if (racetrack.grid.items[position_1 + 2 * racetrack.width]) |distance2| {
if (distance2 > distance1 + min_shortcut + 1) {
shortcuts += 1;
}
}
}
return Racetrack{
.track = ArrayList(usize).init(allocator),
.grid = grid,
.width = width,
.height = height,
};
}

return shortcuts;
}

/// Task 2 -
///
/// Arguments:
/// - `contents`: Input file contents.
/// - `main_allocator`: Base allocator for everything.
///
/// Returns:
/// - Solution for task 2.
pub fn solution_2(contents: string, min_shortcut: usize, main_allocator: Allocator) !usize {
var arena = std.heap.ArenaAllocator.init(main_allocator);
defer arena.deinit();

const allocator = arena.allocator();
const racetrack = try parse(contents, allocator);

var shortcuts: u32 = 0;
for (racetrack.track.items, 0..) |position_1, distance1| {
const x = position_1 % racetrack.width;
const y = position_1 / racetrack.width;

for (0..21) |cheat_x| {
if (x >= cheat_x) {
const position_2 = position_1 - cheat_x;
if (racetrack.grid.items[position_2]) |distance2| {
if (distance2 > distance1 + min_shortcut + cheat_x - 1) {
shortcuts += 1;
/// Count the amount of shortcuts that are possible with the given shortcut
/// range and a are larger than the minimal shortcut length.
///
/// Arguments:
/// - `self`: The racetrack object.
/// - `shortcut_range`: Range for that collision detection is disabled.
/// - `min_shortcut`: Minimal shortcut length.
///
/// Returns:
/// - Amount of possible shortcuts.
fn count_shortcuts(self: Racetrack, shortcut_range: usize, min_shortcut: usize) u32 {
var shortcuts: u32 = 0;
for (self.track.items, 0..) |position_1, distance1| {
const x = position_1 % self.width;
const y = position_1 / self.width;

for (0..shortcut_range + 1) |cheat_x| {
if (x >= cheat_x) {
const position_2 = position_1 - cheat_x;
if (self.grid.items[position_2]) |distance2| {
if (distance2 > distance1 + min_shortcut + cheat_x - 1) {
shortcuts += 1;
}
}
}
for (1..(21 - cheat_x)) |cheat_y| {
if (y >= cheat_y) {
const position_3 = position_2 - cheat_y * racetrack.width;
if (racetrack.grid.items[position_3]) |distance2| {
if (distance2 > distance1 + min_shortcut + cheat_x + cheat_y - 1) {
shortcuts += 1;
for (1..(shortcut_range + 1 - cheat_x)) |cheat_y| {
if (y >= cheat_y) {
const position_3 = position_2 - cheat_y * self.width;
if (self.grid.items[position_3]) |distance2| {
if (distance2 > distance1 + min_shortcut + cheat_x + cheat_y - 1) {
shortcuts += 1;
}
}
}
}

if (y + cheat_y <= racetrack.height - 1) {
const position_3 = position_2 + cheat_y * racetrack.width;
if (racetrack.grid.items[position_3]) |distance2| {
if (distance2 > distance1 + min_shortcut + cheat_x + cheat_y - 1) {
shortcuts += 1;
if (y + cheat_y <= self.height - 1) {
const position_3 = position_2 + cheat_y * self.width;
if (self.grid.items[position_3]) |distance2| {
if (distance2 > distance1 + min_shortcut + cheat_x + cheat_y - 1) {
shortcuts += 1;
}
}
}
}
}
}
if (cheat_x == 0) {
continue;
}
if (cheat_x == 0) {
continue;
}

if (x + cheat_x <= racetrack.width - 1) {
const position_2 = position_1 + cheat_x;
if (racetrack.grid.items[position_2]) |distance2| {
if (distance2 > distance1 + min_shortcut + cheat_x - 1) {
shortcuts += 1;
if (x + cheat_x <= self.width - 1) {
const position_2 = position_1 + cheat_x;
if (self.grid.items[position_2]) |distance2| {
if (distance2 > distance1 + min_shortcut + cheat_x - 1) {
shortcuts += 1;
}
}
}

for (1..(21 - cheat_x)) |cheat_y| {
if (y >= cheat_y) {
const position_3 = position_2 - cheat_y * racetrack.width;
if (racetrack.grid.items[position_3]) |distance2| {
if (distance2 > distance1 + min_shortcut + cheat_x + cheat_y - 1) {
shortcuts += 1;
for (1..(shortcut_range + 1 - cheat_x)) |cheat_y| {
if (y >= cheat_y) {
const position_3 = position_2 - cheat_y * self.width;
if (self.grid.items[position_3]) |distance2| {
if (distance2 > distance1 + min_shortcut + cheat_x + cheat_y - 1) {
shortcuts += 1;
}
}
}
}

if (y + cheat_y <= racetrack.height - 1) {
const position_3 = position_2 + cheat_y * racetrack.width;
if (racetrack.grid.items[position_3]) |distance2| {
if (distance2 > distance1 + min_shortcut + cheat_x + cheat_y - 1) {
shortcuts += 1;
if (y + cheat_y <= self.height - 1) {
const position_3 = position_2 + cheat_y * self.width;
if (self.grid.items[position_3]) |distance2| {
if (distance2 > distance1 + min_shortcut + cheat_x + cheat_y - 1) {
shortcuts += 1;
}
}
}
}
}
}
}
}

return shortcuts;
}

// -------------------------------------------------------------------------- \\

const Racetrack = struct {
track: ArrayList(usize),
grid: ArrayList(?usize),
width: usize,
height: usize,

fn init(width: usize, height: usize, allocator: Allocator) !Racetrack {
var grid = ArrayList(?usize).init(allocator);
try grid.resize(width * height);

return Racetrack{
.track = ArrayList(usize).init(allocator),
.grid = grid,
.width = width,
.height = height,
};
return shortcuts;
}
};

/// Parse the file contents into a list of reports.
/// Parse the file contents into a racetrack object.
///
/// Arguments:
/// - `contents`: Input file contents.
/// - `allocator`: Allocator for the containers.
///
/// Returns:
/// - Array list of report objects.
/// - Racetrack object.
fn parse(contents: string, allocator: Allocator) !Racetrack {
var lines = std.mem.tokenize(u8, contents, "\r\n");
const height: usize = @intCast(std.mem.count(u8, contents, &[1]u8{'\n'}) + 1);
const width: usize = lines.peek().?.len;
var racetrack = try Racetrack.init(width, height, allocator);

// Parse grid (wall = null, path = 0)
var start: usize = undefined;
var end: usize = undefined;
var idx: usize = 0;
Expand All @@ -200,6 +176,7 @@ fn parse(contents: string, allocator: Allocator) !Racetrack {
}
}

// Find the path from start to end
try racetrack.track.append(start);
var position = start;
while (position != end) {
Expand All @@ -208,38 +185,30 @@ fn parse(contents: string, allocator: Allocator) !Racetrack {

var new_pos: usize = undefined;
if (x > 0) {
// std.debug.print("Left: {any}\n", .{racetrack.grid.items[position - 1]});
if (racetrack.grid.items[position - 1]) |next| {
if (next == 0 and position - 1 != start) {
new_pos = position - 1;
// std.debug.print("Left: {} {}\n", .{ position, new_pos });
}
}
}
if (x < width - 1) {
// std.debug.print("Right: {any}\n", .{racetrack.grid.items[position + 1]});
if (racetrack.grid.items[position + 1]) |next| {
if (next == 0 and position + 1 != start) {
new_pos = position + 1;
// std.debug.print("Right: {} {}\n", .{ position, new_pos });
}
}
}
if (y > 0) {
// std.debug.print("Up: {any}\n", .{racetrack.grid.items[position - width]});
if (racetrack.grid.items[position - width]) |next| {
if (next == 0 and position - width != start) {
new_pos = position - width;
// std.debug.print("Up: {} {}\n", .{ position, new_pos });
}
}
}
if (y < height - 1) {
// std.debug.print("Down: {any}\n", .{racetrack.grid.items[position + width]});
if (racetrack.grid.items[position + width]) |next| {
if (next == 0 and position + width != start) {
new_pos = position + width;
// std.debug.print("Down: {} {}\n", .{ position, new_pos });
}
}
}
Expand Down
Loading

0 comments on commit 777a008

Please sign in to comment.