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.
168 lines
5.9 KiB
168 lines
5.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: *Self, needle: T) bool {
|
|
for (0..self.length) |i| {
|
|
if (self.mem[i] == needle) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
fn getMutableSlice(self: *Self) []T {
|
|
return (&self.mem)[0..self.length];
|
|
}
|
|
|
|
fn getSlice(self: *const Self) []const T {
|
|
return self.mem[0..self.length];
|
|
}
|
|
|
|
fn init() Self {
|
|
return Self{
|
|
.mem = undefined,
|
|
.length = 0,
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
fn getNextPoints(char: u8, point: [2]usize) [2][2]usize {
|
|
return switch (char) {
|
|
'L' => .{ .{ point[0] - 1, point[1] }, .{ point[0], point[1] + 1 } },
|
|
'F' => .{ .{ point[0] + 1, point[1] }, .{ point[0], point[1] + 1 } },
|
|
'7' => .{ .{ point[0] + 1, point[1] }, .{ point[0], point[1] - 1 } },
|
|
'J' => .{ .{ point[0] - 1, point[1] }, .{ point[0], point[1] - 1 } },
|
|
'-' => .{ .{ point[0], point[1] - 1 }, .{ point[0], point[1] + 1 } },
|
|
'|' => .{ .{ point[0] - 1, point[1] }, .{ point[0] + 1, point[1] } },
|
|
else => unreachable,
|
|
};
|
|
}
|
|
|
|
fn getNextPoint(char: u8, point: [2]usize, previous_point: [2]usize) [2]usize {
|
|
const next_points = getNextPoints(char, point);
|
|
|
|
if (next_points[0][0] == previous_point[0] and next_points[0][1] == previous_point[1]) {
|
|
return next_points[1];
|
|
}
|
|
|
|
if (next_points[1][0] == previous_point[0] and next_points[1][1] == previous_point[1]) {
|
|
return next_points[0];
|
|
}
|
|
|
|
unreachable;
|
|
}
|
|
|
|
fn getStartingPoint(lines: []const []const u8) [2][2]usize {
|
|
var i: usize = 0;
|
|
while (i < lines.len) : (i += 1) {
|
|
var j: usize = 0;
|
|
while (j < lines[i].len) : (j += 1) {
|
|
if (lines[i][j] == 'S') {
|
|
// Assuming that there is an unique possible orientation (which is true for sample and full inputs)
|
|
if (i == 0) {
|
|
return switch (lines[i + 1][j]) {
|
|
'L', '|', 'J' => .{ .{ i, j }, .{ i + 1, j } },
|
|
'F', '-', '7', '.' => .{ .{ i, j }, .{ i, if (j == 0) j + 1 else j - 1 } },
|
|
else => unreachable,
|
|
};
|
|
} else if (i == lines.len - 1) {
|
|
return switch (lines[i + 1][j]) {
|
|
'F', '|', '7' => .{ .{ i, j }, .{ i - 1, j } },
|
|
'L', '-', 'J', '.' => .{ .{ i, j }, .{ i, if (j == 0) j + 1 else j - 1 } },
|
|
else => unreachable,
|
|
};
|
|
} else if (j == 0) {
|
|
return switch (lines[i][j + 1]) {
|
|
'7', '-', 'J' => .{ .{ i, j }, .{ i, j + 1 } },
|
|
'F', '|', 'L', '.' => .{ .{ i, j }, .{ if (i == 0) i + 1 else i - 1, j } },
|
|
else => unreachable,
|
|
};
|
|
} else if (j == lines[i].len - 1) {
|
|
return switch (lines[i][j + 1]) {
|
|
'F', '-', 'L' => .{ .{ i, j }, .{ i, j - 1 } },
|
|
'7', '|', 'J', '.' => .{ .{ i, j }, .{ if (i == 0) i + 1 else i - 1, j } },
|
|
else => unreachable,
|
|
};
|
|
} else {
|
|
if (lines[i - 1][j] == 'F' or lines[i - 1][j] == '|' or lines[i - 1][j] == '7') {
|
|
return .{ .{ i, j }, .{ i - 1, j } };
|
|
}
|
|
if (lines[i + 1][j] == 'L' or lines[i + 1][j] == '|' or lines[i + 1][j] == 'J') {
|
|
return .{ .{ i, j }, .{ i + 1, j } };
|
|
}
|
|
if (lines[i][j - 1] == 'F' or lines[i][j - 1] == '-' or lines[i][j - 1] == 'L') {
|
|
return .{ .{ i, j }, .{ i, j - 1 } };
|
|
}
|
|
unreachable;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
unreachable;
|
|
}
|
|
|
|
fn solveLines(lines: []const []const u8) usize {
|
|
const starting_point_info = getStartingPoint(lines);
|
|
const starting_point = starting_point_info[0];
|
|
|
|
var path_length: usize = 1;
|
|
var previous_point = starting_point_info[0];
|
|
var current_point = starting_point_info[1];
|
|
while (current_point[0] != starting_point[0] or current_point[1] != starting_point[1]) {
|
|
const next_point = getNextPoint(lines[current_point[0]][current_point[1]], current_point, previous_point);
|
|
previous_point = current_point;
|
|
current_point = next_point;
|
|
path_length += 1;
|
|
}
|
|
|
|
return path_length / 2;
|
|
}
|
|
|
|
pub fn solveAll(reader: anytype) !usize {
|
|
var result: usize = 0;
|
|
while (true) {
|
|
var allocator_buffer: [100000]u8 = undefined;
|
|
var fba = std.heap.FixedBufferAllocator.init(&allocator_buffer);
|
|
var allocator = fba.allocator();
|
|
|
|
var lines = StackList([]const u8, usize, 200).init();
|
|
var empty_line_reached = false;
|
|
|
|
var line_buffer: [1000]u8 = undefined;
|
|
while (try reader.readUntilDelimiterOrEof(&line_buffer, '\n')) |line| {
|
|
if (line.len == 0) {
|
|
empty_line_reached = true;
|
|
break;
|
|
}
|
|
lines.add(try allocator.dupe(u8, line));
|
|
}
|
|
|
|
result += solveLines(lines.getSlice());
|
|
|
|
if (!empty_line_reached) {
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn main() !void {
|
|
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();
|
|
const result = try solveAll(&reader);
|
|
try stdout.print("{d}\n", .{result});
|
|
}
|
|
|