// #define Day22 #if Day22 using System.Text.RegularExpressions; var regex = new Regex(@"(?on|off) x=(?-?\d+)\.\.(?-?\d+),y=(?-?\d+)\.\.(?-?\d+),z=(?-?\d+)\.\.(?-?\d+)"); var changes = File.ReadAllLines("day22/input") .Select(l => regex.Match(l)) .Select(From) .ToList(); PartOne(changes); PartTwo(changes); PartTwoSimpler(changes); void PartTwoSimpler(List changes) { var onCuboids = new List(); foreach (var change in changes) { var newOnCuboids = onCuboids.Where(c => !c.Outside(change)).Select(c => c.CutCommonPart(change)).ToList(); if (change.turnOn) { onCuboids.Add(new Cuboid() {from = change.from, to = change.to, negative = false}); } onCuboids.AddRange(newOnCuboids); } var total = onCuboids.Select(c => c.NumberOfCubes()).Sum(); Console.WriteLine(total); } void PartTwo(List changes) { var onCuboids = new List(); foreach (var change in changes) { var newOnCuboids = onCuboids.SelectMany(c => c.Cut(change)).ToList(); if (change.turnOn) { newOnCuboids.Add(new Cuboid() {from = change.from, to = change.to}); } onCuboids = newOnCuboids; } var total = onCuboids.Select(c => c.NumberOfCubes()).Sum(); Console.WriteLine(total); } void PartOne(List changes) { var on = new HashSet(); foreach (var change in changes) { for (int x = Math.Max(change.from.x, -50); x <= Math.Min(change.to.x, 50); x++) { for (int y = Math.Max(change.from.y, -50); y <= Math.Min(change.to.y, 50); y++) { for (int z = Math.Max(change.from.z, -50); z <= Math.Min(change.to.z, 50); z++) { var curPoint = new Point(x, y, z); if (change.turnOn) { on.Add(curPoint); } else { on.Remove(curPoint); } } } } } Console.WriteLine(on.Count); } Change From(Match m) { int xstart = int.Parse(m.Groups["xstart"].Value); int xend = int.Parse(m.Groups["xend"].Value); int ystart = int.Parse(m.Groups["ystart"].Value); int yend = int.Parse(m.Groups["yend"].Value); int zstart = int.Parse(m.Groups["zstart"].Value); int zend = int.Parse(m.Groups["zend"].Value); Point from = new Point(Math.Min(xstart, xend), Math.Min(ystart, yend), Math.Min(zstart, zend)); Point to = new Point(Math.Max(xstart, xend), Math.Max(ystart, yend), Math.Max(zstart, zend)); return new Change(m.Groups["turn"].Value == "on", from, to); } record Change(bool turnOn, Point from, Point to); record Point(int x, int y, int z); class Cuboid { public bool negative { get; set; } // used for part two simpler version only public Point from { get; set; } public Point to { get; set; } bool Within(Change change) { return change.from.x <= from.x && change.to.x >= to.x && change.from.y <= from.y && change.to.y >= to.y && change.from.z <= from.z && change.to.z >= to.z; } public bool Outside(Change change) { return change.to.x < from.x || change.from.x > to.x || change.to.y < from.y || change.from.y > to.y || change.to.z < from.z || change.from.z > to.z; } public long NumberOfCubes() { long x = to.x - from.x + 1; long y = to.y - from.y + 1; long z = to.z - from.z + 1; long total = x * y * z; return negative ? -total : total; } public List Cut(Change change) { var newCuboids = new List(); if (Within(change)) { return newCuboids; } if (Outside(change)) { newCuboids.Add(this); return newCuboids; } int toX = Math.Min(to.x, change.from.x - 1); if (from.x <= toX) { newCuboids.Add(new Cuboid() { from = this.from, to = new Point(toX, to.y, to.z) }); toX++; } else { toX = from.x; } int fromX = Math.Max(from.x, change.to.x + 1); if (fromX <= to.x) { newCuboids.Add(new Cuboid() { from = new Point(fromX, from.y, from.z), to = this.to }); fromX--; } else { fromX = to.x; } int toY = Math.Min(to.y, change.from.y - 1); if (from.y <= toY) { newCuboids.Add(new Cuboid() { from = new Point(toX, from.y, from.z), to = new Point(fromX, toY, to.z) }); toY++; } else { toY = from.y; } int fromY = Math.Max(from.y, change.to.y + 1); if (fromY <= to.y) { newCuboids.Add(new Cuboid() { from = new Point(toX, fromY, from.z), to = new Point(fromX, to.y, to.z) }); fromY--; } else { fromY = to.y; } int toZ = Math.Min(to.z, change.from.z - 1); if (from.z <= toZ) { newCuboids.Add(new Cuboid() { from = new Point(toX, toY, from.z), to = new Point(fromX, fromY, toZ) }); } int fromZ = Math.Max(from.z, change.to.z + 1); if (fromZ <= to.z) { newCuboids.Add(new Cuboid() { from = new Point(toX, toY, fromZ), to = new Point(fromX, fromY, to.z) }); } return newCuboids; } public Cuboid CutCommonPart(Change change) { if (Outside(change)) { throw new Exception(); } return new Cuboid() { negative = !this.negative, from = new Point( Math.Max(from.x, change.from.x), Math.Max(from.y, change.from.y), Math.Max(from.z, change.from.z) ), to = new Point( Math.Min(to.x, change.to.x), Math.Min(to.y, change.to.y), Math.Min(to.z, change.to.z) ) }; } } #endif