|
@@ -1,119 +1,149 @@
|
|
|
const std = @import("std");
|
|
const std = @import("std");
|
|
|
|
|
|
|
|
-var allocatorBuffer: [100*1024*1024]u8 = undefined;
|
|
|
|
|
-
|
|
|
|
|
-const Shape = struct {
|
|
|
|
|
- data: [9]u8,
|
|
|
|
|
|
|
+const shapeModule = @import("shape.zig");
|
|
|
|
|
+const inputModule = @import("input.zig");
|
|
|
|
|
+const areaModule = @import("area.zig");
|
|
|
|
|
+
|
|
|
|
|
+const Shape = shapeModule.Shape;
|
|
|
|
|
+const Area = areaModule.Area;
|
|
|
|
|
+const kShapeSize = shapeModule.kShapeSize;
|
|
|
|
|
+const readInputIntoString = inputModule.readInputIntoString;
|
|
|
|
|
+const parseInput = inputModule.parseInput;
|
|
|
|
|
+
|
|
|
|
|
+const Coord = struct {
|
|
|
|
|
+ row: u8,
|
|
|
|
|
+ col: u8,
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
- fn getCell(self: *const Shape, row: u8, col: u8) u8 {
|
|
|
|
|
- return self.data[row*3 + col];
|
|
|
|
|
|
|
+pub fn getEligibleCoords(allocator: std.mem.Allocator,
|
|
|
|
|
+ area: Area,
|
|
|
|
|
+ eligibleCoords: *std.ArrayList(Coord)) !void {
|
|
|
|
|
+ eligibleCoords.clearRetainingCapacity();
|
|
|
|
|
+
|
|
|
|
|
+ for (0 .. area.rows) |row| {
|
|
|
|
|
+ for (0 .. area.cols) |col| {
|
|
|
|
|
+ if (area.getCell(@intCast(row), @intCast(col)) == '.') {
|
|
|
|
|
+ var shouldAdd = false;
|
|
|
|
|
+ if (row > 0 and area.getCell(@intCast(row-1), @intCast(col)) != '.') {
|
|
|
|
|
+ shouldAdd = true;
|
|
|
|
|
+ } else if (col > 0 and area.getCell(@intCast(row), @intCast(col-1)) != '.') {
|
|
|
|
|
+ shouldAdd = true;
|
|
|
|
|
+ } else if (row < area.rows - 1 and area.getCell(@intCast(row+1), @intCast(col)) != '.') {
|
|
|
|
|
+ shouldAdd = true;
|
|
|
|
|
+ } else if (col < area.cols - 1 and area.getCell(@intCast(row), @intCast(col+1)) != '.') {
|
|
|
|
|
+ shouldAdd = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (shouldAdd) {
|
|
|
|
|
+ var newEligibleCoord = try eligibleCoords.addOne(allocator);
|
|
|
|
|
+ newEligibleCoord.row = @intCast(row);
|
|
|
|
|
+ newEligibleCoord.col = @intCast(col);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- fn setCell(self: *Shape, row: u8, col: u8, cell: u8) void {
|
|
|
|
|
- self.data[row*3 + col] = cell;
|
|
|
|
|
|
|
+ if (eligibleCoords.items.len == 0 and area.getCell(0, 0) == '.') {
|
|
|
|
|
+ var newEligibleCoord = try eligibleCoords.addOne(allocator);
|
|
|
|
|
+ newEligibleCoord.row = 0;
|
|
|
|
|
+ newEligibleCoord.col = 0;
|
|
|
}
|
|
}
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-const Area = struct {
|
|
|
|
|
- rows: u8,
|
|
|
|
|
- cols: u8,
|
|
|
|
|
- shapesCount: []u8,
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-const Input = struct {
|
|
|
|
|
- shapes: []Shape,
|
|
|
|
|
- areas: []Area,
|
|
|
|
|
-};
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-pub fn parseShape(shapeText: []const u8) Shape {
|
|
|
|
|
- var it = std.mem.tokenizeScalar(u8, shapeText, '\n');
|
|
|
|
|
- _ = it.next(); // skip header
|
|
|
|
|
-
|
|
|
|
|
- var shape: Shape = .{
|
|
|
|
|
- .data = undefined,
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- for (0..3) |row| {
|
|
|
|
|
- const rowText = it.next().?;
|
|
|
|
|
- for (0..3) |col| {
|
|
|
|
|
- shape.setCell(@intCast(row), @intCast(col), rowText[col]);
|
|
|
|
|
|
|
+pub fn calculateShapeSizes(allocator: std.mem.Allocator, shapeTransforms: []const []const Shape) ![]usize{
|
|
|
|
|
+ var shapeSizes = try allocator.alloc(usize, shapeTransforms.len);
|
|
|
|
|
+ for (0..shapeTransforms.len) |i| {
|
|
|
|
|
+ shapeSizes[i] = 0;
|
|
|
|
|
+ for (shapeTransforms[i][0].data) |d| {
|
|
|
|
|
+ if (d != '.') {
|
|
|
|
|
+ shapeSizes[i] += 1;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return shape;
|
|
|
|
|
|
|
+ return shapeSizes;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-pub fn parseArea(allocator: std.mem.Allocator, line: []const u8) !Area {
|
|
|
|
|
- var it = std.mem.tokenizeSequence(u8, line, ": ");
|
|
|
|
|
- const sizeText = it.next().?;
|
|
|
|
|
- const shapesCountText = it.next().?;
|
|
|
|
|
|
|
+pub fn calcShapesTotalSize(shapeCounts: []u8, shapeSizes: []usize) usize {
|
|
|
|
|
+ var totalSize: usize = 0;
|
|
|
|
|
|
|
|
- var sizeTextIt = std.mem.tokenizeScalar(u8, sizeText, 'x');
|
|
|
|
|
- const rowsText = sizeTextIt.next().?;
|
|
|
|
|
- const colsText = sizeTextIt.next().?;
|
|
|
|
|
|
|
+ for (0..shapeCounts.len) |i| {
|
|
|
|
|
+ totalSize += shapeSizes[i] * shapeCounts[i];
|
|
|
|
|
+ }
|
|
|
|
|
+ return totalSize;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- const rows = try std.fmt.parseInt(u8, rowsText, 10);
|
|
|
|
|
- const cols = try std.fmt.parseInt(u8, colsText, 10);
|
|
|
|
|
|
|
|
|
|
- var shapesCountTextIt = std.mem.tokenizeScalar(u8, shapesCountText, ' ');
|
|
|
|
|
- var shapesCount = std.ArrayList(u8).empty;
|
|
|
|
|
- while (shapesCountTextIt.next()) |shapeCountText| {
|
|
|
|
|
- const shapeCount = try shapesCount.addOne(allocator);
|
|
|
|
|
- shapeCount.* = try std.fmt.parseInt(u8, shapeCountText, 10);
|
|
|
|
|
|
|
+pub fn canContainShapes(allocator: std.mem.Allocator, area: Area,
|
|
|
|
|
+ shapeCounts: []u8, shapeTransforms: []const []const Shape,
|
|
|
|
|
+ shapeSizes: []usize) !bool {
|
|
|
|
|
+ // try std.fs.File.stdout().writeAll("canContainShapes: [");
|
|
|
|
|
+ // for (shapeCounts) |shapeCount| {
|
|
|
|
|
+ // try std.fs.File.stdout().writeAll(
|
|
|
|
|
+ // try std.fmt.allocPrint(allocator, " {d} ", .{shapeCount}));
|
|
|
|
|
+ // }
|
|
|
|
|
+ // try std.fs.File.stdout().writeAll("]\n");
|
|
|
|
|
+
|
|
|
|
|
+ if (calcShapesTotalSize(shapeCounts, shapeSizes) > area.totalFreeSize()) {
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ var eligibleCoords = std.ArrayList(Coord).empty;
|
|
|
|
|
+ defer eligibleCoords.deinit(allocator);
|
|
|
|
|
|
|
|
- const area: Area = .{
|
|
|
|
|
- .rows = rows,
|
|
|
|
|
- .cols = cols,
|
|
|
|
|
- .shapesCount = shapesCount.items,
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ var allEmpty = true;
|
|
|
|
|
+ for (shapeCounts) |shapeCount| {
|
|
|
|
|
+ if (shapeCount != 0) {
|
|
|
|
|
+ allEmpty = false;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (allEmpty) {
|
|
|
|
|
+ try area.print(allocator);
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return area;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ for (0 .. shapeCounts.len) |shapeIndex| {
|
|
|
|
|
+ if (shapeCounts[shapeIndex] == 0) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-pub fn parseInput(allocator: std.mem.Allocator, inputBuffer: []u8) !Input {
|
|
|
|
|
- var shapes = std.ArrayList(Shape).empty;
|
|
|
|
|
- var areas = std.ArrayList(Area).empty;
|
|
|
|
|
-
|
|
|
|
|
- var i = std.mem.tokenizeSequence(u8, inputBuffer, "\n\n");
|
|
|
|
|
- while (i.next()) |inputBlock| {
|
|
|
|
|
- if (inputBlock.len >= 2 and inputBlock[1] == ':') {
|
|
|
|
|
- const shape = try shapes.addOne(allocator);
|
|
|
|
|
- shape.* = parseShape(inputBlock);
|
|
|
|
|
- } else {
|
|
|
|
|
- var it = std.mem.tokenizeScalar(u8, inputBlock, '\n');
|
|
|
|
|
- while(it.next()) |line| {
|
|
|
|
|
- const area = try areas.addOne(allocator);
|
|
|
|
|
- area.* = try parseArea(allocator, line);
|
|
|
|
|
|
|
+ for (0..shapeTransforms[shapeIndex].len) |shapeVariant| {
|
|
|
|
|
+ try getEligibleCoords(allocator, area, &eligibleCoords);
|
|
|
|
|
+
|
|
|
|
|
+ for (eligibleCoords.items) |coord| {
|
|
|
|
|
+ const row = coord.row;
|
|
|
|
|
+ const col = coord.col;
|
|
|
|
|
+
|
|
|
|
|
+ if (try area.appendShape(
|
|
|
|
|
+ allocator,
|
|
|
|
|
+ &shapeTransforms[shapeIndex][shapeVariant],
|
|
|
|
|
+ @intCast(row), @intCast(col), '#')) |newArea| {
|
|
|
|
|
+ defer newArea.deinit();
|
|
|
|
|
+
|
|
|
|
|
+ // try std.fs.File.stdout().writeAll("Step: \n");
|
|
|
|
|
+ // try newArea.print(allocator);
|
|
|
|
|
+ // try std.fs.File.stdout().writeAll("\n");
|
|
|
|
|
+
|
|
|
|
|
+ var newShapeCounts = try allocator.alloc(u8, shapeCounts.len);
|
|
|
|
|
+ defer allocator.free(newShapeCounts);
|
|
|
|
|
+ std.mem.copyForwards(u8, newShapeCounts, shapeCounts);
|
|
|
|
|
+ newShapeCounts[shapeIndex] -= 1;
|
|
|
|
|
+
|
|
|
|
|
+ if (try canContainShapes(allocator, newArea, newShapeCounts,
|
|
|
|
|
+ shapeTransforms, shapeSizes)) {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const input: Input = .{
|
|
|
|
|
- .shapes = shapes.items,
|
|
|
|
|
- .areas = areas.items,
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- return input;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-pub fn readInputIntoString(allocator: std.mem.Allocator, fileName: []const u8) ![]u8 {
|
|
|
|
|
- const inputFile = try std.fs.cwd().openFile(
|
|
|
|
|
- fileName, .{.mode = .read_only,});
|
|
|
|
|
- defer inputFile.close();
|
|
|
|
|
-
|
|
|
|
|
- var inputFileReader = inputFile.reader(
|
|
|
|
|
- try allocator.alignedAlloc(u8, null, 1024));
|
|
|
|
|
- const inputFileSize = try inputFileReader.getSize();
|
|
|
|
|
-
|
|
|
|
|
- const inputBuffer = try allocator.alignedAlloc(u8, null, inputFileSize);
|
|
|
|
|
- try inputFileReader.interface.readSliceAll(inputBuffer);
|
|
|
|
|
- return inputBuffer;
|
|
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pub fn main() !void {
|
|
pub fn main() !void {
|
|
|
- var fb_alloc = std.heap.FixedBufferAllocator.init(&allocatorBuffer);
|
|
|
|
|
- const allocator = fb_alloc.allocator();
|
|
|
|
|
|
|
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
|
|
|
+ const allocator = gpa.allocator();
|
|
|
|
|
|
|
|
const inputBuffer = try readInputIntoString(allocator, "input.txt");
|
|
const inputBuffer = try readInputIntoString(allocator, "input.txt");
|
|
|
const input = try parseInput(allocator, inputBuffer);
|
|
const input = try parseInput(allocator, inputBuffer);
|
|
@@ -128,18 +158,39 @@ pub fn main() !void {
|
|
|
try std.fs.File.stdout().writeAll("]\n");
|
|
try std.fs.File.stdout().writeAll("]\n");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- for (input.shapes) |shape| {
|
|
|
|
|
- try std.fs.File.stdout().writeAll("shape:\n");
|
|
|
|
|
- for (0..3) |row| {
|
|
|
|
|
- for (0..3) |col| {
|
|
|
|
|
- const cell = shape.getCell(@intCast(row), @intCast(col));
|
|
|
|
|
- try std.fs.File.stdout().writeAll(
|
|
|
|
|
- try std.fmt.allocPrint(allocator, "{c}", .{cell}));
|
|
|
|
|
|
|
+ var shapeTransforms: [][]Shape = try allocator.alloc([]Shape, input.shapes.len);
|
|
|
|
|
+ for (0..input.shapes.len) |i| {
|
|
|
|
|
+ var allTransforms = try input.shapes[i].getAllTransforms(allocator);
|
|
|
|
|
+ defer allTransforms.deinit();
|
|
|
|
|
|
|
|
- }
|
|
|
|
|
- try std.fs.File.stdout().writeAll("\n");
|
|
|
|
|
|
|
+ shapeTransforms[i] = try allocator.alloc(Shape, allTransforms.count());
|
|
|
|
|
+
|
|
|
|
|
+ var j: usize = 0;
|
|
|
|
|
+ var it = allTransforms.keyIterator();
|
|
|
|
|
+ while (it.next()) |shapeTransform| {
|
|
|
|
|
+ shapeTransforms[i][j] = shapeTransform.*;
|
|
|
|
|
+ j += 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const shapeSizes = try calculateShapeSizes(allocator, shapeTransforms);
|
|
|
|
|
+ defer allocator.free(shapeSizes);
|
|
|
|
|
+
|
|
|
|
|
+ var counter: usize = 0;
|
|
|
|
|
+ for (0..input.areas.len) |i| {
|
|
|
|
|
+ const area = try Area.init(allocator, input.areas[i].rows, input.areas[i].cols);
|
|
|
|
|
+ defer area.deinit();
|
|
|
|
|
+
|
|
|
|
|
+ if(try canContainShapes(allocator, area, input.areas[i].shapesCount, shapeTransforms, shapeSizes)) {
|
|
|
|
|
+ try std.fs.File.stdout().writeAll("Can contain shapes!\n");
|
|
|
|
|
+ counter += 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ try std.fs.File.stdout().writeAll("Can NOT contain shapes!\n");
|
|
|
}
|
|
}
|
|
|
- try std.fs.File.stdout().writeAll("\n");
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ try std.fs.File.stdout().writeAll(
|
|
|
|
|
+ try std.fmt.allocPrint(allocator, "Answer: {d}\n", .{counter}));
|
|
|
}
|
|
}
|
|
|
|
|
|