Solutions of most (39 out of 50 so far) puzzles in Zig (system language, alternative for C). My first experience with it.
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.

229 lines
5.8 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 readNumber(comptime T: type, line: []const u8, index: *usize) T {
var result: T = 0;
while (index.* < line.len) : (index.* += 1) {
const char = line[index.*];
switch (char) {
'0'...'9' => {
result = result * 10 + (char - '0');
},
else => {
break;
},
}
}
return result;
}
const Segment = packed struct(u32) {
first: u16,
last: u16,
fn init(a: u16, b: u16) Segment {
if (a < b) {
return .{
.first = a,
.last = b,
};
} else {
return .{
.first = b,
.last = a,
};
}
}
fn intersects(a: Segment, b: Segment) bool {
return a.first <= b.last and a.last >= b.first;
}
};
const Brick = struct {
x: Segment,
y: Segment,
z: Segment,
is_settled: bool,
fn is_above(self: *const Brick, other: Brick) bool {
return Segment.intersects(self.x, other.x) and Segment.intersects(self.y, other.y) and self.z.first > other.z.first;
}
fn is_on(self: *const Brick, other: Brick) bool {
return Segment.intersects(self.x, other.x) and Segment.intersects(self.y, other.y) and self.z.first == other.z.last + 1;
}
pub fn format(value: Brick, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
return writer.print("{d},{d},{d}~{d},{d},{d}", .{ value.x.first, value.y.first, value.z.first, value.x.last, value.y.last, value.z.last });
}
};
fn settleBrick(bricks: []Brick, this: *Brick) usize {
if (this.is_settled) {
return 0;
}
var moved_bricks: usize = 0;
var min_z: u16 = 1;
for (bricks) |*other| {
if (this.is_above(other.*)) {
moved_bricks += settleBrick(bricks, other);
min_z = @max(min_z, other.z.last + 1);
}
}
if (this.z.first != min_z) {
moved_bricks += 1;
}
this.z.last -= (this.z.first - min_z);
this.z.first = min_z;
this.is_settled = true;
return moved_bricks;
}
fn settleBricks(bricks: []Brick) usize {
var result: usize = 0;
for (bricks) |*this| {
result += settleBrick(bricks, this);
}
return result;
}
fn simulateDisintegration(bricks: []const Brick, brick_number: usize) usize {
var simulated_bricks_array: [1500]Brick = undefined;
std.mem.copy(Brick, &simulated_bricks_array, bricks);
var simulated_bricks = simulated_bricks_array[0..bricks.len];
for (simulated_bricks) |*brick| {
brick.*.is_settled = false;
}
simulated_bricks[brick_number].z = Segment.init(0, 0);
simulated_bricks[brick_number].is_settled = true;
return settleBricks(simulated_bricks);
}
fn solveForBricks(bricks: []Brick) usize {
_ = settleBricks(bricks);
var result: usize = 0;
for (0..bricks.len) |brick_number| {
//std.debug.print("Simulating disintegration of brick {d}\n", .{brick_number});
result += simulateDisintegration(bricks, brick_number);
}
return result;
}
fn solveLines(lines: []const []const u8) usize {
var bricks_list = StackList(Brick, usize, 1500).init();
for (lines) |line| {
var i: usize = 0;
var x1 = readNumber(u16, line, &i);
i += 1;
var y1 = readNumber(u16, line, &i);
i += 1;
var z1 = readNumber(u16, line, &i);
i += 1;
var x2 = readNumber(u16, line, &i);
i += 1;
var y2 = readNumber(u16, line, &i);
i += 1;
var z2 = readNumber(u16, line, &i);
bricks_list.add(.{
.x = Segment.init(x1, x2),
.y = Segment.init(y1, y2),
.z = Segment.init(z1, z2),
.is_settled = false,
});
}
return solveForBricks(bricks_list.getMutableSlice());
}
pub fn solveAll(reader: anytype) !usize {
var result: usize = 0;
while (true) {
var allocator_buffer: [50000]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&allocator_buffer);
var allocator = fba.allocator();
var lines = StackList([]u8, usize, 1500).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});
}