Initial Commit
This commit is contained in:
10
2022/Day18CSharp/Day18CSharp.csproj
Normal file
10
2022/Day18CSharp/Day18CSharp.csproj
Normal file
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
344
2022/Day18CSharp/Program.cs
Normal file
344
2022/Day18CSharp/Program.cs
Normal file
@@ -0,0 +1,344 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Drawing;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
Part01();
|
||||
|
||||
void Part01()
|
||||
{
|
||||
Console.WriteLine("!! === Part 01 === !!");
|
||||
|
||||
Console.WriteLine(" === Example Simple ===");
|
||||
var exampleSimpleData = new ProblemData("example-input-simple.txt");
|
||||
exampleSimpleData.Print();
|
||||
|
||||
Console.WriteLine(" === Example ===");
|
||||
var exampleData = new ProblemData("example-input.txt");
|
||||
exampleData.Print();
|
||||
|
||||
Console.WriteLine(" === Puzzle ===");
|
||||
var puzzleData = new ProblemData("puzzle-input.txt");
|
||||
puzzleData.Print();
|
||||
}
|
||||
|
||||
struct Vertex
|
||||
: IComparable
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
public int Z;
|
||||
|
||||
public Vertex() : this(int.MinValue, int.MinValue, int.MinValue) { }
|
||||
|
||||
public Vertex(int x, int y, int z)
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
this.Z = z;
|
||||
}
|
||||
|
||||
public int CompareTo(object? obj)
|
||||
{
|
||||
if (obj == null) throw new InvalidCastException();
|
||||
var other = (Vertex)obj;
|
||||
|
||||
if (this.X != other.X)
|
||||
{
|
||||
return this.X.CompareTo(other.X);
|
||||
}
|
||||
else if (this.Y != other.Y)
|
||||
{
|
||||
return this.Y.CompareTo(other.Y);
|
||||
}
|
||||
else if (this.Z != other.Z)
|
||||
{
|
||||
return this.Z.CompareTo(other.Z);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return false;
|
||||
var other = (Vertex)obj;
|
||||
return this.CompareTo(other) == 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Cube
|
||||
{
|
||||
public Cube(int x, int y, int z)
|
||||
{
|
||||
init(x, y, z);
|
||||
}
|
||||
|
||||
public Cube(string data)
|
||||
{
|
||||
var split = data.Split(',');
|
||||
|
||||
init(int.Parse(split[0]), int.Parse(split[1]), int.Parse(split[2]));
|
||||
}
|
||||
|
||||
private void init(int x, int y, int z)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
|
||||
List<Vertex> vertices = new List<Vertex>();
|
||||
|
||||
// Create the verts (we'll store CCW)
|
||||
for (int d = 0; d < 2; d++)
|
||||
{
|
||||
vertices.Add(new Vertex(x, y, z + d));
|
||||
vertices.Add(new Vertex(x+1, y, z + d));
|
||||
vertices.Add(new Vertex(x+1, y+1, z + d));
|
||||
vertices.Add(new Vertex(x, y+1, z + d));
|
||||
}
|
||||
|
||||
Vertices = vertices.ToArray();
|
||||
}
|
||||
|
||||
public Vertex[] Vertices { get; private set; } = new Vertex[0];
|
||||
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public int Z { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("Cube at {0},{1},{2}", X, Y, Z);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj == null) return false;
|
||||
var other = (Cube)obj;
|
||||
return X == other.X && Y == other.Y && Z == other.Z;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return X ^ Y ^ Z;
|
||||
}
|
||||
|
||||
public bool IsAdjacent(Cube c)
|
||||
{
|
||||
var faceAdjacents = new Cube[]
|
||||
{
|
||||
// Directly to the sides
|
||||
new Cube(c.X+1, c.Y, c.Z),
|
||||
new Cube(c.X, c.Y+1, c.Z),
|
||||
new Cube(c.X, c.Y, c.Z+1),
|
||||
new Cube(c.X-1, c.Y, c.Z),
|
||||
new Cube(c.X, c.Y-1, c.Z),
|
||||
new Cube(c.X, c.Y, c.Z-1),
|
||||
};
|
||||
|
||||
foreach (var f in faceAdjacents)
|
||||
{
|
||||
if (f.Equals(this)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Cube[] Adjacents
|
||||
{
|
||||
get
|
||||
{
|
||||
var faceAdjacents = new Cube[]
|
||||
{
|
||||
// Directly to the sides
|
||||
new Cube(this.X+1, this.Y, this.Z),
|
||||
new Cube(this.X, this.Y+1, this.Z),
|
||||
new Cube(this.X, this.Y, this.Z+1),
|
||||
new Cube(this.X-1, this.Y, this.Z),
|
||||
new Cube(this.X, this.Y-1, this.Z),
|
||||
new Cube(this.X, this.Y, this.Z-1),
|
||||
};
|
||||
|
||||
return faceAdjacents;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ProblemData
|
||||
{
|
||||
public HashSet<Cube> Cubes { get; }
|
||||
public HashSet<Cube> AirCubes { get; private set; } = new HashSet<Cube>();
|
||||
|
||||
public ProblemData(string filename)
|
||||
{
|
||||
Cubes = new HashSet<Cube>();
|
||||
|
||||
using (StreamReader reader = System.IO.File.OpenText(filename))
|
||||
{
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
var line = reader.ReadLine();
|
||||
if (line == null) throw new InvalidDataException();
|
||||
|
||||
var newCube = new Cube(line);
|
||||
if (Cubes.Contains(newCube)) throw new InvalidDataException();
|
||||
Cubes.Add(newCube);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetExposedSides(Cube c, HashSet<Cube> cubes)
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
var faceAdjacents = new Cube[]
|
||||
{
|
||||
// Directly to the sides
|
||||
new Cube(c.X+1, c.Y, c.Z),
|
||||
new Cube(c.X, c.Y+1, c.Z),
|
||||
new Cube(c.X, c.Y, c.Z+1),
|
||||
new Cube(c.X-1, c.Y, c.Z),
|
||||
new Cube(c.X, c.Y-1, c.Z),
|
||||
new Cube(c.X, c.Y, c.Z-1),
|
||||
};
|
||||
|
||||
var angledAdjacents = new Cube[]
|
||||
{
|
||||
new Cube(c.X+1, c.Y, c.Z-1), // Right and closer to camera
|
||||
new Cube(c.X-1, c.Y, c.Z-1), // Left and closer to camera
|
||||
new Cube(c.X+1, c.Y, c.Z+1), // Right and farther from camera
|
||||
new Cube(c.X-1, c.Y, c.Z+1), // Left and farther from camera
|
||||
new Cube(c.X, c.Y+1, c.Z-1), // Up and closer to the camera
|
||||
new Cube(c.X, c.Y+1, c.Z+1), // Up and farther from camera
|
||||
new Cube(c.X, c.Y-1, c.Z-1), // Down and closer to camera
|
||||
new Cube(c.X, c.Y-1, c.Z+1), // Down and farther from camera
|
||||
};
|
||||
|
||||
foreach (var adjacent in faceAdjacents)
|
||||
{
|
||||
if (cubes.Contains(adjacent))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
total++;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
public int SurfaceArea
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetSurfaceArea(Cubes);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetSurfaceArea(HashSet<Cube> cubes)
|
||||
{
|
||||
int area = 0;
|
||||
foreach (var c in cubes)
|
||||
{
|
||||
area += GetExposedSides(c, cubes);
|
||||
}
|
||||
return area;
|
||||
}
|
||||
|
||||
public int ExteriorSurfaceArea
|
||||
{
|
||||
get
|
||||
{
|
||||
HashSet<Cube> exterior = new HashSet<Cube>();
|
||||
|
||||
FillExterior(new Cube(Bounds[0].X, Bounds[0].Y, Bounds[0].Z), Cubes, exterior);
|
||||
|
||||
int area = 0;
|
||||
foreach (var cube in Cubes)
|
||||
{
|
||||
foreach (var adjacent in cube.Adjacents)
|
||||
{
|
||||
if (exterior.Contains(adjacent)) area++;
|
||||
}
|
||||
}
|
||||
|
||||
return area;
|
||||
}
|
||||
}
|
||||
|
||||
public void FillExterior(Cube startingCube, HashSet<Cube> dropletCubes, HashSet<Cube> exterior)
|
||||
{
|
||||
List<Cube> toTest = new List<Cube>();
|
||||
|
||||
toTest.Add(startingCube);
|
||||
|
||||
do
|
||||
{
|
||||
var c = toTest[0];
|
||||
toTest.RemoveAt(0);
|
||||
|
||||
if (c.X >= Bounds[0].X - 1 && c.Y >= Bounds[0].Y - 1 && c.Z >= Bounds[0].Z - 1
|
||||
&& c.X <= Bounds[1].X + 1 && c.Y <= Bounds[1].Y + 1 && c.Z <= Bounds[1].Z + 1
|
||||
&& !dropletCubes.Contains(c)
|
||||
&& !exterior.Contains(c))
|
||||
{
|
||||
exterior.Add(c);
|
||||
foreach (var face in c.Adjacents)
|
||||
{
|
||||
// C# doesnt support tail recursion innately
|
||||
//FillExterior(face, dropletCubes, exterior);
|
||||
toTest.Add(face);
|
||||
}
|
||||
}
|
||||
} while (toTest.Count > 0);
|
||||
}
|
||||
|
||||
private bool HasCubeBelow(Cube c)
|
||||
{
|
||||
return Cubes.Contains(new Cube(c.X, c.Y-1, c.Z));
|
||||
}
|
||||
|
||||
public Vertex[] Bounds
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mBounds.Length == 0)
|
||||
{
|
||||
Vertex bottomLeft = new Vertex(int.MaxValue, int.MaxValue, int.MaxValue);
|
||||
Vertex topRight = new Vertex(int.MinValue,int.MinValue,int.MinValue);
|
||||
|
||||
foreach (var c in Cubes)
|
||||
{
|
||||
bottomLeft.X = int.Min(c.X, bottomLeft.X);
|
||||
bottomLeft.Y = int.Min(c.Y, bottomLeft.Y);
|
||||
bottomLeft.Z = int.Min(c.Z, bottomLeft.Z);
|
||||
|
||||
topRight.X = int.Max(c.X, topRight.X);
|
||||
topRight.Y = int.Max(c.Y, topRight.Y);
|
||||
topRight.Z = int.Max(c.Z, topRight.Z);
|
||||
}
|
||||
|
||||
mBounds = new Vertex[] { bottomLeft, topRight };
|
||||
}
|
||||
|
||||
return mBounds;
|
||||
}
|
||||
}
|
||||
|
||||
private Vertex[] mBounds = new Vertex[0];
|
||||
|
||||
public void Print()
|
||||
{
|
||||
Console.WriteLine("Cubes {0} with surface area {1} and {2} exterior area", Cubes.Count, SurfaceArea, ExteriorSurfaceArea);
|
||||
}
|
||||
}
|
||||
8
2022/Day18CSharp/Properties/launchSettings.json
Normal file
8
2022/Day18CSharp/Properties/launchSettings.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Day18CSharp": {
|
||||
"commandName": "Project",
|
||||
"workingDirectory": "C:\\dev\\DevSandbox\\AdventOfCode\\2022\\Day18CSharp"
|
||||
}
|
||||
}
|
||||
}
|
||||
2
2022/Day18CSharp/example-input-simple.txt
Normal file
2
2022/Day18CSharp/example-input-simple.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
1,1,1
|
||||
2,1,1
|
||||
13
2022/Day18CSharp/example-input.txt
Normal file
13
2022/Day18CSharp/example-input.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
2,2,2
|
||||
1,2,2
|
||||
3,2,2
|
||||
2,1,2
|
||||
2,3,2
|
||||
2,2,1
|
||||
2,2,3
|
||||
2,2,4
|
||||
2,2,6
|
||||
1,2,5
|
||||
3,2,5
|
||||
2,1,5
|
||||
2,3,5
|
||||
44
2022/Day18CSharp/problem.txt
Normal file
44
2022/Day18CSharp/problem.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
--- Day 18: Boiling Boulders ---
|
||||
|
||||
You and the elephants finally reach fresh air. You've emerged near the base of a large volcano that seems to be actively erupting! Fortunately, the lava seems to be flowing away from you and toward the ocean.
|
||||
|
||||
Bits of lava are still being ejected toward you, so you're sheltering in the cavern exit a little longer. Outside the cave, you can see the lava landing in a pond and hear it loudly hissing as it solidifies.
|
||||
|
||||
Depending on the specific compounds in the lava and speed at which it cools, it might be forming obsidian! The cooling rate should be based on the surface area of the lava droplets, so you take a quick scan of a droplet as it flies past you (your puzzle input).
|
||||
|
||||
Because of how quickly the lava is moving, the scan isn't very good; its resolution is quite low and, as a result, it approximates the shape of the lava droplet with 1x1x1 cubes on a 3D grid, each given as its x,y,z position.
|
||||
|
||||
To approximate the surface area, count the number of sides of each cube that are not immediately connected to another cube. So, if your scan were only two adjacent cubes like 1,1,1 and 2,1,1, each cube would have a single side covered and five sides exposed, a total surface area of 10 sides.
|
||||
|
||||
Here's a larger example:
|
||||
|
||||
2,2,2
|
||||
1,2,2
|
||||
3,2,2
|
||||
2,1,2
|
||||
2,3,2
|
||||
2,2,1
|
||||
2,2,3
|
||||
2,2,4
|
||||
2,2,6
|
||||
1,2,5
|
||||
3,2,5
|
||||
2,1,5
|
||||
2,3,5
|
||||
|
||||
In the above example, after counting up all the sides that aren't connected to another cube, the total surface area is 64.
|
||||
|
||||
What is the surface area of your scanned lava droplet?
|
||||
|
||||
Your puzzle answer was 4332.
|
||||
|
||||
The first half of this puzzle is complete! It provides one gold star: *
|
||||
--- Part Two ---
|
||||
|
||||
Something seems off about your calculation. The cooling rate depends on exterior surface area, but your calculation also included the surface area of air pockets trapped in the lava droplet.
|
||||
|
||||
Instead, consider only cube sides that could be reached by the water and steam as the lava droplet tumbles into the pond. The steam will expand to reach as much as possible, completely displacing any air on the outside of the lava droplet but never expanding diagonally.
|
||||
|
||||
In the larger example above, exactly one cube of air is trapped within the lava droplet (at 2,2,5), so the exterior surface area of the lava droplet is 58.
|
||||
|
||||
What is the exterior surface area of your scanned lava droplet?
|
||||
2879
2022/Day18CSharp/puzzle-input.txt
Normal file
2879
2022/Day18CSharp/puzzle-input.txt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user