Solution to 1-2
This commit is contained in:
parent
09ff76600a
commit
aa408ad75b
41
NOTES.md
41
NOTES.md
@ -3,6 +3,8 @@ Notes, thoughts, or questions that arose as I implemented the solutions. Hopeful
|
|||||||
# Things I like
|
# Things I like
|
||||||
|
|
||||||
* [Continue expressions](https://zig-by-example.com/while)
|
* [Continue expressions](https://zig-by-example.com/while)
|
||||||
|
* Built in optionals (with `orelse`)
|
||||||
|
* Better error-handling than GoLang's (though that bar is set _real_ low). I have only just scratched the surface, though, it looks interestingly powerful - might well be even better than I've realized at this point!
|
||||||
|
|
||||||
# Things that I've found missing from this language
|
# Things that I've found missing from this language
|
||||||
|
|
||||||
@ -10,6 +12,7 @@ I mean, Jesus Christ, right now it seems even worse than GoLang.
|
|||||||
|
|
||||||
* [String concatenation](https://old.reddit.com/r/Zig/comments/bfcsul/concatenating_zig_strings/)
|
* [String concatenation](https://old.reddit.com/r/Zig/comments/bfcsul/concatenating_zig_strings/)
|
||||||
* [String equality](https://nofmal.github.io/zig-with-example/string-handling/#string-equal)
|
* [String equality](https://nofmal.github.io/zig-with-example/string-handling/#string-equal)
|
||||||
|
* Switching on strings
|
||||||
|
|
||||||
# Questions
|
# Questions
|
||||||
|
|
||||||
@ -83,3 +86,41 @@ test {
|
|||||||
I can fix it by changing the type signature to accept `[]const u8`, but (I think?) that then means that I can't call the function with non-const-length strings - including strings read from files.
|
I can fix it by changing the type signature to accept `[]const u8`, but (I think?) that then means that I can't call the function with non-const-length strings - including strings read from files.
|
||||||
|
|
||||||
[This](https://stackoverflow.com/questions/72736997/how-to-pass-a-c-string-into-a-zig-function-expecting-a-zig-string) link refers to `[]const u8` as a "Zig-style string-slice", but also refers to `[*c]const u8` as a "c_string", so...:shrug:?
|
[This](https://stackoverflow.com/questions/72736997/how-to-pass-a-c-string-into-a-zig-function-expecting-a-zig-string) link refers to `[]const u8` as a "Zig-style string-slice", but also refers to `[*c]const u8` as a "c_string", so...:shrug:?
|
||||||
|
|
||||||
|
## Why can't I iterate over a HashMap?
|
||||||
|
|
||||||
|
The following code:
|
||||||
|
|
||||||
|
```zig
|
||||||
|
const std = @import("std");
|
||||||
|
const print = std.debug.print;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
var hashMap = std.AutoHashMap(u32, u32).init(allocator);
|
||||||
|
|
||||||
|
try hashMap.put(2, 5);
|
||||||
|
try hashMap.put(1, 35);
|
||||||
|
try hashMap.put(4, 20);
|
||||||
|
|
||||||
|
const iter = hashMap.keyIterator();
|
||||||
|
while (try iter.next()) |key| {
|
||||||
|
print("{}\n", .{key});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
gives:
|
||||||
|
|
||||||
|
```
|
||||||
|
scratch.zig:15:20: error: expected type '*hash_map.HashMapUnmanaged(u32,u32,hash_map.AutoContext(u32),80).FieldIterator(u32)', found '*const hash_map.HashMapUnmanaged(u32,u32,hash_map.AutoContext(u32),80).FieldIterator(u32)'
|
||||||
|
while (try iter.next()) |key| {
|
||||||
|
~~~~^~~~~
|
||||||
|
scratch.zig:15:20: note: cast discards const qualifier
|
||||||
|
/Users/scubbo/zig/zig-macos-x86_64-0.14.0-dev.2362+a47aa9dd9/lib/std/hash_map.zig:894:35: note: parameter type declared here
|
||||||
|
pub fn next(self: *@This()) ?*T {
|
||||||
|
```
|
||||||
|
|
||||||
|
I _think_ this means that the pointer to the Iterator is a Const-pointer and `.next()` expects a mutable pointer. But, if so - how do we get a mutable pointer from a const? I tried `@ptrCast` but that gave a similar error.
|
||||||
|
@ -3,3 +3,11 @@
|
|||||||
If you - like me - are new to the Zig language, [Ziglings](https://codeberg.org/ziglings/exercises/) seems to be a well-respected entrypoint!
|
If you - like me - are new to the Zig language, [Ziglings](https://codeberg.org/ziglings/exercises/) seems to be a well-respected entrypoint!
|
||||||
|
|
||||||
The authoritative source for this code is on [Gitea](https://gitea.scubbo.org/scubbo/advent-of-code-2024). The GitHub version is a [mirror](https://docs.gitea.com/usage/repo-mirror#setting-up-a-push-mirror-from-gitea-to-github). [Self-hosting](https://old.reddit.com/r/selfhosted/) is not only the best way to learn, but also to reduce dependency on untrustworthy corporations.
|
The authoritative source for this code is on [Gitea](https://gitea.scubbo.org/scubbo/advent-of-code-2024). The GitHub version is a [mirror](https://docs.gitea.com/usage/repo-mirror#setting-up-a-push-mirror-from-gitea-to-github). [Self-hosting](https://old.reddit.com/r/selfhosted/) is not only the best way to learn, but also to reduce dependency on untrustworthy corporations.
|
||||||
|
|
||||||
|
# Execution
|
||||||
|
|
||||||
|
I've tried (in `main.zig`) to make a general-purpose executable that can be passed arguments to determine the function to run (e.g. `zig run main.zig -- 1 2`), but so far no luck - lots of type errors 🙃
|
||||||
|
|
||||||
|
So for now, run directly with (e.g.) `zig run solutions/01.zig`, and do the following manual changes:
|
||||||
|
* Change `pub fn main() void {...}` in each solution-file to invoke the function you want run.
|
||||||
|
* Change `isTestCase` from `true` to `false` when ready to get the real solution.
|
48
main.zig
Normal file
48
main.zig
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
// Unfortunately Zig doesn't appear to support dynamic imports - that is, non-literal arguments to `@import` -
|
||||||
|
// so we can't do `const module = @import(util.concatString(&.{"solutions/", problem_number, ".zig"}))`
|
||||||
|
|
||||||
|
const problem_one = @import("solutions/01.zig");
|
||||||
|
|
||||||
|
pub fn main() void {
|
||||||
|
// std.debug.print("There are {d} args:\n", .{std.os.argv.len});
|
||||||
|
// for (std.os.argv) |arg| {
|
||||||
|
// std.debug.print(" {s}\n", .{arg});
|
||||||
|
// }
|
||||||
|
const args = std.os.argv;
|
||||||
|
const problem_number = parse_input_as_number(args[1]);
|
||||||
|
const sub_problem_number = parse_input_as_number(args[2]);
|
||||||
|
const module = switch (problem_number) {
|
||||||
|
1 => {
|
||||||
|
return problem_one;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
switch (sub_problem_number) {
|
||||||
|
1 => {
|
||||||
|
module.part_one();
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
module.part_two();
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_input_as_number(input: [*:0]u8) i32 {
|
||||||
|
// We _should_ be able to just use `try std.fmt.parseInt(i32, input)` - but that complains with
|
||||||
|
// `expected type '[]const u8', found '[*:0]u8'`
|
||||||
|
// and I CBA to figure out how to do that conversion when I have the time pressure of solving problems!
|
||||||
|
// That can be for later learning :P
|
||||||
|
var output_value: i32 = 0;
|
||||||
|
for (input) |char| {
|
||||||
|
output_value *= 10;
|
||||||
|
output_value + char;
|
||||||
|
}
|
||||||
|
return output_value;
|
||||||
|
}
|
18
scratch.zig
Normal file
18
scratch.zig
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const print = std.debug.print;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
var hashMap = std.AutoHashMap(u32, u32).init(allocator);
|
||||||
|
|
||||||
|
try hashMap.put(2, 5);
|
||||||
|
try hashMap.put(1, 35);
|
||||||
|
try hashMap.put(4, 20);
|
||||||
|
|
||||||
|
const iter = hashMap.keyIterator();
|
||||||
|
while (try iter.next()) |key| {
|
||||||
|
print("{}\n", .{key});
|
||||||
|
}
|
||||||
|
}
|
@ -2,9 +2,13 @@ const std = @import("std");
|
|||||||
const print = std.debug.print;
|
const print = std.debug.print;
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
const output = try part_two();
|
||||||
|
print("{}\n", .{output});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn part_one() !u32 {
|
pub fn part_one() !u32 {
|
||||||
const arrays = try parseInputFileToArrays();
|
const arrays = try parseInputFileToArrays();
|
||||||
std.debug.print("{any}", .{arrays.first});
|
|
||||||
const arr1 = arrays.first;
|
const arr1 = arrays.first;
|
||||||
const arr2 = arrays.second;
|
const arr2 = arrays.second;
|
||||||
|
|
||||||
@ -30,7 +34,57 @@ pub fn part_one() !u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn part_two() !u32 {
|
pub fn part_two() !u32 {
|
||||||
return 0;
|
const arrays = try parseInputFileToArrays();
|
||||||
|
const arr1 = arrays.first;
|
||||||
|
const arr2 = arrays.second;
|
||||||
|
print("DEBUG - arr1 is {any}\narr2 is {any}\n", .{arr1, arr2});
|
||||||
|
// Logic:
|
||||||
|
// * Iterate over each array
|
||||||
|
// * Count the number of occurrences
|
||||||
|
// * For each number, increment the sum by (number * count_1 * count_2)
|
||||||
|
// (Would technically be parallelizable if you wanted to get fancy, but JFC I'm not ready for that in Zig yet)
|
||||||
|
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
|
var counts1 = std.AutoHashMap(u32, u32).init(allocator);
|
||||||
|
var counts2 = std.AutoHashMap(u32, u32).init(allocator);
|
||||||
|
// Later, we'll need to iterate over the keys of `counts1` to sum up the final value.
|
||||||
|
// You'd think you could do this with:
|
||||||
|
// ```
|
||||||
|
// const iter = counts1.keyIterator();
|
||||||
|
// while (try iter.next()) |key| {
|
||||||
|
// ...
|
||||||
|
// ```
|
||||||
|
// But that gives an error that the iterator is a const pointer but `while` requires a mutable pointer.
|
||||||
|
// So instead I preserve the encountered keys in this array so that we can then loop over them.
|
||||||
|
// Ridiculous language.
|
||||||
|
var preservedKeys = std.ArrayList(u32).init(allocator);
|
||||||
|
for (arr1) |elem| {
|
||||||
|
if (!counts1.contains(elem)) {
|
||||||
|
try preservedKeys.append(elem);
|
||||||
|
print("Added {} to the preservedKeys list\n", .{elem});
|
||||||
|
}
|
||||||
|
try counts1.put(elem, (counts1.get(elem) orelse 0) + 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
for (arr2) |elem| {
|
||||||
|
try counts2.put(elem, (counts2.get(elem) orelse 0) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Beginning the calculation", .{});
|
||||||
|
var output: u32 = 0;
|
||||||
|
for (preservedKeys.items) |key| {
|
||||||
|
print("Operating on {} - at this point the output value is {}\n", .{key, output});
|
||||||
|
const count1 = (counts1.get(key) orelse 0);
|
||||||
|
const count2 = (counts2.get(key) orelse 0);
|
||||||
|
const increment = key * count1 * count2;
|
||||||
|
print("The increment for key {} is {} (calculated based on counts {} and {})\n", .{key, increment, count1, count2});
|
||||||
|
output += increment;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseInputFileToArrays() !struct { first: []u32, second: []u32 } {
|
fn parseInputFileToArrays() !struct { first: []u32, second: []u32 } {
|
||||||
@ -118,6 +172,6 @@ test "part one" {
|
|||||||
try expect(try part_one() == 11);
|
try expect(try part_one() == 11);
|
||||||
}
|
}
|
||||||
|
|
||||||
// test "part two" {
|
test "part two" {
|
||||||
// try expect(try part_two() == 31);
|
try expect(try part_two() == 31);
|
||||||
// }
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user