day12a.zig 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. const std = @import("std");
  2. const shapeModule = @import("shape.zig");
  3. const inputModule = @import("input.zig");
  4. const areaModule = @import("area.zig");
  5. const coordModule = @import("coord.zig");
  6. const unionFindModule = @import("unionfind.zig");
  7. const areacacheModule = @import("areacache.zig");
  8. const Shape = shapeModule.Shape;
  9. const Area = areaModule.Area;
  10. const Coord = coordModule.Coord;
  11. const UnionFind = unionFindModule.UnionFind;
  12. const AreaCache = areacacheModule.AreaCache;
  13. const AreaCacheResult = areacacheModule.AreaCacheResult;
  14. const AreaHashContext = areacacheModule.AreaHashContext;
  15. const kShapeSize = shapeModule.kShapeSize;
  16. const readInputIntoString = inputModule.readInputIntoString;
  17. const parseInput = inputModule.parseInput;
  18. pub fn calculateShapeSizes(allocator: std.mem.Allocator, shapeTransforms: []const []const Shape) ![]usize{
  19. var shapeSizes = try allocator.alloc(usize, shapeTransforms.len);
  20. for (0..shapeTransforms.len) |i| {
  21. shapeSizes[i] = 0;
  22. for (shapeTransforms[i][0].data) |d| {
  23. if (d != '.') {
  24. shapeSizes[i] += 1;
  25. }
  26. }
  27. }
  28. return shapeSizes;
  29. }
  30. pub fn calcShapesTotalSize(shapeCounts: []i32, shapeSizes: []usize) usize {
  31. var totalSize: usize = 0;
  32. for (0..shapeCounts.len) |i| {
  33. totalSize += shapeSizes[i] * @as(usize, @abs(shapeCounts[i]));
  34. }
  35. return totalSize;
  36. }
  37. pub fn canContainShapes(allocator: std.mem.Allocator, area: *const Area,
  38. shapeCounts: []i32, shapeTransforms: []const []const Shape,
  39. shapeSizes: []usize, minShapeSize: usize,
  40. areaCache: *AreaCache) !bool {
  41. const cacheCheckResult = areaCache.check(area, shapeCounts);
  42. if (cacheCheckResult == AreaCacheResult.kPossible) {
  43. return true;
  44. } else if (cacheCheckResult == AreaCacheResult.kPossible) {
  45. return false;
  46. }
  47. if (calcShapesTotalSize(shapeCounts, shapeSizes) > area.totalFreeSize()) {
  48. try areaCache.addImpossibleCacheEntry(area, shapeCounts);
  49. return false;
  50. }
  51. var allEmpty = true;
  52. for (shapeCounts) |shapeCount| {
  53. if (shapeCount != 0) {
  54. allEmpty = false;
  55. break;
  56. }
  57. }
  58. if (allEmpty) {
  59. return true;
  60. }
  61. for (0 .. shapeCounts.len) |shapeIndex| {
  62. if (shapeCounts[shapeIndex] == 0) {
  63. continue;
  64. }
  65. for (0..shapeTransforms[shapeIndex].len) |shapeVariant| {
  66. for (0 .. @intCast(area.rows)) |row| {
  67. for (0 .. @intCast(area.cols)) |col| {
  68. if (try area.appendShape(
  69. allocator,
  70. &shapeTransforms[shapeIndex][shapeVariant],
  71. @intCast(row), @intCast(col), '#')) |*newArea| {
  72. defer newArea.deinit();
  73. var mutableArea: Area = newArea.*;
  74. var unionFind = try UnionFind.init(allocator, &mutableArea);
  75. for (0 .. @intCast(mutableArea.rows)) |unionRow| {
  76. for (0 .. @intCast(mutableArea.cols)) |unionCol| {
  77. if (mutableArea.getCell(@intCast(unionRow), @intCast(unionCol)) == '.') {
  78. const nodeAIndex:usize = @intCast(unionRow*@abs(mutableArea.cols) + unionCol);
  79. const nodeARootIndex = unionFind.Find(nodeAIndex);
  80. if (unionFind.nodes[nodeARootIndex].size < minShapeSize) {
  81. mutableArea.setCell(@intCast(unionRow), @intCast(unionCol), '#');
  82. }
  83. }
  84. }
  85. }
  86. unionFind.deinit();
  87. var newShapeCounts = try allocator.alloc(i32, shapeCounts.len);
  88. defer allocator.free(newShapeCounts);
  89. std.mem.copyForwards(i32, newShapeCounts, shapeCounts);
  90. newShapeCounts[shapeIndex] -= 1;
  91. if (try canContainShapes(allocator, newArea, newShapeCounts,
  92. shapeTransforms, shapeSizes, minShapeSize,
  93. areaCache)) {
  94. try areaCache.addPossibleCacheEntry(area, newShapeCounts);
  95. return true;
  96. }
  97. }
  98. }
  99. }
  100. }
  101. }
  102. try areaCache.addImpossibleCacheEntry(area, shapeCounts);
  103. return false;
  104. }
  105. pub fn main() !void {
  106. var gpa = std.heap.GeneralPurposeAllocator(.{}){};
  107. const allocator = gpa.allocator();
  108. const inputBuffer = try readInputIntoString(allocator, "input.txt");
  109. const input = try parseInput(allocator, inputBuffer);
  110. var shapeTransforms: [][]Shape = try allocator.alloc([]Shape, input.shapes.len);
  111. for (0..input.shapes.len) |i| {
  112. var allTransforms = try input.shapes[i].getAllTransforms(allocator);
  113. defer allTransforms.deinit();
  114. shapeTransforms[i] = try allocator.alloc(Shape, allTransforms.count());
  115. var j: usize = 0;
  116. var it = allTransforms.keyIterator();
  117. while (it.next()) |shapeTransform| {
  118. shapeTransforms[i][j] = shapeTransform.*;
  119. j += 1;
  120. }
  121. }
  122. const shapeSizes = try calculateShapeSizes(allocator, shapeTransforms);
  123. defer allocator.free(shapeSizes);
  124. var minShapeSize = shapeSizes[0];
  125. for (shapeSizes) |shapeSize| {
  126. if (shapeSize < minShapeSize) {
  127. minShapeSize = shapeSize;
  128. }
  129. }
  130. var areaCache = try AreaCache.init(allocator);
  131. defer areaCache.deinit();
  132. var counter: usize = 0;
  133. for (0..input.areas.len) |i| {
  134. const area = try Area.init(allocator, input.areas[i].rows, input.areas[i].cols);
  135. defer area.deinit();
  136. if(try canContainShapes(allocator, &area, input.areas[i].shapesCount,
  137. shapeTransforms, shapeSizes, minShapeSize, &areaCache)) {
  138. counter += 1;
  139. try std.fs.File.stdout().writeAll("can contain shapes\n");
  140. } else {
  141. try std.fs.File.stdout().writeAll("CAN't contain shapes\n");
  142. }
  143. }
  144. try std.fs.File.stdout().writeAll(
  145. try std.fmt.allocPrint(allocator, "Answer: {d}\n", .{counter}));
  146. }