aoc-2020-zig

git clone https://git.sinitax.com/sinitax/aoc-2020-zig
Log | Files | Refs | README | sfeed.txt

commit 2a2a7f93fca42a62e23f456625d8ee29301c5782
parent 37bcc7dedc24240162a4869bafc5e375c6cbf4eb
Author: Louis Burda <quent.burda@gmail.com>
Date:   Thu, 24 Dec 2020 08:53:37 +0100

optimized rewrite of day 23 (part 2 not working)

Diffstat:
Msrc/day23/main.zig | 215++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
1 file changed, 120 insertions(+), 95 deletions(-)

diff --git a/src/day23/main.zig b/src/day23/main.zig @@ -1,137 +1,162 @@ const std = @import("std"); const aoc = @import("aoc"); -// totally overengineered.. -const Ring = struct { - list: std.ArrayList(u32), - indeces: std.ArrayList(*usize), - +// Links in this list are arranges in a circle +const RingLink = struct { + data: u32, + next: *RingLink, const Self = @This(); - fn init(allocator: *std.mem.Allocator) Self { - return Ring{ - .list = std.ArrayList(u32).init(allocator), - .indeces = std.ArrayList(*usize).init(allocator), - }; - } - - fn deinit(self: *Self) void { - self.list.deinit(); - self.indeces.deinit(); - } - - fn size(self: *Self) usize { - return self.list.items.len; - } - - fn track(self: *Self, p: *usize) !void { - try self.indeces.append(p); - } - - fn untrack(self: *Self, p: *usize) void { - const ind = std.mem.indexOfScalar(*usize, self.indeces.items, p); - if (ind != null) _ = self.indeces.swapRemove(ind.?); - } - - fn advanceIndex(self: *Self, ind: usize, off: i64) usize { - return (ind + @intCast(usize, @mod(off, @intCast(i64, self.list.items.len)) + @intCast(i64, self.list.items.len))) % self.list.items.len; + pub fn insertNext(self: *Self, link: *RingLink) void { + link.next = self.next; + self.next = link; } - fn dist(self: *Self, a: usize, b: usize) usize { // a - b (wrapped) - return ((a % self.size()) + self.size() - (b % self.size())) % self.size(); + pub fn popNext(self: *Self) !*Self { + const nlink = self.next; + if (nlink == self) return error.EmptyRingList; + self.next = nlink.next; + return nlink; } - fn removeAt(self: *Self, ind: usize) u32 { - for (self.indeces.items) |v, i| { - if (v.* > ind) v.* -= 1; + pub fn length(self: *Self) usize { + var count: usize = 1; + var link = self.next; + while (link != self) : (link = link.next) { + count += 1; } - return self.list.orderedRemove(ind); + return count; } - fn insertAt(self: *Self, ind: usize, item: u32) !void { - for (self.indeces.items) |v| { - if (v.* >= ind) v.* += 1; + pub fn advance(self: *Self, count: usize) *RingLink { + var link = self; + var counter: usize = 0; + while (counter < count) : (link = link.next) { + counter += 1; } - try self.list.insert(ind, item); + return link; } }; -fn parseInput(input: []u8, list: *std.ArrayList(u32)) !u32 { +fn parseInput(input: []const u8, lookup: []RingLink, list: *?*RingLink) !u32 { var max: u32 = 0; + var link: *RingLink = undefined; for (input) |c, i| { if (c == '\n') break; const v = try std.fmt.parseInt(u32, input[i .. i + 1], 10); if (v > max) max = v; - try list.append(v); + if (list.* == null) { + list.* = &lookup[v]; + link = list.*.?; + link.next = link; + } else { + link.insertNext(&lookup[v]); + link = link.next; + } } return max; } -fn part1(allocator: *std.mem.Allocator, input: []u8, args: [][]u8) !void { - var ring = Ring.init(allocator); - defer ring.deinit(); +fn doRound(list: *RingLink, len: u32, lookup: []RingLink, current: **RingLink, max: u32, round: usize) !void { + if (aoc.debug) { + std.debug.print("\n-- move {} --\ncups:", .{round}); + + var start = current.*.advance(len - ((round - 1) % len)); + var link = start; + while (true) { + if (link == current.*) { + std.debug.print(" ({})", .{link.data}); + } else { + std.debug.print(" {} ", .{link.data}); + } + link = link.next; + if (link == start) break; + } + std.debug.print("\n", .{}); + } - var max = try parseInput(input, &ring.list); + var target = (current.*.data + max - 2) % max + 1; + var k: usize = 0; + var check = current.*.next; + while (k < 9) : (k += 1) { + if (check.data == target) + target = (target + max - 2) % max + 1; - for (input) |c, i| { - if (c == '\n') break; - const v = try std.fmt.parseInt(u32, input[i .. i + 1], 10); - if (v > max) max = v; - try ring.list.append(v); + check = if (k % 3 == 0) current.*.next else check.next; } - if (ring.size() < 5) return aoc.Error.InvalidInput; + var closest = &lookup[target]; + var i: usize = 0; + while (i < 3) : (i += 1) { + const poplink = try current.*.popNext(); + closest.insertNext(poplink); + closest = poplink; + } - var current: usize = 0; - try ring.track(&current); + current.* = current.*.next; +} - var round: u32 = 0; - while (round < 100) : (round += 1) { - var target = if (ring.list.items[current] == 0) max else ring.list.items[current] - 1; - var closest: usize = current; - for (ring.list.items) |v, i| { - if (ring.dist(target, v) < ring.dist(target, ring.list.items[closest]) and ring.dist(i, current) > 3) { - closest = i; - } - } +fn createLookup(allocator: *std.mem.Allocator, len: usize) ![]RingLink { + var lookup = try allocator.alloc(RingLink, len + 1); + errdefer allocator.free(lookup); - if (aoc.debug) { - std.debug.print("\n-- move {} --\ncups: ", .{round + 1}); - for (ring.list.items) |v, i| { - if (i > 0) std.debug.print(" ", .{}); - if (i == current) { - std.debug.print("({})", .{v}); - } else { - std.debug.print(" {} ", .{v}); - } - } - std.debug.print("\npick up: ", .{}); - } + var i: usize = 1; + while (i <= len) : (i += 1) { + lookup[i] = RingLink{ .data = @intCast(u32, i), .next = undefined }; + } - try ring.track(&closest); - var i: usize = 0; - while (i < 3) : (i += 1) { - if (aoc.debug) { - if (i > 0) std.debug.print(" ", .{}); - std.debug.print("{}", .{ring.list.items[ring.advanceIndex(current, 1)]}); - } - const v = ring.removeAt(ring.advanceIndex(current, 1)); - try ring.insertAt(ring.advanceIndex(closest, @intCast(i64, 1 + i)), v); - } - ring.untrack(&closest); + return lookup; +} + +fn part1(allocator: *std.mem.Allocator, input: []u8, args: [][]u8) !void { + var lookup = try createLookup(allocator, 9); + defer allocator.free(lookup); - if (aoc.debug) std.debug.print("\ndestination: {}\n", .{ring.list.items[closest]}); - current = (current + 1) % ring.list.items.len; + var list: ?*RingLink = null; + const max = try parseInput(input, lookup, &list); + if (list == null) return aoc.Error.InvalidInput; + const real_len = @intCast(u32, list.?.length()); + + var round: usize = 0; + var current = list.?; + while (round < 100) : (round += 1) { + try doRound(list.?, real_len, lookup, &current, max, round + 1); } - var start = std.mem.indexOfScalar(u32, ring.list.items, 1).?; - var i: u32 = 0; - while (i < ring.size() - 1) : (i += 1) { - std.debug.print("{}", .{ring.list.items[ring.advanceIndex(start, 1 + i)]}); + var start = &lookup[1]; + var link = start.next; + while (link != start) : (link = link.next) { + std.debug.print("{}", .{link.data}); } std.debug.print("\n", .{}); } -fn part2(allocator: *std.mem.Allocator, input: []u8, args: [][]u8) !void {} +fn part2(allocator: *std.mem.Allocator, input: []u8, args: [][]u8) !void { + var lookup = try createLookup(allocator, 1000000); + defer allocator.free(lookup); + + var list: ?*RingLink = null; + const max = try parseInput(input, lookup, &list); + if (list == null) return aoc.Error.InvalidInput; + const real_len = list.?.length(); + + var end = list.?.advance(real_len - 1); + var i = real_len + 1; + while (i <= 1000000) : (i += 1) { + end.insertNext(&lookup[i]); + end = end.next; + } + + var round: usize = 0; + var current = list.?; + while (round < 10000000) : (round += 1) { + if (round % 1000000 == 0) std.debug.print(".", .{}); + try doRound(list.?, 1000000, lookup, &current, max, round + 1); + } + std.debug.print("\n", .{}); + + var link = (&lookup[1]).next; + std.debug.print("{} * {} = {}\n", .{ @intCast(u64, link.data), @intCast(u64, link.next.data), @intCast(u64, link.data) * @intCast(u64, link.next.data) }); +} pub const main = aoc.gen_main(part1, part2);