Compare commits
2 Commits
e112876796
...
052bf70095
Author | SHA1 | Date | |
---|---|---|---|
052bf70095 | |||
9c64d710a3 |
99
src/day04.zig
Normal file
99
src/day04.zig
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const util = @import("util.zig");
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
const input = @embedFile("data/day04.txt");
|
||||||
|
const sln = try solve(util.gpa, input);
|
||||||
|
std.debug.print("{d}\n", .{sln.value});
|
||||||
|
std.debug.print("{d}\n", .{sln.copies});
|
||||||
|
}
|
||||||
|
|
||||||
|
const Solution = struct {
|
||||||
|
value: usize,
|
||||||
|
copies: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn solve(alloc: mem.Allocator, input: []const u8) !Solution {
|
||||||
|
var value: usize = 0;
|
||||||
|
var card_counts = std.AutoHashMap(usize, usize).init(alloc);
|
||||||
|
defer card_counts.deinit();
|
||||||
|
|
||||||
|
var card: usize = 0;
|
||||||
|
var it = util.splitLines(input);
|
||||||
|
while (it.next()) |line| : (card += 1) {
|
||||||
|
if (line.len == 0) continue;
|
||||||
|
|
||||||
|
const sep = mem.indexOfScalar(u8, line, ':').?;
|
||||||
|
var line_it = util.split(line[sep + 1 ..], '|');
|
||||||
|
const winning = try util.parseIntsScalar(usize, alloc, line_it.next().?, .{});
|
||||||
|
defer alloc.free(winning);
|
||||||
|
const mine = try util.parseIntsScalar(usize, alloc, line_it.next().?, .{});
|
||||||
|
defer alloc.free(mine);
|
||||||
|
|
||||||
|
var matches: usize = 0;
|
||||||
|
for (mine) |n| {
|
||||||
|
if (mem.containsAtLeast(usize, winning, 1, &[_]usize{n})) {
|
||||||
|
matches += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matches > 0) {
|
||||||
|
value += std.math.pow(usize, 2, matches - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise with 1 copy of current card
|
||||||
|
const copies = blk: {
|
||||||
|
const entry = try card_counts.getOrPut(card);
|
||||||
|
if (entry.found_existing) {
|
||||||
|
entry.value_ptr.* += 1;
|
||||||
|
} else {
|
||||||
|
entry.value_ptr.* = 1;
|
||||||
|
}
|
||||||
|
break :blk entry.value_ptr.*;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1 additional card for each match, multiplied by copies of this card
|
||||||
|
for (1..matches + 1) |offset| {
|
||||||
|
const winning_card_entry = try card_counts.getOrPut(card + offset);
|
||||||
|
if (winning_card_entry.found_existing) {
|
||||||
|
winning_card_entry.value_ptr.* += copies;
|
||||||
|
} else {
|
||||||
|
winning_card_entry.value_ptr.* = copies;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var copy_count: usize = 0;
|
||||||
|
var copy_it = card_counts.valueIterator();
|
||||||
|
while (copy_it.next()) |v| {
|
||||||
|
copy_count += v.*;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .value = value, .copies = copy_count };
|
||||||
|
}
|
||||||
|
|
||||||
|
test "silver" {
|
||||||
|
const input =
|
||||||
|
\\Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
|
||||||
|
\\Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
|
||||||
|
\\Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
|
||||||
|
\\Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
|
||||||
|
\\Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
|
||||||
|
\\Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11
|
||||||
|
;
|
||||||
|
const sln = try solve(std.testing.allocator, input);
|
||||||
|
try std.testing.expectEqual(@as(usize, 13), sln.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "gold" {
|
||||||
|
const input =
|
||||||
|
\\Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
|
||||||
|
\\Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
|
||||||
|
\\Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
|
||||||
|
\\Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
|
||||||
|
\\Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
|
||||||
|
\\Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11
|
||||||
|
;
|
||||||
|
const sln = try solve(std.testing.allocator, input);
|
||||||
|
try std.testing.expectEqual(@as(usize, 30), sln.copies);
|
||||||
|
}
|
33
src/util.zig
33
src/util.zig
@ -1,4 +1,37 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
var gpa_impl = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa_impl = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
/// General purpose allocator.
|
||||||
pub const gpa = gpa_impl.allocator();
|
pub const gpa = gpa_impl.allocator();
|
||||||
|
|
||||||
|
pub const ParseIntsOptions = struct {
|
||||||
|
base: u8 = 10,
|
||||||
|
sep: u8 = ' ',
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Parses separated integers. Sequential separators are treated as one. Caller owns memory.
|
||||||
|
pub fn parseIntsScalar(comptime T: type, alloc: std.mem.Allocator, input: []const u8, opts: ParseIntsOptions) ![]T {
|
||||||
|
var items = std.ArrayList(T).init(alloc);
|
||||||
|
errdefer items.deinit();
|
||||||
|
|
||||||
|
var it = split(input, opts.sep);
|
||||||
|
while (it.next()) |i| {
|
||||||
|
if (i.len == 0) continue;
|
||||||
|
try items.append(try std.fmt.parseInt(T, i, opts.base));
|
||||||
|
}
|
||||||
|
return try items.toOwnedSlice();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shortcut to splitScalar with a byte buffer.
|
||||||
|
pub fn split(buffer: []const u8, sep: u8) mem.SplitIterator(u8, .scalar) {
|
||||||
|
return mem.splitScalar(u8, buffer, sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn splitLines(buffer: []const u8) mem.SplitIterator(u8, .scalar) {
|
||||||
|
return split(buffer, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn splitSpace(buffer: []const u8) mem.SplitIterator(u8, .scalar) {
|
||||||
|
return split(buffer, ' ');
|
||||||
|
}
|
||||||
|
42
template.zig
Normal file
42
template.zig
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const util = @import("util.zig");
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
const input = @embedFile("data/dayXX.txt");
|
||||||
|
const sln = try solve(util.gpa, input);
|
||||||
|
std.debug.print("{d}\n", .{sln.a});
|
||||||
|
std.debug.print("{d}\n", .{sln.b});
|
||||||
|
}
|
||||||
|
|
||||||
|
const Solution = struct {
|
||||||
|
a: usize,
|
||||||
|
b: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn solve(alloc: mem.Allocator, input: []const u8) !Solution {
|
||||||
|
_ = alloc;
|
||||||
|
|
||||||
|
var it = util.splitLines(input);
|
||||||
|
while (it.next()) |line| {
|
||||||
|
if (line.len == 0) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .a = 0, .b = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
test "silver" {
|
||||||
|
const input =
|
||||||
|
\\
|
||||||
|
;
|
||||||
|
const sln = try solve(std.testing.allocator, input);
|
||||||
|
try std.testing.expectEqual(@as(usize, 0), sln.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "gold" {
|
||||||
|
const input =
|
||||||
|
\\
|
||||||
|
;
|
||||||
|
const sln = try solve(std.testing.allocator, input);
|
||||||
|
try std.testing.expectEqual(@as(usize, 0), sln.b);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user