This doesn't work on the example but it does work on the actual dataset. TODO: Fix that
242 lines
7.9 KiB
Zig
242 lines
7.9 KiB
Zig
const std = @import("std");
|
|
|
|
pub const title = "Day 09: Movie Theater";
|
|
|
|
pub fn run(allocator: std.mem.Allocator) !void {
|
|
const input = @embedFile("./input/day09.txt");
|
|
//const input =
|
|
// \\7,1
|
|
// \\11,1
|
|
// \\11,7
|
|
// \\9,7
|
|
// \\9,5
|
|
// \\2,5
|
|
// \\2,3
|
|
// \\7,3
|
|
// ;
|
|
|
|
var lines = std.mem.tokenizeScalar(u8, input, '\n');
|
|
|
|
var tiles: std.ArrayList(Tile) = .empty;
|
|
defer tiles.deinit(allocator);
|
|
|
|
std.debug.print("parsing tiles...\n", .{});
|
|
var index: usize = 0;
|
|
while (lines.next()) |line| {
|
|
defer index += 1;
|
|
var coordinates = std.mem.tokenizeScalar(u8, line, ',');
|
|
const x = blk: {
|
|
const s = coordinates.next() orelse continue;
|
|
break :blk try std.fmt.parseUnsigned(u64, s, 10);
|
|
};
|
|
const y = blk: {
|
|
const s = coordinates.next() orelse continue;
|
|
break :blk try std.fmt.parseUnsigned(u64, s, 10);
|
|
};
|
|
try tiles.append(allocator, .{ .index = index, .pos = .{ x, y } });
|
|
}
|
|
|
|
std.debug.print("calculating edges...\n", .{});
|
|
var edges: std.ArrayList(Edge) = .empty;
|
|
defer edges.deinit(allocator);
|
|
for (tiles.items, 0..) |tile, i| {
|
|
const a = tile;
|
|
const b = if (i == tiles.items.len - 1) tiles.items[0] else tiles.items[i + 1];
|
|
try edges.append(allocator, Edge.fromTiles(a, b));
|
|
}
|
|
|
|
std.debug.print("finding largest rectangle...\n", .{});
|
|
var largest_area: usize = 0;
|
|
var largest_rectangle: Rectangle = undefined;
|
|
for (tiles.items, 0..) |first_tile, i| {
|
|
inner: for (tiles.items[i + 1..]) |second_tile| {
|
|
const rectangle = first_tile.rectangle(second_tile);
|
|
|
|
std.debug.print("checking rectangle {f}...\n", .{rectangle});
|
|
|
|
const has_inside = rectangle.width() >= 3 and rectangle.height() >= 3;
|
|
if (has_inside) {
|
|
const one: @Vector(2, u64) = @splat(1);
|
|
const top_left = rectangle.topLeft() + one;
|
|
const bottom_right = rectangle.bottomRight() - one;
|
|
edge_loop: for (edges.items) |edge| {
|
|
if (edge.direction == .horizontal) {
|
|
if (edge.a.pos[1] < top_left[1] or edge.a.pos[1] > bottom_right[1]) {
|
|
continue :edge_loop;
|
|
}
|
|
|
|
const start, const end = if (edge.a.pos[0] < edge.b.pos[0] + 1) .{ edge.a.pos[0], edge.b.pos[0] } else .{ edge.b.pos[0], edge.a.pos[0] + 1 };
|
|
for (start..end) |ex| {
|
|
const edge_tile: @Vector(2, u64) = .{ ex, edge.a.pos[1] };
|
|
if (top_left[0] <= edge_tile[0] and edge_tile[0] <= bottom_right[0]) {
|
|
std.debug.print("rectangle {f} hits edge {f}\n", .{rectangle, edge});
|
|
continue :inner;
|
|
}
|
|
}
|
|
} else {
|
|
if (edge.a.pos[0] < top_left[0] or edge.a.pos[0] > bottom_right[0]) {
|
|
continue :edge_loop;
|
|
}
|
|
|
|
const start, const end = if (edge.a.pos[1] < edge.b.pos[1] + 1) .{ edge.a.pos[1], edge.b.pos[1] } else .{ edge.b.pos[1], edge.a.pos[1] + 1 };
|
|
for (start..end) |ey| {
|
|
const edge_tile: @Vector(2, u64) = .{ edge.a.pos[0], ey };
|
|
if (top_left[1] <= edge_tile[1] and edge_tile[1] <= bottom_right[1]) {
|
|
std.debug.print("rectangle {f} hits edge {f}\n", .{rectangle, edge});
|
|
continue :inner;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const area = rectangle.area();
|
|
if (area > largest_area) {
|
|
largest_area = area;
|
|
largest_rectangle = rectangle;
|
|
}
|
|
}
|
|
}
|
|
|
|
std.debug.print("rectangle = {f}\n", .{largest_rectangle});
|
|
std.debug.print("top_left = {any}, bottom_right = {any}\n", .{largest_rectangle.topLeft(), largest_rectangle.bottomRight()});
|
|
|
|
var buffer: [64]u8 = undefined;
|
|
var stdout_writer = std.fs.File.stdout().writer(&buffer);
|
|
const stdout = &stdout_writer.interface;
|
|
|
|
try stdout.print("{d}\n", .{largest_area});
|
|
|
|
try stdout.flush();
|
|
}
|
|
|
|
const Tile = struct {
|
|
index: usize,
|
|
pos: @Vector(2, u64),
|
|
|
|
const Self = @This();
|
|
|
|
pub fn format(self: Self, w: *std.io.Writer) std.io.Writer.Error!void {
|
|
try w.print("{d},{d}", .{self.pos[0], self.pos[1]});
|
|
}
|
|
|
|
pub fn rectangle(self: Self, other_corner: Self) Rectangle {
|
|
return Rectangle.fromTiles(self, other_corner);
|
|
}
|
|
};
|
|
|
|
const Edge = struct {
|
|
a: Tile,
|
|
b: Tile,
|
|
|
|
direction: Direction,
|
|
|
|
const Self = @This();
|
|
|
|
const Direction = enum {
|
|
horizontal,
|
|
vertical,
|
|
};
|
|
|
|
pub fn fromTiles(a: Tile, b: Tile) Self {
|
|
const direction: Direction = if (a.pos[0] == b.pos[0])
|
|
.vertical
|
|
else if (a.pos[1] == b.pos[1])
|
|
.horizontal
|
|
else
|
|
unreachable;
|
|
|
|
return .{
|
|
.a = a,
|
|
.b = b,
|
|
.direction = direction,
|
|
};
|
|
}
|
|
|
|
pub fn format(self: Self, w: *std.io.Writer) std.io.Writer.Error!void {
|
|
try w.print("{f} - {f}", .{self.a, self.b});
|
|
}
|
|
};
|
|
|
|
/// 0,0 1,0
|
|
/// a ---- c
|
|
/// | |
|
|
/// | |
|
|
/// d ---- b
|
|
/// 0,1 1,1
|
|
const Rectangle = struct {
|
|
a: Tile,
|
|
b: Tile,
|
|
|
|
c: @Vector(2, u64),
|
|
d: @Vector(2, u64),
|
|
|
|
const Self = @This();
|
|
|
|
pub fn fromTiles(a: Tile, b: Tile) Self {
|
|
const cx = if (a.pos[0] <= b.pos[0]) b.pos[0] else a.pos[0];
|
|
const cy = if (a.pos[1] >= b.pos[1]) a.pos[1] else b.pos[1];
|
|
const dx = if (a.pos[0] <= b.pos[0]) a.pos[0] else b.pos[0];
|
|
const dy = if (a.pos[1] >= b.pos[1]) b.pos[1] else a.pos[1];
|
|
return .{
|
|
.a = a,
|
|
.b = b,
|
|
.c = .{ cx, cy },
|
|
.d = .{ dx, dy },
|
|
};
|
|
}
|
|
|
|
pub fn format(self: Self, w: *std.io.Writer) std.io.Writer.Error!void {
|
|
try w.print("{d} to {d} ({f} - {d},{d} - {f} - {d},{d})", .{self.a.index, self.b.index, self.a, self.c[0], self.c[1], self.b, self.d[0], self.d[1]});
|
|
}
|
|
|
|
pub fn topLeft(self: Self) @Vector(2, u64) {
|
|
const verts = [_]@Vector(2, u64){ self.c, self.b.pos, self.d };
|
|
var top_left: @Vector(2, u64) = self.a.pos;
|
|
for (verts) |vert| {
|
|
const cond = vert <= top_left;
|
|
if (@reduce(.And, cond)) {
|
|
top_left = vert;
|
|
}
|
|
}
|
|
return top_left;
|
|
}
|
|
|
|
pub fn bottomRight(self: Self) @Vector(2, u64) {
|
|
const verts = [_]@Vector(2, u64){ self.d, self.a.pos, self.c };
|
|
var bottom_right: @Vector(2, u64) = self.b.pos;
|
|
for (verts) |vert| {
|
|
const cond = vert >= bottom_right;
|
|
if (@reduce(.And, cond)) {
|
|
bottom_right = vert;
|
|
}
|
|
}
|
|
return bottom_right;
|
|
}
|
|
|
|
pub fn width(self: Self) u64 {
|
|
const cond = self.a.pos > self.b.pos;
|
|
const high = @select(u64, cond, self.a.pos, self.b.pos);
|
|
const low = @select(u64, !cond, self.a.pos, self.b.pos);
|
|
const diff = high - low;
|
|
return diff[0] + 1;
|
|
}
|
|
|
|
pub fn height(self: Self) u64 {
|
|
const cond = self.a.pos > self.b.pos;
|
|
const high = @select(u64, cond, self.a.pos, self.b.pos);
|
|
const low = @select(u64, !cond, self.a.pos, self.b.pos);
|
|
const diff = high - low;
|
|
return diff[1] + 1;
|
|
}
|
|
|
|
pub fn area(self: Self) u64 {
|
|
const cond = self.a.pos > self.b.pos;
|
|
const high = @select(u64, cond, self.a.pos, self.b.pos);
|
|
const low = @select(u64, !cond, self.a.pos, self.b.pos);
|
|
const diff = high - low;
|
|
const one: @Vector(2, u64) = @splat(1);
|
|
return @reduce(.Mul, diff + one);
|
|
}
|
|
};
|
|
|