BrickStack.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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. public long CountAllFalling()
  99. {
  100. var supports = new Dictionary<Brick, List<Brick>>();
  101. var isSupportedBy = new Dictionary<Brick, List<Brick>>();
  102. foreach (var b in _bricks.OrderBy(x => x.MinZ))
  103. {
  104. supports.TryAdd(b, new List<Brick>());
  105. isSupportedBy.TryAdd(b, new List<Brick>());
  106. foreach (var above in BricksAbove(b))
  107. {
  108. supports[b].Add(above);
  109. isSupportedBy.TryAdd(above, new List<Brick>());
  110. isSupportedBy[above].Add(b);
  111. }
  112. }
  113. var count = 0L;
  114. foreach (var b in _bricks.OrderBy(x => x.MinZ))
  115. {
  116. // walk "up" the graph to all nodes that only have supports within our "set" starting with the current brick
  117. var set = new HashSet<Brick>();
  118. var edge = new List<Brick> { b };
  119. while (edge.Count > 0)
  120. {
  121. foreach (var e in edge)
  122. {
  123. set.Add(e);
  124. }
  125. edge = edge.SelectMany(e => supports[e])
  126. .Distinct()
  127. .Where(above => isSupportedBy[above].Count(below => !set.Contains(below)) == 0)
  128. .ToList();
  129. }
  130. count += set.Count - 1;
  131. }
  132. return count;
  133. }
  134. private Vec Min(params Vec[] vectors)
  135. {
  136. var x = vectors[0].X;
  137. var y = vectors[0].Y;
  138. var z = vectors[0].Z;
  139. foreach (var v in vectors.Skip(1))
  140. {
  141. x = Math.Min(x, v.X);
  142. y = Math.Min(y, v.Y);
  143. z = Math.Min(z, v.Z);
  144. }
  145. return new Vec(x, y, z);
  146. }
  147. private Vec Max(params Vec[] vectors)
  148. {
  149. var x = vectors[0].X;
  150. var y = vectors[0].Y;
  151. var z = vectors[0].Z;
  152. foreach (var v in vectors.Skip(1))
  153. {
  154. x = Math.Max(x, v.X);
  155. y = Math.Max(y, v.Y);
  156. z = Math.Max(z, v.Z);
  157. }
  158. return new Vec(x, y, z);
  159. }
  160. private void MoveDown(Brick brick, long count)
  161. {
  162. foreach (var p in brick.Points())
  163. {
  164. _space.Remove(p);
  165. }
  166. brick.MoveDown(count);
  167. foreach (var p in brick.Points())
  168. {
  169. if (!_space.TryAdd(p, brick))
  170. {
  171. throw new Exception("Unexpected overlap during collapse phase");
  172. }
  173. }
  174. }
  175. private IEnumerable<Brick> BricksAbove(Brick brick)
  176. {
  177. return brick.Points()
  178. .Select(p => _space.GetValueOrDefault(p.Add(Vec.Up)))
  179. .Where(b => b != null && b != brick)
  180. .Cast<Brick>()
  181. .Distinct();
  182. }
  183. private IEnumerable<Brick> BricksBelow(Brick brick)
  184. {
  185. return brick.Points()
  186. .Select(p => _space.GetValueOrDefault(p.Add(Vec.Down)))
  187. .Where(b => b != null && b != brick)
  188. .Cast<Brick>()
  189. .Distinct();
  190. }
  191. }