BrickStack.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. namespace Day22;
  2. public class BrickStack
  3. {
  4. private readonly List<Brick> _bricks = new List<Brick>();
  5. private Dictionary<Vec, Brick?> _space = new Dictionary<Vec, Brick?>();
  6. private Vec _min = Vec.Zero;
  7. private Vec _max = Vec.Zero;
  8. public BrickStack()
  9. {
  10. }
  11. public void Add(Brick brick)
  12. {
  13. _bricks.Add(brick);
  14. _min = Min(_min, brick.Start, brick.End);
  15. _max = Max(_max, brick.Start, brick.End);
  16. }
  17. public void Populate()
  18. {
  19. _space = new Dictionary<Vec, Brick?>();
  20. foreach (var b in _bricks.OrderBy(x => x.MinZ))
  21. {
  22. foreach (var p in b.Points())
  23. {
  24. if (!_space.TryAdd(p, b))
  25. {
  26. throw new Exception("Unexpected overlap during populate phase");
  27. }
  28. }
  29. }
  30. }
  31. public void Collapse()
  32. {
  33. foreach (var b in _bricks.OrderBy(x => x.MinZ))
  34. {
  35. var newZ = 1L;
  36. foreach (var p in b.Points())
  37. {
  38. var below = p;
  39. while (below.Z > newZ - 1)
  40. {
  41. var target = _space.GetValueOrDefault(below);
  42. if (target == null || target == b)
  43. {
  44. below = below.Add(Vec.Down);
  45. }
  46. else
  47. {
  48. if (below.Z + 1 > newZ)
  49. {
  50. newZ = below.Z + 1;
  51. }
  52. break;
  53. }
  54. }
  55. }
  56. if (newZ < b.MinZ)
  57. {
  58. MoveDown(b, b.MinZ - newZ);
  59. }
  60. }
  61. }
  62. public void Print()
  63. {
  64. for (var y = _min.Y; y <= _max.Y; y++)
  65. {
  66. for (var z = _min.Z; z <= Math.Min(_max.Z, 19); z++)
  67. {
  68. for (var x = _min.X; x <= _max.X; x++)
  69. {
  70. var brick = _space.GetValueOrDefault(new Vec(x, y, z));
  71. if (brick != null)
  72. {
  73. Console.Write(brick.Label);
  74. }
  75. else
  76. {
  77. Console.Write('.');
  78. }
  79. }
  80. Console.Write(' ');
  81. }
  82. Console.WriteLine();
  83. }
  84. }
  85. public long CountSafeRemoval()
  86. {
  87. var count = 0L;
  88. foreach (var b in _bricks.OrderBy(x => x.MinZ))
  89. {
  90. var above = BricksAbove(b).ToList();
  91. if (above.Count == 0 || above.All(a => BricksBelow(a).Count() >= 2))
  92. {
  93. count++;
  94. }
  95. }
  96. return count;
  97. }
  98. private Vec Min(params Vec[] vectors)
  99. {
  100. var x = vectors[0].X;
  101. var y = vectors[0].Y;
  102. var z = vectors[0].Z;
  103. foreach (var v in vectors.Skip(1))
  104. {
  105. x = Math.Min(x, v.X);
  106. y = Math.Min(y, v.Y);
  107. z = Math.Min(z, v.Z);
  108. }
  109. return new Vec(x, y, z);
  110. }
  111. private Vec Max(params Vec[] vectors)
  112. {
  113. var x = vectors[0].X;
  114. var y = vectors[0].Y;
  115. var z = vectors[0].Z;
  116. foreach (var v in vectors.Skip(1))
  117. {
  118. x = Math.Max(x, v.X);
  119. y = Math.Max(y, v.Y);
  120. z = Math.Max(z, v.Z);
  121. }
  122. return new Vec(x, y, z);
  123. }
  124. private void MoveDown(Brick brick, long count)
  125. {
  126. foreach (var p in brick.Points())
  127. {
  128. _space.Remove(p);
  129. }
  130. brick.MoveDown(count);
  131. foreach (var p in brick.Points())
  132. {
  133. if (!_space.TryAdd(p, brick))
  134. {
  135. throw new Exception("Unexpected overlap during collapse phase");
  136. }
  137. }
  138. }
  139. private IEnumerable<Brick> BricksAbove(Brick brick)
  140. {
  141. return brick.Points()
  142. .Select(p => _space.GetValueOrDefault(p.Add(Vec.Up)))
  143. .Where(b => b != null && b != brick)
  144. .Cast<Brick>()
  145. .Distinct();
  146. }
  147. private IEnumerable<Brick> BricksBelow(Brick brick)
  148. {
  149. return brick.Points()
  150. .Select(p => _space.GetValueOrDefault(p.Add(Vec.Down)))
  151. .Where(b => b != null && b != brick)
  152. .Cast<Brick>()
  153. .Distinct();
  154. }
  155. }