1
0

Compare commits

...

3 Commits

Author SHA1 Message Date
24669a60f0
wtf happened in day06
Some checks failed
Build and test / test (push) Failing after 2m40s
2023-12-06 16:25:34 +11:00
0ab1fa186d
wash day05 2023-12-06 11:19:55 +11:00
0f2044b762
hey lmao day05 2023-12-06 11:17:05 +11:00
2 changed files with 201 additions and 93 deletions

View File

@ -5,117 +5,140 @@ const mem = std.mem;
pub fn main() !void { pub fn main() !void {
const input = @embedFile("data/day05.txt"); const input = @embedFile("data/day05.txt");
const sln = try solve(util.gpa, input); const sln = try solve(util.gpa, input);
std.debug.print("{d}\n", .{sln.a}); std.debug.print("{d}\n", .{sln});
std.debug.print("{d}\n", .{sln.b}); std.debug.print("{d}\n", .{sln});
} }
const Solution = struct { fn Range(comptime T: type) type {
a: usize, return struct {
b: usize, start: T,
}; end: T,
const Transform = struct { const Self = @This();
from: []const u8,
to: []const u8, /// Returns the intersection of two ranges.
pub fn intersect(self: Self, other: Self) ?Self {
const a = if (self.start < other.start) self else other;
const b = if (self.start < other.start) other else self;
if (a.start == a.end or b.start == b.end) return null; // Points don't intersect.
if (a.end < b.start) return null; // No intersection.
if (a.end > b.end) return b; // A is a superset of B.
return .{ .start = b.start, .end = a.end };
}
/// Returns the union of two ranges.
pub fn join(self: Self, other: Self) ?Self {
if (self.intersect(other) == null) return null; // Can't union disjoint ranges.
// Now guaranteed that they overlap.
return .{ .start = @min(self.start, other.start), .end = @max(self.end, other.end) };
}
}; };
}
const Map = struct { const Map = struct {
dest_start: usize, offset: isize,
source_start: usize, source: Range(usize),
range: usize,
}; };
const Component = struct { const Component = struct {
name: []const u8, stage: usize,
value: usize, range: Range(usize),
}; };
const UsizeSet = std.AutoHashMap(usize, void); fn mergeRanges(ranges: *std.ArrayList(Component)) void {
var i: usize = 0;
while (i < ranges.items.len) : (i += 1) {
var item = ranges.items[i];
var j = i + 1;
while (j < ranges.items.len) {
const next = ranges.items[j];
if (item.range.join(next.range)) |merged| {
const merged_item = .{ .stage = item.stage, .range = merged };
item = merged_item;
ranges.items[i] = merged_item;
_ = ranges.swapRemove(j);
} else {
j += 1;
}
}
}
}
fn solve(alloc: mem.Allocator, input: []const u8) !Solution { fn solve(alloc: mem.Allocator, input: []const u8) !usize {
var it = util.splitLines(input); var it = util.splitLines(input);
const seed_line = it.next().?; const seed_line = it.next().?;
const seeds = try util.parseIntsScalar(usize, alloc, seed_line[mem.indexOfScalar(u8, seed_line, ':').? + 1 ..], .{}); const seeds = try util.parseIntsScalar(usize, alloc, seed_line[mem.indexOfScalar(u8, seed_line, ':').? + 1 ..], .{});
defer alloc.free(seeds); defer alloc.free(seeds);
var last_values = UsizeSet.init(alloc); var ranges = std.ArrayList(Component).init(alloc);
var working_values = UsizeSet.init(alloc); defer ranges.deinit();
defer last_values.deinit();
defer working_values.deinit();
var low_loc: usize = std.math.maxInt(usize); {
var index: usize = 0;
var seeds_index: usize = 0; while (index < seeds.len) : (index += 2) {
while (seeds_index < seeds.len) : (seeds_index += 2) { try ranges.append(.{
last_values.clearRetainingCapacity(); .stage = 0,
working_values.clearRetainingCapacity(); .range = .{
.start = seeds[index],
std.debug.print("= seeding {d}/{d} =\n", .{ seeds_index, seeds.len }); .end = seeds[index] + seeds[index + 1],
const start = seeds[seeds_index]; },
const range = seeds[seeds_index + 1]; });
for (start..start + range) |seed| { }
// std.debug.print("seed {d}\n", .{seed});
try working_values.put(seed, {});
} }
// Reset parse input. var current_stage: usize = 0;
it = util.splitLines(input);
_ = it.next().?;
var current_component: []const u8 = undefined;
while (it.next()) |line| { while (it.next()) |line| {
if (line.len == 0) { if (line.len == 0) {
std.debug.print("== swap ==\n", .{}); for (ranges.items, 0..) |item, index| {
// Copy all remaining if (item.stage != current_stage) {
var lv_it = last_values.iterator(); ranges.items[index] = .{ .stage = current_stage, .range = item.range };
while (lv_it.next()) |entry| {
try working_values.put(entry.key_ptr.*, {});
} }
// Swap working sets }
mem.swap(UsizeSet, &last_values, &working_values); mergeRanges(&ranges);
working_values.clearRetainingCapacity();
} else if (mem.endsWith(u8, line, "map:")) { } else if (mem.endsWith(u8, line, "map:")) {
var t_it = util.split(line, ' '); current_stage += 1;
var comp_it = util.split(t_it.next().?, '-');
_ = comp_it.next(); // A
_ = comp_it.next(); // to
current_component = comp_it.next().?; // B
} else { } else {
std.debug.print("== {s} {d}/{d}\n", .{ current_component, working_values.count(), last_values.count() }); const map_line = try util.parseIntsScalar(usize, alloc, line, .{});
const map = try util.parseIntsScalar(usize, alloc, line, .{}); defer alloc.free(map_line);
defer alloc.free(map); const map = Map{
.offset = @as(isize, @intCast(map_line[0])) - @as(isize, @intCast(map_line[1])),
.source = .{ .start = map_line[1], .end = map_line[1] + map_line[2] },
};
var to_delete = UsizeSet.init(alloc); var i: usize = ranges.items.len;
defer to_delete.deinit(); while (i != 0) : (i -= 1) {
var lv_it = last_values.iterator(); if (ranges.items[i - 1].stage == current_stage) continue;
while (lv_it.next()) |entry| { const item = ranges.swapRemove(i - 1);
// if (transitioned[index]) {
// std.debug.print("{d} already mapped\n", .{index}); if (item.range.intersect(.{ .start = 0, .end = map.source.start })) |section| {
// continue :map_blk; // Non-transitioning section.
// } try ranges.append(.{ .stage = item.stage, .range = section });
const item = entry.key_ptr.*;
if (map[1] <= item and item <= map[1] + map[2]) {
const offset = @as(isize, @intCast(map[0])) - @as(isize, @intCast(map[1]));
const res: usize = @intCast(@as(isize, @intCast(item)) + offset);
// std.debug.print("{d} => {d}\n", .{ item, res });
try working_values.put(res, {});
try to_delete.put(item, {});
} }
if (item.range.intersect(map.source)) |section| {
// Transitioning section.
try ranges.append(.{
.stage = current_stage,
.range = .{
.start = @intCast(@as(isize, @intCast(section.start)) + map.offset),
.end = @intCast(@as(isize, @intCast(section.end)) + map.offset),
},
});
}
if (item.range.intersect(.{ .start = map.source.end, .end = std.math.maxInt(usize) })) |section| {
// Non-transitioning section.
try ranges.append(.{ .stage = item.stage, .range = section });
} }
var td_it = to_delete.iterator();
while (td_it.next()) |entry| {
// std.debug.print("pop {d}\n", .{entry.key_ptr.*});
_ = last_values.remove(entry.key_ptr.*);
} }
} }
} }
var lv_it = last_values.iterator(); var min_loc: usize = std.math.maxInt(usize);
while (lv_it.next()) |value| { for (ranges.items) |item| {
low_loc = @min(low_loc, value.key_ptr.*); min_loc = @min(min_loc, item.range.start);
} }
} return min_loc;
return .{ .a = low_loc, .b = 0 };
} }
test "silver" { test "silver" {
@ -156,7 +179,7 @@ test "silver" {
; ;
_ = input; _ = input;
// const sln = try solve(std.testing.allocator, input); // const sln = try solve(std.testing.allocator, input);
// try std.testing.expectEqual(@as(usize, 35), sln.a); // try std.testing.expectEqual(@as(usize, 35), sln);
} }
test "gold" { test "gold" {
@ -196,5 +219,5 @@ test "gold" {
\\56 93 4 \\56 93 4
; ;
const sln = try solve(std.testing.allocator, input); const sln = try solve(std.testing.allocator, input);
try std.testing.expectEqual(@as(usize, 46), sln.a); try std.testing.expectEqual(@as(usize, 46), sln);
} }

85
src/day06.zig Normal file
View File

@ -0,0 +1,85 @@
const std = @import("std");
const util = @import("util.zig");
const mem = std.mem;
pub fn main() !void {
const input = @embedFile("data/day06.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,
};
const Race = struct {
time: usize,
distance: usize,
};
fn solve(alloc: mem.Allocator, input: []const u8) !Solution {
const races: []Race = r: {
var it = util.splitLines(input);
const times = try util.parseIntsScalar(usize, alloc, it.next().?[10..], .{});
const distances = try util.parseIntsScalar(usize, alloc, it.next().?[10..], .{});
defer alloc.free(times);
defer alloc.free(distances);
var al = try std.ArrayList(Race).initCapacity(alloc, times.len);
for (times, distances) |t, d| {
try al.append(.{ .time = t, .distance = d });
}
break :r try al.toOwnedSlice();
};
defer alloc.free(races);
const bigRace: Race = r: {
var it = util.splitLines(input);
var vals: [2]usize = undefined;
for (0..vals.len) |i| {
const line = try mem.replaceOwned(u8, alloc, it.next().?[10..], " ", "");
defer alloc.free(line);
vals[i] = try std.fmt.parseInt(usize, line, 10);
}
break :r .{ .time = vals[0], .distance = vals[1] };
};
var result: usize = 1;
for (races) |race| {
var winning: usize = 0;
for (0..race.time - 1) |speed| {
const distance = speed * (race.time - speed);
if (distance > race.distance) winning += 1;
}
result *= winning;
}
var result2: usize = 1;
var winning2: usize = 0;
for (0..bigRace.time - 1) |speed| {
const distance = speed * (bigRace.time - speed);
if (distance > bigRace.distance) winning2 += 1;
}
result2 *= winning2;
return .{ .a = result, .b = result2 };
}
test "silver" {
const input =
\\Time: 7 15 30
\\Distance: 9 40 200
;
const sln = try solve(std.testing.allocator, input);
try std.testing.expectEqual(@as(usize, 288), sln.a);
}
test "gold" {
const input =
\\Time: 7 15 30
\\Distance: 9 40 200
;
const sln = try solve(std.testing.allocator, input);
try std.testing.expectEqual(@as(usize, 288), sln.b);
}