Skip to content

Commit 054f0ad

Browse files
committed
[2024] Added Day 03: Mull It Over
1 parent 5913548 commit 054f0ad

File tree

11 files changed

+358
-0
lines changed

11 files changed

+358
-0
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const std = @import("std");
2+
const zbench = @import("zbench");
3+
const mull_it_over = @import("mull_it_over");
4+
5+
const puzzle_input = @embedFile("puzzle_input");
6+
7+
// Benchmark of part 1
8+
fn task_1(_: std.mem.Allocator) void {
9+
_ = mull_it_over.sum_of_multiplication_instructions(puzzle_input) catch {};
10+
}
11+
12+
// Benchmark of part 2
13+
fn task_2(_: std.mem.Allocator) void {
14+
_ = mull_it_over.conditional_sum_of_multiplication_instructions(puzzle_input) catch {};
15+
}
16+
17+
pub fn main() !void {
18+
const stdout = std.io.getStdOut().writer();
19+
var bench = zbench.Benchmark.init(std.heap.page_allocator, .{});
20+
defer bench.deinit();
21+
22+
try bench.add("Day 03 - Task 1", task_1, .{});
23+
try bench.add("Day 03 - Task 2", task_2, .{});
24+
25+
try stdout.writeAll("\n");
26+
try bench.run(stdout);
27+
}

2024/03/mull_it_over/build.zig

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
const std = @import("std");
2+
3+
pub fn build(b: *std.Build) void {
4+
const target = b.standardTargetOptions(.{});
5+
const optimize = b.standardOptimizeOption(.{});
6+
7+
// -------------------------- Solution module --------------------------- \\
8+
const mull_it_over = b.addModule("mull_it_over", .{
9+
.root_source_file = b.path("src/mull_it_over.zig"),
10+
});
11+
12+
// -------------------------- Main executable --------------------------- \\
13+
const mull_it_over_exe = b.addExecutable(.{
14+
.name = "mull_it_over",
15+
.root_source_file = b.path("src/main.zig"),
16+
.target = target,
17+
.optimize = optimize,
18+
});
19+
20+
const yazap = b.dependency("yazap", .{});
21+
mull_it_over_exe.root_module.addImport("yazap", yazap.module("yazap"));
22+
mull_it_over_exe.root_module.addImport("mull_it_over", mull_it_over);
23+
b.installArtifact(mull_it_over_exe);
24+
25+
const run_cmd = b.addRunArtifact(mull_it_over_exe);
26+
run_cmd.step.dependOn(b.getInstallStep());
27+
if (b.args) |args| {
28+
run_cmd.addArgs(args);
29+
}
30+
31+
const run_step = b.step("run", "Run the mull_it_over (day 03) app");
32+
run_step.dependOn(&run_cmd.step);
33+
34+
// --------------------------- Example tests ---------------------------- \\
35+
const mull_it_over_tests = b.addTest(.{
36+
.name = "mull_it_over_tests",
37+
.root_source_file = b.path("tests/example_tests.zig"),
38+
.target = target,
39+
.optimize = optimize,
40+
});
41+
42+
mull_it_over_tests.root_module.addImport("mull_it_over", mull_it_over);
43+
mull_it_over_tests.root_module.addAnonymousImport("example_input_1", .{
44+
.root_source_file = b.path("input/example_input_1.txt"),
45+
});
46+
mull_it_over_tests.root_module.addAnonymousImport("example_input_2", .{
47+
.root_source_file = b.path("input/example_input_2.txt"),
48+
});
49+
b.installArtifact(mull_it_over_tests);
50+
51+
const test_step = b.step("test", "Run mull_it_over (day 03) tests");
52+
test_step.dependOn(&b.addRunArtifact(mull_it_over_tests).step);
53+
54+
// ------------------------- Puzzle benchmarks -------------------------- \\
55+
const mull_it_over_benchmarks = b.addExecutable(.{
56+
.name = "mull_it_over_benchmarks",
57+
.root_source_file = b.path("benchmarks/puzzle_benchmarks.zig"),
58+
.target = target,
59+
.optimize = optimize,
60+
});
61+
62+
const zbench = b.dependency("zbench", .{
63+
.target = target,
64+
.optimize = optimize,
65+
});
66+
mull_it_over_benchmarks.root_module.addImport("zbench", zbench.module("zbench"));
67+
mull_it_over_benchmarks.root_module.addImport("mull_it_over", mull_it_over);
68+
mull_it_over_benchmarks.root_module.addAnonymousImport("puzzle_input", .{
69+
.root_source_file = b.path("input/puzzle_input.txt"),
70+
});
71+
b.installArtifact(mull_it_over_benchmarks);
72+
73+
const benchmark_step = b.step("benchmark", "Run mull_it_over (day 03) benchmarks");
74+
benchmark_step.dependOn(&b.addRunArtifact(mull_it_over_benchmarks).step);
75+
}

2024/03/mull_it_over/build.zig.zon

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
.{
2+
.name = "mull_it_over",
3+
.version = "0.1.0",
4+
.minimum_zig_version = "0.13.0",
5+
.dependencies = .{
6+
.yazap = .{
7+
.url = "git+https://github.com/prajwalch/yazap#c2e3122d5dd6192513ba590f229dbc535110efb8",
8+
.hash = "122054439ec36ac10987c87ae69f3b041b40b2e451af3fe3ef1fc578b3bad756a800",
9+
},
10+
.zbench = .{
11+
.url = "git+https://github.com/hendriknielaender/zBench#fb3ecae5d035091fd2392a2ec21970c06fc375fa",
12+
.hash = "122095b73930ff5d627429295c669905d85bb9b54394ddc185ad2d61295cc65819e5",
13+
},
14+
},
15+
.paths = .{
16+
"build.zig",
17+
"build.zig.zon",
18+
"src",
19+
"input",
20+
"tests",
21+
"benchmarks",
22+
},
23+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))

2024/03/mull_it_over/input/puzzle_input.txt

Lines changed: 6 additions & 0 deletions
Large diffs are not rendered by default.

2024/03/mull_it_over/src/main.zig

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
const std = @import("std");
2+
const yazap = @import("yazap");
3+
const mull_it_over = @import("mull_it_over");
4+
5+
const allocator = std.heap.page_allocator;
6+
const log = std.log;
7+
const App = yazap.App;
8+
const Arg = yazap.Arg;
9+
const string = []const u8;
10+
11+
pub fn main() !void {
12+
var app = App.init(allocator, "Day 03", "Day 03: Mull It Over");
13+
defer app.deinit();
14+
15+
var cmd = app.rootCommand();
16+
cmd.setProperty(.help_on_empty_args);
17+
try cmd.addArg(Arg.singleValueOption(
18+
"filename",
19+
'f',
20+
"Input file (e.g. input/puzzle_input.txt)",
21+
));
22+
23+
const matches = try app.parseProcess();
24+
25+
const stdout_file = std.io.getStdOut().writer();
26+
var bw = std.io.bufferedWriter(stdout_file);
27+
const stdout = bw.writer();
28+
29+
var file_content: string = undefined;
30+
if (matches.getSingleValue("filename")) |filename| {
31+
const file = try std.fs.cwd().openFile(filename, .{});
32+
defer file.close();
33+
34+
const file_size = try file.getEndPos();
35+
const buffer: []u8 = try allocator.alloc(u8, file_size);
36+
defer allocator.free(buffer);
37+
38+
_ = try file.readAll(buffer);
39+
file_content = std.mem.Allocator.dupe(
40+
allocator,
41+
u8,
42+
std.mem.trim(u8, buffer, "\n"),
43+
) catch unreachable;
44+
} else {
45+
try app.displayHelp();
46+
return;
47+
}
48+
49+
const result_1 = mull_it_over.sum_of_multiplication_instructions(file_content);
50+
try stdout.print("Sum of all multiplication instructions: {!}\n", .{result_1});
51+
try bw.flush();
52+
53+
const result_2 = mull_it_over.conditional_sum_of_multiplication_instructions(file_content);
54+
try stdout.print("Conditional sum of multiplication instructions: {!}\n", .{result_2});
55+
try bw.flush();
56+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
const std = @import("std");
2+
const Allocator = std.mem.Allocator;
3+
const string = []const u8;
4+
5+
/// Task 1 - Calculate the sum over all multiplication instructions.
6+
///
7+
/// Arguments:
8+
/// - `contents`: Input file contents.
9+
///
10+
/// Returns:
11+
/// - Sum of all multiplications.
12+
pub fn sum_of_multiplication_instructions(contents: string) !u32 {
13+
const min_instruction_len: usize = 8;
14+
15+
var product_sum: u32 = 0;
16+
var i: usize = 0;
17+
while (i <= contents.len - min_instruction_len) {
18+
product_sum += parse_mul_instruction(contents, &i) catch {
19+
continue;
20+
};
21+
}
22+
23+
return product_sum;
24+
}
25+
26+
/// Task 2 - Calculate the sum over the multiplication instructions which are
27+
/// activated via the do() instructions.
28+
///
29+
/// Arguments:
30+
/// - `contents`: Input file contents.
31+
///
32+
/// Returns:
33+
/// - Sum of all active multiplications.
34+
pub fn conditional_sum_of_multiplication_instructions(contents: string) !u32 {
35+
const min_instruction_len: usize = 8;
36+
37+
var product_sum: u32 = 0;
38+
var do: bool = true;
39+
var i: usize = 0;
40+
while (i <= contents.len - min_instruction_len) {
41+
do = parse_conditional_instructions(contents, &i) catch do;
42+
if (do) {
43+
product_sum += parse_mul_instruction(contents, &i) catch {
44+
continue;
45+
};
46+
} else {
47+
i += 1;
48+
}
49+
}
50+
51+
return product_sum;
52+
}
53+
54+
// -------------------------------------------------------------------------- \\
55+
56+
/// Parse a single multiplication instruction.
57+
///
58+
/// Arguments:
59+
/// - `contents`: The instruction string.
60+
/// - `i`: Pointer to the current position in the instruction string.
61+
///
62+
/// Returns:
63+
/// - The result of the multiplication instruction if one was found.
64+
fn parse_mul_instruction(contents: string, i: *usize) !u32 {
65+
if (!std.mem.eql(u8, contents[(i.*)..(i.* + 4)], "mul(")) {
66+
i.* += 1;
67+
return error.InvalidInstruction;
68+
}
69+
i.* += 4;
70+
71+
const multiplier = try parse_three_digit_number(contents[(i.*)..(i.* + 3)], i);
72+
if (contents[i.*] != ',') {
73+
return error.InvalidInstruction;
74+
}
75+
i.* += 1;
76+
77+
const multiplicand = try parse_three_digit_number(contents[(i.*)..(i.* + 3)], i);
78+
if (contents[i.*] != ')') {
79+
return error.InvalidInstruction;
80+
}
81+
i.* += 1;
82+
83+
return multiplier * multiplicand;
84+
}
85+
86+
/// Parse a single integer up to three digits.
87+
///
88+
/// Arguments:
89+
/// - `contents`: The instruction string.
90+
/// - `i`: Pointer to the current position in the instruction string.
91+
///
92+
/// Returns:
93+
/// - The integer if one was found.
94+
fn parse_three_digit_number(str: string, i: *usize) !u32 {
95+
var num = try std.fmt.parseInt(u32, str[0..1], 10);
96+
i.* += 1;
97+
98+
if (str[1] != ',' and str[1] != ')') {
99+
num *= 10;
100+
num += try std.fmt.parseInt(u32, str[1..2], 10);
101+
} else {
102+
return num;
103+
}
104+
i.* += 1;
105+
106+
if (str[2] != ',' and str[2] != ')') {
107+
num *= 10;
108+
num += try std.fmt.parseInt(u32, str[2..3], 10);
109+
} else {
110+
return num;
111+
}
112+
i.* += 1;
113+
114+
return num;
115+
}
116+
117+
/// Parse a single conditional instruction: do() or don't().
118+
///
119+
/// Arguments:
120+
/// - `contents`: The instruction string.
121+
/// - `i`: Pointer to the current position in the instruction string.
122+
///
123+
/// Returns:
124+
/// - The true if do() was found and false if don't() was found.
125+
fn parse_conditional_instructions(contents: string, i: *usize) !bool {
126+
if (std.mem.eql(u8, contents[(i.*)..(i.* + 4)], "do()")) {
127+
i.* += 4;
128+
return true;
129+
}
130+
131+
if (std.mem.eql(u8, contents[(i.*)..(i.* + 7)], "don't()")) {
132+
i.* += 7;
133+
return false;
134+
}
135+
136+
return error.InvalidInstruction;
137+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const std = @import("std");
2+
const mull_it_over = @import("mull_it_over");
3+
const testing = std.testing;
4+
5+
// Test of part 1
6+
test "task_1_input_1" {
7+
const example_input = @embedFile("example_input_1");
8+
try testing.expectEqual(
9+
161,
10+
mull_it_over.sum_of_multiplication_instructions(example_input),
11+
);
12+
}
13+
14+
// Test of part 2
15+
test "task_2_input_1" {
16+
const example_input = @embedFile("example_input_1");
17+
try testing.expectEqual(
18+
161,
19+
mull_it_over.conditional_sum_of_multiplication_instructions(example_input),
20+
);
21+
}
22+
23+
test "task_2_input_2" {
24+
const example_input = @embedFile("example_input_2");
25+
try testing.expectEqual(
26+
48,
27+
mull_it_over.conditional_sum_of_multiplication_instructions(example_input),
28+
);
29+
}

2024/build.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@ pub fn build(b: *std.Build) void {
3434
add_subproject(b, target, optimize, test_step, benchmark_step, "00", "zig_template");
3535
add_subproject(b, target, optimize, test_step, benchmark_step, "01", "historian_hysteria");
3636
add_subproject(b, target, optimize, test_step, benchmark_step, "02", "red_nosed_reports");
37+
add_subproject(b, target, optimize, test_step, benchmark_step, "03", "mull_it_over");
3738
add_subproject(b, target, optimize, test_step, benchmark_step, "06", "guard_gallivant");
3839
}

0 commit comments

Comments
 (0)