Solution for 08-01

This commit is contained in:
Jack Jackson 2024-12-27 20:14:09 -08:00
parent bf704d831b
commit 43982a67a1
5 changed files with 217 additions and 16 deletions

View File

@ -13,6 +13,7 @@ Notes, thoughts, or questions that arose as I implemented the solutions. Hopeful
* [Continue expressions](https://ziglang.org/documentation/master/#while) - don't need to remember to put the index-incrementing code at the end of every branch!
* Great powerful `switch` syntax (though not as powerful as Rust's)
* Labelled loops - _usually_ should be avoided, but helpful on occasion!
* `defer` - though, unlike in GoLang where it's a nice-to-have that allows one to do cleanup, here it is _absolutely essential_ for all the manual `deinit`s and `free`s
# Things that I've found missing from this language
@ -22,6 +23,7 @@ Hmmmm, right now it seems even worse than GoLang. Though the Error handling is _
* [String equality](https://nofmal.github.io/zig-with-example/string-handling/#string-equal)
* Switching on strings
* [Iterating over values of an enum](https://zig.guide/language-basics/enums) - [this](https://ziggit.dev/t/iterating-over-a-packed-enum/6530) suggests that it's possible, but testing indicates that that only works at comptime.
* [Sets](https://github.com/ziglang/zig/issues/6919) (though, as the top comment points out, that's not _too_ bad as you can abuse a HashMap for it)
## Not "missing", but...
@ -198,4 +200,8 @@ fn accumulate() ![]u32 {
@memcpy(response, list.items);
return response;
}
```
```
## What's the point in `HashMap.getOrPut`?
`getOrPut` _doesn't_ actually `put` anything, it _only_ `get`s. See https://ziggit.dev/t/whats-the-point-in-hashmap-getorput/7547.

50
inputs/08/real.txt Normal file
View File

@ -0,0 +1,50 @@
..............U.............c.....3...............
.....p.........F..................................
.....m..7....................4x............3......
..e.............F..........c...YH..3..............
.......e...................................c..E..8
................a...U................8............
..............................4.F...8....x........
............7.....4............Hc..E.......x......
........p..............................E..........
.............U.e....................x....t........
.7..........................Z.H....g..............
.........7..m.....S.........................E.....
...F.....p...........6...SY.......................
.................6..k...................g.........
..........m......a........................g.......
.......M.......................................g..
..............a............Y....C........H........
....u.......6........a.........C.GY...............
.....M..................S......................2..
..........M........S.....................2........
........M.......................5.........z..f....
.....................................Z........t.2.
..........6.......................................
......................................G...........
.........................A.........G9....Z........
........................C.........................
.....k......................G......z..t...........
.......k......................zs....f........5...9
................h........................9....2...
.............h.....0...........f.....K..ZX........
..................................f...............
.......1....................9.........Xz..........
...............1......B.s......X..................
............h...............B.....................
..T.........k..................b..................
...............u..................................
.........u.............h..................0.......
..............y...................................
...............................t....X......5......
.................A............................5...
................u..................s..............
.T..........b....y................................
............y............................K........
..1...............................s....B..........
..............Ay.............B...P................
..........T.......................K...........0...
.............T..................P.........K.......
......A....P......................................
....b.........1...................................
.........b................................P.......

12
inputs/08/test.txt Normal file
View File

@ -0,0 +1,12 @@
............
........0...
.....0......
.......0....
....0.......
......A.....
............
............
........A...
.........A..
............
............

View File

@ -1,25 +1,26 @@
const std = @import("std");
const print = std.debug.print;
test "Demo accumulation" {
const accumulated = try accumulate();
print("DEBUG - accumulated values are {any}\n", .{accumulated});
}
const expect = @import("std").testing.expect;
fn accumulate() ![]u32 {
test "Len of an iterator is not the same as size" {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var list = std.ArrayList(u32).init(allocator);
defer list.deinit();
try list.append(1);
try list.append(2);
try list.append(3);
var map = std.AutoHashMap(u8, u8).init(allocator);
try map.put('a', 'b');
try map.put('c', 'd');
try map.put('e', 'f');
const response = try allocator.alloc(u32, list.items.len);
@memcpy(response, list.items);
return response;
var keyIterator = map.keyIterator();
const length = keyIterator.len;
var counted_length: usize = 0;
while (keyIterator.next()) |_| {
counted_length += 1;
}
print("DEBUG - length is {} and counted_length is {}\n", .{ length, counted_length });
try expect(length == counted_length);
}
pub fn main() !void {
@ -42,5 +43,3 @@ pub fn main() !void {
fn doIt(string: *const [3:0]u8) *const [9:0]u8 {
return "prefix" ++ string;
}
const expect = @import("std").testing.expect;

134
solutions/08.zig Normal file
View File

@ -0,0 +1,134 @@
const std = @import("std");
const print = std.debug.print;
const util = @import("util.zig");
pub fn main() !void {
const response = try part_one(false);
print("{}\n", .{response});
}
const Point = struct { x: usize, y: usize };
fn part_one(is_test_case: bool) !usize {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const input_file = try util.getInputFile("08", is_test_case);
const data = try util.readAllInputWithAllocator(input_file, allocator);
defer allocator.free(data);
print("DEBUG - created data", .{});
// In this problem I'm experimenting with not even parsing the input into lines, but just keeping a "line counter"
// that is incremented whenever we hit a `\n` character
var width: ?usize = null;
var height: ?usize = null;
var x: usize = 0;
var y: usize = 0;
var antennae = std.AutoHashMap(u8, std.ArrayList(Point)).init(allocator);
defer antennae.deinit();
for (data) |c| {
print("DEBUG - checking {c} at {}, {}\n", .{ c, x, y });
switch (c) {
'\n' => {
if (width == null) {
width = x;
}
x = 0;
y += 1;
},
'.' => {
x += 1;
},
else => {
const point = Point{ .x = x, .y = y };
// https://ziggit.dev/t/problem-with-hashmaps/7221 was helpful!
var result = try antennae.getOrPut(c);
if (!result.found_existing) {
result.value_ptr.* = std.ArrayList(Point).init(allocator);
}
try result.value_ptr.append(point);
x += 1;
},
}
}
height = y; // No `+1` because the trailing newline will do that for us.
print("DEBUG - height is {} and width is {}\n", .{ height.?, width.? });
// Zig lacks a Set (https://github.com/ziglang/zig/issues/6919), so we abuse a HashMap to pretend
var all_antinodes = std.AutoHashMap(Point, usize).init(allocator);
defer all_antinodes.deinit();
var it = antennae.valueIterator();
while (it.next()) |v| {
const node_pairs = try pairs(v.items, allocator);
defer allocator.free(node_pairs);
for (node_pairs) |node_pair| {
const antinodes = try findAntinodes(node_pair, width.?, height.?, allocator);
defer allocator.free(antinodes);
for (antinodes) |antinode| {
try all_antinodes.put(antinode, 1); // We don't actually need to put any value - just populating the key
}
}
// allocator.free(v); <-- because we can't do this, there will still always be memory leaked :'(
}
var count: usize = 0;
var antinode_iterator = all_antinodes.keyIterator();
print("DEBUG - antinodes are:\n", .{});
while (antinode_iterator.next()) |antinode| {
print("{}\n", .{antinode});
count += 1;
}
return count;
}
fn pairs(nodes: []Point, allocator: std.mem.Allocator) ![][2]Point {
var output = std.ArrayList([2]Point).init(allocator);
defer output.deinit();
var a: usize = 0;
while (a < nodes.len - 1) : (a += 1) {
var b = a + 1;
while (b < nodes.len) : (b += 1) {
try output.append(.{ nodes[a], nodes[b] });
}
}
return output.toOwnedSlice();
}
fn findAntinodes(nodes: [2]Point, width: usize, height: usize, allocator: std.mem.Allocator) ![]Point {
var response = std.ArrayList(Point).init(allocator);
defer response.deinit();
if (2 * nodes[1].x >= nodes[0].x and 2 * nodes[1].y >= nodes[0].y) {
const antiNode1 = Point{ .x = 2 * nodes[1].x - nodes[0].x, .y = 2 * nodes[1].y - nodes[0].y };
if (antiNodeIsValid(antiNode1, width, height)) {
try response.append(antiNode1);
}
}
if (2 * nodes[0].x >= nodes[1].x and 2 * nodes[0].y >= nodes[1].y) {
const antiNode2 = Point{ .x = 2 * nodes[0].x - nodes[1].x, .y = 2 * nodes[0].y - nodes[1].y };
if (antiNodeIsValid(antiNode2, width, height)) {
try response.append(antiNode2);
}
}
return response.toOwnedSlice();
}
fn antiNodeIsValid(antiNode: Point, width: usize, height: usize) bool {
// Don't technically need to check for >= 0 because that's already checked in `findAntinodes` (because otherwise
// there would be integer overflow by daring to use a negative number :P ), but doesn't hurt to replicate it here -
// otherwise a future reader might think we've forgotten it.
return antiNode.x >= 0 and antiNode.y >= 0 and antiNode.x < width and antiNode.y < height;
}
const expect = std.testing.expect;
test "part_one" {
const part_one_response = try part_one(true);
print("DEBUG - part_one_response is {}\n", .{part_one_response});
try expect(part_one_response == 14);
}