You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
6.9 KiB
221 lines
6.9 KiB
const std = @import("std");
|
|
|
|
fn StackList(comptime T: type, comptime capacity_type: type, comptime capacity: capacity_type) type {
|
|
return struct {
|
|
const Self = @This();
|
|
mem: [capacity]T,
|
|
length: capacity_type,
|
|
|
|
fn add(self: *Self, value: T) void {
|
|
self.mem[self.length] = value;
|
|
self.length += 1;
|
|
}
|
|
|
|
fn has(self: *const Self, needle: T) bool {
|
|
for (0..self.length) |i| {
|
|
if (self.mem[i] == needle) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
fn getMutableSlice(self: *Self) []T {
|
|
//var mem_full_slice = &self.mem;
|
|
//var mem_slice: []T = mem_full_slice[0..self.length];
|
|
//return mem_slice;
|
|
return (&self.mem)[0..self.length];
|
|
}
|
|
|
|
fn getSlice(self: *const Self) []const T {
|
|
return self.mem[0..self.length];
|
|
}
|
|
|
|
fn getLoopedValue(self: *const Self, index: usize) T {
|
|
return self.mem[index % self.length];
|
|
}
|
|
|
|
fn reset(self: *Self) void {
|
|
self.length = 0;
|
|
}
|
|
|
|
fn init() Self {
|
|
return Self{
|
|
.mem = undefined,
|
|
.length = 0,
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
const MAX_DIRECTIONS = 270;
|
|
const SIXTEEN_BITS = 65535;
|
|
const FIVE_BITS = 31;
|
|
const END_LINE_MASK = 512 | 256 | 128;
|
|
|
|
const Direction = enum(u8) { Left, Right };
|
|
const Directions = StackList(Direction, usize, MAX_DIRECTIONS);
|
|
|
|
fn parseDirections(line: []const u8) Directions {
|
|
var result = Directions.init();
|
|
|
|
for (line) |char| {
|
|
result.add(switch (char) {
|
|
'L' => .Left,
|
|
'R' => .Right,
|
|
else => unreachable,
|
|
});
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
const Node = struct {
|
|
line_index: u16,
|
|
current_label: u16,
|
|
left_next_label: u16,
|
|
right_next_label: u16,
|
|
};
|
|
|
|
const Nodes = [32 * 32 * 32]Node;
|
|
|
|
fn parseNodeLabel(line: []const u8) u16 {
|
|
var result: u16 = 0;
|
|
for (line) |char| {
|
|
result = (result << 5) + (char - 'A');
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
fn parseNodeLine(nodes: *Nodes, line: []const u8, line_index: u16) void {
|
|
const current_node = Node{
|
|
.line_index = if (line[2] == 'Z') (line_index | END_LINE_MASK) else line_index,
|
|
.current_label = parseNodeLabel(line[0..3]),
|
|
.left_next_label = parseNodeLabel(line[7..10]),
|
|
.right_next_label = parseNodeLabel(line[12..15]),
|
|
};
|
|
nodes[current_node.current_label] = current_node;
|
|
}
|
|
|
|
const TransitionMap = [MAX_DIRECTIONS * 1024]u32;
|
|
|
|
fn createTransitions(nodes: *const Nodes, directions: *const Directions) TransitionMap {
|
|
var result = std.mem.zeroes(TransitionMap);
|
|
for (nodes.*) |node| {
|
|
if (node.current_label == 0) {
|
|
continue;
|
|
}
|
|
|
|
//std.debug.print("Computing transitions for {d}\n", .{node.line_index});
|
|
|
|
for (directions.getSlice(), 0..) |direction, direction_index| {
|
|
const key = (direction_index << 10) | node.line_index;
|
|
const next_direction_index = (direction_index + 1) % directions.length;
|
|
const next = (@as(u32, @intCast(next_direction_index)) << 10) | nodes[
|
|
switch (direction) {
|
|
.Left => node.left_next_label,
|
|
.Right => node.right_next_label,
|
|
}
|
|
].line_index;
|
|
result[key] = next;
|
|
//std.debug.print("Saved transition from {d} to {d}\n", .{ key, next });
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
const CurrentNodes = [6]u32;
|
|
|
|
fn getStartingNodes(nodes: *const Nodes) CurrentNodes {
|
|
var starting_nodes = std.mem.zeroes(CurrentNodes);
|
|
var current_index: usize = 0;
|
|
for (nodes.*) |node| {
|
|
if (node.line_index != 0 and node.current_label & FIVE_BITS == 0) {
|
|
if (current_index == 0) {
|
|
for (&starting_nodes) |*starting_node| {
|
|
starting_node.* = node.line_index;
|
|
}
|
|
} else {
|
|
starting_nodes[current_index] = node.line_index;
|
|
}
|
|
|
|
current_index += 1;
|
|
}
|
|
}
|
|
|
|
return starting_nodes;
|
|
}
|
|
|
|
fn solve(nodes: *const Nodes, directions: *const Directions) u64 {
|
|
std.debug.print("Inside solve\n", .{});
|
|
const transitions = createTransitions(nodes, directions);
|
|
const starting = getStartingNodes(nodes);
|
|
//var current: CurrentNodes = .{ 203941, 204125, 203913, 204388, 204337, 203941 };
|
|
|
|
std.debug.print("Starting points: {any}\n", .{starting});
|
|
const DEBUG_MASK = (1 << 27) - 1;
|
|
|
|
var current0 = starting[0];
|
|
var current1 = starting[1];
|
|
var current2 = starting[2];
|
|
var current3 = starting[3];
|
|
var current4 = starting[4];
|
|
var current5 = starting[5];
|
|
var i: usize = 0;
|
|
while (true) : (i += 1) {
|
|
// Main loop, with hundreds of billions of iterations, so it is performance-critical.
|
|
if (i & DEBUG_MASK == 0) {
|
|
std.debug.print(
|
|
"Points at step {d}: {d} {d} {d} {d} {d} {d} (raw: {any})\n",
|
|
.{ i, current0 & 1023, current1 & 1023, current2 & 1023, current3 & 1023, current4 & 1023, current5 & 1023, .{ current0, current1, current2, current3, current4, current5 } },
|
|
);
|
|
}
|
|
|
|
if (current0 & current1 & current2 & current3 & current4 & current5 & @as(u32, END_LINE_MASK) == @as(u32, END_LINE_MASK)) {
|
|
std.debug.print(
|
|
"Points at step {d}: {d} {d} {d} {d} {d} {d} (raw: {any})\n",
|
|
.{ i, current0 & 1023, current1 & 1023, current2 & 1023, current3 & 1023, current4 & 1023, current5 & 1023, .{ current0, current1, current2, current3, current4, current5 } },
|
|
);
|
|
break;
|
|
}
|
|
|
|
current0 = transitions[@as(usize, current0)];
|
|
current1 = transitions[@as(usize, current1)];
|
|
current2 = transitions[@as(usize, current2)];
|
|
current3 = transitions[@as(usize, current3)];
|
|
current4 = transitions[@as(usize, current4)];
|
|
current5 = transitions[@as(usize, current5)];
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
pub fn main() !void {
|
|
std.debug.print("First line of main\n", .{});
|
|
const stdout = std.io.getStdOut().writer();
|
|
|
|
const raw_in = std.io.getStdIn();
|
|
var buffered_reader = std.io.bufferedReader(raw_in.reader());
|
|
var reader = buffered_reader.reader();
|
|
|
|
var line_buffer: [1000]u8 = undefined;
|
|
const first_line = (try reader.readUntilDelimiterOrEof(&line_buffer, '\n')).?;
|
|
var directions = parseDirections(first_line);
|
|
_ = try reader.readUntilDelimiterOrEof(&line_buffer, '\n');
|
|
|
|
std.debug.print("Creating nodes\n", .{});
|
|
var nodes = std.mem.zeroes(Nodes);
|
|
std.debug.print("Created nodes\n", .{});
|
|
var line_index: u16 = 3;
|
|
while (try reader.readUntilDelimiterOrEof(&line_buffer, '\n')) |line| {
|
|
parseNodeLine(&nodes, line, line_index);
|
|
line_index += 1;
|
|
}
|
|
|
|
std.debug.print("Calling solve\n", .{});
|
|
const result = solve(&nodes, &directions);
|
|
try stdout.print("{d}\n", .{result});
|
|
}
|
|
|