Solution for 08-01
This commit is contained in:
parent
bf704d831b
commit
43982a67a1
8
NOTES.md
8
NOTES.md
@ -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
50
inputs/08/real.txt
Normal 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
12
inputs/08/test.txt
Normal file
@ -0,0 +1,12 @@
|
||||
............
|
||||
........0...
|
||||
.....0......
|
||||
.......0....
|
||||
....0.......
|
||||
......A.....
|
||||
............
|
||||
............
|
||||
........A...
|
||||
.........A..
|
||||
............
|
||||
............
|
29
scratch.zig
29
scratch.zig
@ -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
134
solutions/08.zig
Normal 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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user