day8b.zig 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. const std = @import("std");
  2. var printBuffer: [1024]u8 = undefined;
  3. var allocatorBuffer: [100*1024*1024]u8 = undefined;
  4. const Junction = struct {
  5. x: i64 = 0,
  6. y: i64 = 0,
  7. z: i64 = 0,
  8. };
  9. const JunctionPair = struct {
  10. a: usize = 0,
  11. b: usize = 0,
  12. pub fn distanceSquared(self: JunctionPair, junctions: []Junction) i64 {
  13. const ja = &junctions[self.a];
  14. const jb = &junctions[self.b];
  15. const dx = ja.x - jb.x;
  16. const dy = ja.y - jb.y;
  17. const dz = ja.z - jb.z;
  18. return dx * dx + dy * dy + dz * dz;
  19. }
  20. };
  21. const JunctionIdNode = struct {
  22. id: usize = 0,
  23. node: std.DoublyLinkedList.Node = .{},
  24. };
  25. const Circuit = struct {
  26. junctions: std.DoublyLinkedList = .{},
  27. node: std.DoublyLinkedList.Node = .{},
  28. };
  29. fn junctionPairCompareLT(junctions: []Junction, left: JunctionPair, right: JunctionPair) bool {
  30. return left.distanceSquared(junctions) < right.distanceSquared(junctions);
  31. }
  32. const Error = error {
  33. JunctionIdNotFound,
  34. };
  35. fn findCircuitForJunction(circuits: std.DoublyLinkedList, junctionId: usize) !*std.DoublyLinkedList.Node {
  36. var circuitIter = circuits.first;
  37. while (circuitIter) |circuitNode| : (circuitIter = circuitNode.next) {
  38. const circuit: *Circuit = @fieldParentPtr("node", circuitNode);
  39. var found = false;
  40. var junctionIdIter = circuit.junctions.first;
  41. while (junctionIdIter) |node| : (junctionIdIter = node.next) {
  42. const junctionIdNode: *JunctionIdNode = @fieldParentPtr("node", node);
  43. if (junctionIdNode.id == junctionId) {
  44. found = true;
  45. break;
  46. }
  47. }
  48. if (found) {
  49. return circuitNode;
  50. }
  51. }
  52. return Error.JunctionIdNotFound;
  53. }
  54. pub fn main() !void {
  55. var fb_alloc = std.heap.FixedBufferAllocator.init(&allocatorBuffer);
  56. var allocator = fb_alloc.allocator();
  57. const inputFile = try std.fs.cwd().openFile(
  58. "input.txt",
  59. .{
  60. .mode = .read_only,
  61. },
  62. );
  63. defer inputFile.close();
  64. var inputFileBuffer: [1024]u8 = undefined;
  65. var inputFileReader = inputFile.reader(&inputFileBuffer);
  66. const inputFileSize = try inputFileReader.getSize();
  67. const inputBuffer = try allocator.alloc(u8, inputFileSize);
  68. try inputFileReader.interface.readSliceAll(inputBuffer);
  69. var junctions = std.ArrayList(Junction).empty;
  70. var i = std.mem.tokenizeScalar(u8, inputBuffer, '\n');
  71. while (i.next()) |newJunctionText| {
  72. var j = std.mem.tokenizeAny(u8, newJunctionText, ",\n");
  73. var newJunction = try junctions.addOne(allocator);
  74. newJunction.x = try std.fmt.parseInt(i64, j.next().?, 10);
  75. newJunction.y = try std.fmt.parseInt(i64, j.next().?, 10);
  76. newJunction.z = try std.fmt.parseInt(i64, j.next().?, 10);
  77. }
  78. var junctionPairs = std.ArrayList(JunctionPair).empty;
  79. for (0..junctions.items.len) |a| {
  80. for (a+1..junctions.items.len) |b| {
  81. var newJunctionPair = try junctionPairs.addOne(allocator);
  82. newJunctionPair.a = a;
  83. newJunctionPair.b = b;
  84. }
  85. }
  86. std.sort.block(JunctionPair, junctionPairs.items, junctions.items, junctionPairCompareLT);
  87. var junctionIdNodeStorage = try std.ArrayList(JunctionIdNode).initCapacity(allocator, junctions.items.len);
  88. var circuitsStorage = try std.ArrayList(Circuit).initCapacity(allocator, junctions.items.len);
  89. var circuits: std.DoublyLinkedList = .{};
  90. for (0..junctions.items.len) |a| {
  91. var newJunctionIdNode = try junctionIdNodeStorage.addOne(allocator);
  92. newJunctionIdNode.id = a;
  93. var newCircuit = try circuitsStorage.addOne(allocator);
  94. newCircuit.junctions = .{};
  95. newCircuit.junctions.append(&newJunctionIdNode.node);
  96. circuits.append(&newCircuit.node);
  97. }
  98. var circuitsCount:usize = junctions.items.len;
  99. for (0..junctionPairs.items.len) |wire| {
  100. const a = junctionPairs.items[wire].a;
  101. const b = junctionPairs.items[wire].b;
  102. const circuitANode = try findCircuitForJunction(circuits, a);
  103. const circuitBNode = try findCircuitForJunction(circuits, b);
  104. if (circuitANode == circuitBNode) {
  105. continue;
  106. }
  107. const circuitA: *Circuit = @fieldParentPtr("node", circuitANode);
  108. const circuitB: *Circuit = @fieldParentPtr("node", circuitBNode);
  109. circuitA.junctions.concatByMoving(&circuitB.junctions);
  110. circuits.remove(circuitBNode);
  111. circuitsCount -= 1;
  112. if (circuitsCount == 1) {
  113. try std.fs.File.stdout().writeAll(
  114. try std.fmt.bufPrint(&printBuffer, "{}\n", .{junctions.items[a].x*junctions.items[b].x}));
  115. break;
  116. }
  117. }
  118. }