| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- namespace Day22;
- public class BrickStack
- {
- private readonly List<Brick> _bricks = new List<Brick>();
- private Dictionary<Vec, Brick?> _space = new Dictionary<Vec, Brick?>();
- private Vec _min = Vec.Zero;
- private Vec _max = Vec.Zero;
-
- public BrickStack()
- {
-
- }
- public void Add(Brick brick)
- {
- _bricks.Add(brick);
- _min = Min(_min, brick.Start, brick.End);
- _max = Max(_max, brick.Start, brick.End);
- }
- public void Populate()
- {
- _space = new Dictionary<Vec, Brick?>();
- foreach (var b in _bricks.OrderBy(x => x.MinZ))
- {
- foreach (var p in b.Points())
- {
- if (!_space.TryAdd(p, b))
- {
- throw new Exception("Unexpected overlap during populate phase");
- }
- }
- }
- }
- public void Collapse()
- {
- foreach (var b in _bricks.OrderBy(x => x.MinZ))
- {
- var newZ = 1L;
- foreach (var p in b.Points())
- {
- var below = p;
- while (below.Z > newZ - 1)
- {
- var target = _space.GetValueOrDefault(below);
- if (target == null || target == b)
- {
- below = below.Add(Vec.Down);
- }
- else
- {
- if (below.Z + 1 > newZ)
- {
- newZ = below.Z + 1;
- }
- break;
- }
- }
- }
- if (newZ < b.MinZ)
- {
- MoveDown(b, b.MinZ - newZ);
- }
- }
- }
- public void Print()
- {
- for (var y = _min.Y; y <= _max.Y; y++)
- {
- for (var z = _min.Z; z <= Math.Min(_max.Z, 19); z++)
- {
- for (var x = _min.X; x <= _max.X; x++)
- {
- var brick = _space.GetValueOrDefault(new Vec(x, y, z));
- if (brick != null)
- {
- Console.Write(brick.Label);
- }
- else
- {
- Console.Write('.');
- }
- }
- Console.Write(' ');
- }
-
- Console.WriteLine();
- }
- }
- public long CountSafeRemoval()
- {
- var count = 0L;
- foreach (var b in _bricks.OrderBy(x => x.MinZ))
- {
- var above = BricksAbove(b).ToList();
-
- if (above.Count == 0 || above.All(a => BricksBelow(a).Count() >= 2))
- {
- count++;
- }
- }
- return count;
- }
- private Vec Min(params Vec[] vectors)
- {
- var x = vectors[0].X;
- var y = vectors[0].Y;
- var z = vectors[0].Z;
- foreach (var v in vectors.Skip(1))
- {
- x = Math.Min(x, v.X);
- y = Math.Min(y, v.Y);
- z = Math.Min(z, v.Z);
- }
- return new Vec(x, y, z);
- }
-
- private Vec Max(params Vec[] vectors)
- {
- var x = vectors[0].X;
- var y = vectors[0].Y;
- var z = vectors[0].Z;
- foreach (var v in vectors.Skip(1))
- {
- x = Math.Max(x, v.X);
- y = Math.Max(y, v.Y);
- z = Math.Max(z, v.Z);
- }
- return new Vec(x, y, z);
- }
- private void MoveDown(Brick brick, long count)
- {
- foreach (var p in brick.Points())
- {
- _space.Remove(p);
- }
- brick.MoveDown(count);
- foreach (var p in brick.Points())
- {
- if (!_space.TryAdd(p, brick))
- {
- throw new Exception("Unexpected overlap during collapse phase");
- }
- }
- }
- private IEnumerable<Brick> BricksAbove(Brick brick)
- {
- return brick.Points()
- .Select(p => _space.GetValueOrDefault(p.Add(Vec.Up)))
- .Where(b => b != null && b != brick)
- .Cast<Brick>()
- .Distinct();
- }
-
- private IEnumerable<Brick> BricksBelow(Brick brick)
- {
- return brick.Points()
- .Select(p => _space.GetValueOrDefault(p.Add(Vec.Down)))
- .Where(b => b != null && b != brick)
- .Cast<Brick>()
- .Distinct();
- }
- }
|