day12a.zig 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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 Shape = shapeModule.Shape;
  6. const Area = areaModule.Area;
  7. const kShapeSize = shapeModule.kShapeSize;
  8. const readInputIntoString = inputModule.readInputIntoString;
  9. const parseInput = inputModule.parseInput;
  10. const Coord = struct {
  11. row: u8,
  12. col: u8,
  13. };
  14. pub fn getEligibleCoords(allocator: std.mem.Allocator,
  15. area: Area,
  16. eligibleCoords: *std.ArrayList(Coord)) !void {
  17. eligibleCoords.clearRetainingCapacity();
  18. for (0 .. area.rows) |row| {
  19. for (0 .. area.cols) |col| {
  20. if (area.getCell(@intCast(row), @intCast(col)) == '.') {
  21. var shouldAdd = false;
  22. if (row > 0 and area.getCell(@intCast(row-1), @intCast(col)) != '.') {
  23. shouldAdd = true;
  24. } else if (col > 0 and area.getCell(@intCast(row), @intCast(col-1)) != '.') {
  25. shouldAdd = true;
  26. } else if (row < area.rows - 1 and area.getCell(@intCast(row+1), @intCast(col)) != '.') {
  27. shouldAdd = true;
  28. } else if (col < area.cols - 1 and area.getCell(@intCast(row), @intCast(col+1)) != '.') {
  29. shouldAdd = true;
  30. }
  31. if (shouldAdd) {
  32. var newEligibleCoord = try eligibleCoords.addOne(allocator);
  33. newEligibleCoord.row = @intCast(row);
  34. newEligibleCoord.col = @intCast(col);
  35. }
  36. }
  37. }
  38. }
  39. if (eligibleCoords.items.len == 0 and area.getCell(0, 0) == '.') {
  40. var newEligibleCoord = try eligibleCoords.addOne(allocator);
  41. newEligibleCoord.row = 0;
  42. newEligibleCoord.col = 0;
  43. }
  44. }
  45. pub fn calculateShapeSizes(allocator: std.mem.Allocator, shapeTransforms: []const []const Shape) ![]usize{
  46. var shapeSizes = try allocator.alloc(usize, shapeTransforms.len);
  47. for (0..shapeTransforms.len) |i| {
  48. shapeSizes[i] = 0;
  49. for (shapeTransforms[i][0].data) |d| {
  50. if (d != '.') {
  51. shapeSizes[i] += 1;
  52. }
  53. }
  54. }
  55. return shapeSizes;
  56. }
  57. pub fn calcShapesTotalSize(shapeCounts: []u8, shapeSizes: []usize) usize {
  58. var totalSize: usize = 0;
  59. for (0..shapeCounts.len) |i| {
  60. totalSize += shapeSizes[i] * shapeCounts[i];
  61. }
  62. return totalSize;
  63. }
  64. pub fn canContainShapes(allocator: std.mem.Allocator, area: Area,
  65. shapeCounts: []u8, shapeTransforms: []const []const Shape,
  66. shapeSizes: []usize) !bool {
  67. // try std.fs.File.stdout().writeAll("canContainShapes: [");
  68. // for (shapeCounts) |shapeCount| {
  69. // try std.fs.File.stdout().writeAll(
  70. // try std.fmt.allocPrint(allocator, " {d} ", .{shapeCount}));
  71. // }
  72. // try std.fs.File.stdout().writeAll("]\n");
  73. if (calcShapesTotalSize(shapeCounts, shapeSizes) > area.totalFreeSize()) {
  74. return false;
  75. }
  76. var eligibleCoords = std.ArrayList(Coord).empty;
  77. defer eligibleCoords.deinit(allocator);
  78. var allEmpty = true;
  79. for (shapeCounts) |shapeCount| {
  80. if (shapeCount != 0) {
  81. allEmpty = false;
  82. break;
  83. }
  84. }
  85. if (allEmpty) {
  86. try area.print(allocator);
  87. return true;
  88. }
  89. for (0 .. shapeCounts.len) |shapeIndex| {
  90. if (shapeCounts[shapeIndex] == 0) {
  91. continue;
  92. }
  93. for (0..shapeTransforms[shapeIndex].len) |shapeVariant| {
  94. try getEligibleCoords(allocator, area, &eligibleCoords);
  95. for (eligibleCoords.items) |coord| {
  96. const row = coord.row;
  97. const col = coord.col;
  98. if (try area.appendShape(
  99. allocator,
  100. &shapeTransforms[shapeIndex][shapeVariant],
  101. @intCast(row), @intCast(col), '#')) |newArea| {
  102. defer newArea.deinit();
  103. // try std.fs.File.stdout().writeAll("Step: \n");
  104. // try newArea.print(allocator);
  105. // try std.fs.File.stdout().writeAll("\n");
  106. var newShapeCounts = try allocator.alloc(u8, shapeCounts.len);
  107. defer allocator.free(newShapeCounts);
  108. std.mem.copyForwards(u8, newShapeCounts, shapeCounts);
  109. newShapeCounts[shapeIndex] -= 1;
  110. if (try canContainShapes(allocator, newArea, newShapeCounts,
  111. shapeTransforms, shapeSizes)) {
  112. return true;
  113. }
  114. }
  115. }
  116. }
  117. }
  118. return false;
  119. }
  120. pub fn main() !void {
  121. var gpa = std.heap.GeneralPurposeAllocator(.{}){};
  122. const allocator = gpa.allocator();
  123. const inputBuffer = try readInputIntoString(allocator, "input.txt");
  124. const input = try parseInput(allocator, inputBuffer);
  125. for (input.areas) |area| {
  126. try std.fs.File.stdout().writeAll(
  127. try std.fmt.allocPrint(allocator, "area: rows={d}, cols={d}, shapes=[ ", .{area.rows, area.cols}));
  128. for (area.shapesCount) |shapeCount| {
  129. try std.fs.File.stdout().writeAll(
  130. try std.fmt.allocPrint(allocator, "{d}, ", .{shapeCount}));
  131. }
  132. try std.fs.File.stdout().writeAll("]\n");
  133. }
  134. var shapeTransforms: [][]Shape = try allocator.alloc([]Shape, input.shapes.len);
  135. for (0..input.shapes.len) |i| {
  136. var allTransforms = try input.shapes[i].getAllTransforms(allocator);
  137. defer allTransforms.deinit();
  138. shapeTransforms[i] = try allocator.alloc(Shape, allTransforms.count());
  139. var j: usize = 0;
  140. var it = allTransforms.keyIterator();
  141. while (it.next()) |shapeTransform| {
  142. shapeTransforms[i][j] = shapeTransform.*;
  143. j += 1;
  144. }
  145. }
  146. const shapeSizes = try calculateShapeSizes(allocator, shapeTransforms);
  147. defer allocator.free(shapeSizes);
  148. var counter: usize = 0;
  149. for (0..input.areas.len) |i| {
  150. const area = try Area.init(allocator, input.areas[i].rows, input.areas[i].cols);
  151. defer area.deinit();
  152. if(try canContainShapes(allocator, area, input.areas[i].shapesCount, shapeTransforms, shapeSizes)) {
  153. try std.fs.File.stdout().writeAll("Can contain shapes!\n");
  154. counter += 1;
  155. }
  156. else {
  157. try std.fs.File.stdout().writeAll("Can NOT contain shapes!\n");
  158. }
  159. }
  160. try std.fs.File.stdout().writeAll(
  161. try std.fmt.allocPrint(allocator, "Answer: {d}\n", .{counter}));
  162. }