Solution for 08-01
This commit is contained in:
parent
bf704d831b
commit
43982a67a1
6
NOTES.md
6
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!
|
* [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)
|
* Great powerful `switch` syntax (though not as powerful as Rust's)
|
||||||
* Labelled loops - _usually_ should be avoided, but helpful on occasion!
|
* 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
|
# 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)
|
* [String equality](https://nofmal.github.io/zig-with-example/string-handling/#string-equal)
|
||||||
* Switching on strings
|
* 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.
|
* [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...
|
## Not "missing", but...
|
||||||
|
|
||||||
@ -199,3 +201,7 @@ fn accumulate() ![]u32 {
|
|||||||
return response;
|
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 std = @import("std");
|
||||||
const print = std.debug.print;
|
const print = std.debug.print;
|
||||||
|
|
||||||
test "Demo accumulation" {
|
const expect = @import("std").testing.expect;
|
||||||
const accumulated = try accumulate();
|
|
||||||
print("DEBUG - accumulated values are {any}\n", .{accumulated});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn accumulate() ![]u32 {
|
test "Len of an iterator is not the same as size" {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
defer _ = gpa.deinit();
|
defer _ = gpa.deinit();
|
||||||
const allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
var list = std.ArrayList(u32).init(allocator);
|
var map = std.AutoHashMap(u8, u8).init(allocator);
|
||||||
defer list.deinit();
|
try map.put('a', 'b');
|
||||||
try list.append(1);
|
try map.put('c', 'd');
|
||||||
try list.append(2);
|
try map.put('e', 'f');
|
||||||
try list.append(3);
|
|
||||||
|
|
||||||
const response = try allocator.alloc(u32, list.items.len);
|
var keyIterator = map.keyIterator();
|
||||||
@memcpy(response, list.items);
|
const length = keyIterator.len;
|
||||||
return response;
|
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 {
|
pub fn main() !void {
|
||||||
@ -42,5 +43,3 @@ pub fn main() !void {
|
|||||||
fn doIt(string: *const [3:0]u8) *const [9:0]u8 {
|
fn doIt(string: *const [3:0]u8) *const [9:0]u8 {
|
||||||
return "prefix" ++ string;
|
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