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.

226 lines
5.7 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) void {
if (this.is_settled) {
return;
}
var min_z: u16 = 1;
for (bricks) |*other| {
if (this.is_above(other.*)) {
settleBrick(bricks, other);
min_z = @max(min_z, other.z.last + 1);
}
}
this.z.last -= (this.z.first - min_z);
this.z.first = min_z;
this.is_settled = true;
}
fn isDisintegratable(bricks: []const Brick, this: Brick) bool {
for (bricks) |other| {
if (other.is_on(this)) {
var supports_number: usize = 0;
for (bricks) |support| {
if (other.is_on(support)) {
supports_number += 1;
}
}
if (supports_number == 1) {
//std.debug.print("{any} is not disintegratable because {any} is on it\n", .{ this, other });
return false;
}
}
}
return true;
}
fn solveForBricks(bricks: []Brick) usize {
for (bricks) |*this| {
settleBrick(bricks, this);
}
//std.debug.print("Settled {d} bricks\n", .{bricks.len});
//for (bricks) |brick| {
//std.debug.print("{any}\n", .{brick});
//}
var result: usize = 0;
for (bricks) |this| {
if (isDisintegratable(bricks, this)) {
//std.debug.print("Can be disintegrated: {any}\n", .{this});
result += 1;
}
}
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});
}