Add Day 08 solution
This commit is contained in:
parent
afc7997fa2
commit
04d9b2fd45
|
|
@ -0,0 +1,47 @@
|
||||||
|
using AdvenOfCode.Contracts;
|
||||||
|
|
||||||
|
namespace AoC_2025.Tests;
|
||||||
|
|
||||||
|
public class Day08Test
|
||||||
|
{
|
||||||
|
private readonly Day08 _sut;
|
||||||
|
private static readonly string rootPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||||
|
private readonly string TestInputPath = @$"{rootPath}\AoC-PuzzleInputs\2025\Test\day08.txt";
|
||||||
|
private readonly string ProdInputPath = @$"{rootPath}\AoC-PuzzleInputs\2025\Prod\day08.txt";
|
||||||
|
|
||||||
|
public Day08Test()
|
||||||
|
{
|
||||||
|
_sut = new Day08();
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Part01_Test_equals_40()
|
||||||
|
{
|
||||||
|
var actual = _sut.SolvePart1(TestInputPath, 10);
|
||||||
|
|
||||||
|
Assert.Equal(40, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Part01_Prod_equals_42840()
|
||||||
|
{
|
||||||
|
var actual = _sut.SolvePart1(ProdInputPath, 1000);
|
||||||
|
|
||||||
|
Assert.Equal(42840, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Part02_Test_equals_25272()
|
||||||
|
{
|
||||||
|
var actual = _sut.SolvePart2(TestInputPath);
|
||||||
|
|
||||||
|
Assert.Equal(25272, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Part02_Prod_equals_170629052()
|
||||||
|
{
|
||||||
|
var actual = _sut.SolvePart2(ProdInputPath);
|
||||||
|
|
||||||
|
Assert.Equal(170629052, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,160 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using AdvenOfCode.Contracts;
|
||||||
|
using Coordinate = (int x, int y, int z);
|
||||||
|
|
||||||
|
namespace AoC_2025;
|
||||||
|
|
||||||
|
public class Day08
|
||||||
|
{
|
||||||
|
private Coordinate[] ParsePuzzleInput(string path)
|
||||||
|
{
|
||||||
|
var puzzleInput = File.ReadAllLines(path)
|
||||||
|
.Where(line => !string.IsNullOrWhiteSpace(line))
|
||||||
|
.Select(line => line.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(str => int.Parse(str)).ToArray())
|
||||||
|
.Select(numbers => (numbers[0], numbers[1], numbers[2]))
|
||||||
|
.ToArray();
|
||||||
|
return puzzleInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long SolvePart1(string pathToPuzzleInput, int amountToConnect)
|
||||||
|
{
|
||||||
|
var points = ParsePuzzleInput(pathToPuzzleInput);
|
||||||
|
Dictionary<Coordinate, HashSet<Coordinate>> connected = points.ToDictionary(p => p, p => new HashSet<Coordinate>());
|
||||||
|
var pointsWithClosest = points.Select(point =>
|
||||||
|
{
|
||||||
|
var closest = GetClosestPoint(point, points, connected);
|
||||||
|
return (point, closest: closest.point, closest.distance);
|
||||||
|
})
|
||||||
|
.OrderBy(x => x.distance)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
List<List<Coordinate>> circuits = [];
|
||||||
|
for (var i = 0; i < amountToConnect; i++)
|
||||||
|
{
|
||||||
|
var next = pointsWithClosest[0];
|
||||||
|
_ = AddToCircuits(next.point, next.closest, circuits);
|
||||||
|
connected[next.point].Add(next.closest);
|
||||||
|
connected[next.closest].Add(next.point);
|
||||||
|
pointsWithClosest = points.Select(point =>
|
||||||
|
{
|
||||||
|
var closest = GetClosestPoint(point, points, connected);
|
||||||
|
return (point, closest: closest.point, closest.distance);
|
||||||
|
})
|
||||||
|
.OrderBy(x => x.distance)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return circuits
|
||||||
|
.Select(circuit => circuit.Count)
|
||||||
|
.OrderDescending()
|
||||||
|
.Take(3)
|
||||||
|
.Aggregate((acc, next) => acc * next);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long SolvePart2(string pathToPuzzleInput)
|
||||||
|
{
|
||||||
|
var points = ParsePuzzleInput(pathToPuzzleInput);
|
||||||
|
Dictionary<Coordinate, HashSet<Coordinate>> connected = points.ToDictionary(p => p, p => new HashSet<Coordinate>());
|
||||||
|
var pointsWithClosest = points.Select(point =>
|
||||||
|
{
|
||||||
|
var closest = GetClosestPoint(point, points, connected);
|
||||||
|
return (point, closest: closest.point, closest.distance);
|
||||||
|
})
|
||||||
|
.OrderBy(x => x.distance)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
List<List<Coordinate>> circuits = points.Select(p => new List<Coordinate>() { p }).ToList();
|
||||||
|
(Coordinate a, Coordinate b) lastConnected = ((0, 0, 0), (0, 0, 0));
|
||||||
|
while(circuits.Count > 1)
|
||||||
|
{
|
||||||
|
var next = pointsWithClosest[0];
|
||||||
|
_ = AddToCircuits(next.point, next.closest, circuits);
|
||||||
|
connected[next.point].Add(next.closest);
|
||||||
|
connected[next.closest].Add(next.point);
|
||||||
|
lastConnected = (next.point, next.closest);
|
||||||
|
pointsWithClosest = points.Select(point =>
|
||||||
|
{
|
||||||
|
var closest = GetClosestPoint(point, points, connected);
|
||||||
|
return (point, closest: closest.point, closest.distance);
|
||||||
|
})
|
||||||
|
.OrderBy(x => x.distance)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastConnected.a.x * lastConnected.b.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
private (Coordinate point, double distance) GetClosestPoint(Coordinate a, Coordinate[] points, Dictionary<Coordinate, HashSet<Coordinate>> connections)
|
||||||
|
{
|
||||||
|
var minDistance = double.MaxValue;
|
||||||
|
var minIndex = -1;
|
||||||
|
for (var i = 0; i < points.Length; i++)
|
||||||
|
{
|
||||||
|
if(a == points[i]) continue;
|
||||||
|
if(connections[a].Contains(points[i])) continue;
|
||||||
|
|
||||||
|
var distance = GetDistance(a, points[i]);
|
||||||
|
if (minDistance > distance)
|
||||||
|
{
|
||||||
|
minIndex = i;
|
||||||
|
minDistance = GetDistance(a, points[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (points[minIndex], minDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double GetDistance(Coordinate a, Coordinate b)
|
||||||
|
{
|
||||||
|
return Math.Sqrt(Math.Pow(a.x - b.x, 2) + Math.Pow(a.y - b.y, 2) + Math.Pow(a.z - b.z, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int AddToCircuits(Coordinate a, Coordinate b, List<List<Coordinate>> circuits)
|
||||||
|
{
|
||||||
|
var circuitToAddBTo = circuits.FirstOrDefault(circuit => circuit.Contains(a));
|
||||||
|
var circuitToAddATo = circuits.FirstOrDefault(circuit => circuit.Contains(b));
|
||||||
|
if (circuitToAddATo == null && circuitToAddBTo == null)
|
||||||
|
{
|
||||||
|
circuits.Add([a, b]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (circuitToAddATo == circuitToAddBTo)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (circuitToAddATo != null && circuitToAddBTo != null)
|
||||||
|
{
|
||||||
|
circuits.Remove(circuitToAddATo);
|
||||||
|
circuits.Remove(circuitToAddBTo);
|
||||||
|
circuits.Add([..circuitToAddATo, ..circuitToAddBTo]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (circuitToAddATo != null)
|
||||||
|
{
|
||||||
|
circuitToAddATo.Add(a);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
circuitToAddBTo.Add(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<(Coordinate pointA, Coordinate pointB, double distance)> GetAllDistances(Coordinate[] coordinates)
|
||||||
|
{
|
||||||
|
var combinations = coordinates
|
||||||
|
.SelectMany((coord, ix) =>
|
||||||
|
coordinates.Skip(ix + 1).Select(coordB => (coord, coordB, distance: GetDistance(coord, coordB))))
|
||||||
|
.OrderBy(x => x.distance)
|
||||||
|
.ToArray();
|
||||||
|
return combinations;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue