209 lines
6.3 KiB
C#
209 lines
6.3 KiB
C#
// #define Day22
|
|
#if Day22
|
|
using System.Text.RegularExpressions;
|
|
|
|
var regex = new Regex(@"(?<turn>on|off) x=(?<xstart>-?\d+)\.\.(?<xend>-?\d+),y=(?<ystart>-?\d+)\.\.(?<yend>-?\d+),z=(?<zstart>-?\d+)\.\.(?<zend>-?\d+)");
|
|
|
|
var changes = File.ReadAllLines("day22/input")
|
|
.Select(l => regex.Match(l))
|
|
.Select(From)
|
|
.ToList();
|
|
|
|
PartOne(changes);
|
|
PartTwo(changes);
|
|
PartTwoSimpler(changes);
|
|
|
|
void PartTwoSimpler(List<Change> changes) {
|
|
var onCuboids = new List<Cuboid>();
|
|
|
|
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<Change> changes) {
|
|
var onCuboids = new List<Cuboid>();
|
|
|
|
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<Change> changes) {
|
|
var on = new HashSet<Point>();
|
|
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<Cuboid> Cut(Change change) {
|
|
var newCuboids = new List<Cuboid>();
|
|
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 |