172 lines
5.3 KiB
C#
172 lines
5.3 KiB
C#
using System.Collections.Frozen;
|
|
using System.Numerics;
|
|
using System.Runtime.Intrinsics.X86;
|
|
using System.Text;
|
|
using Spectre.Console;
|
|
|
|
namespace AdventOfCode.Days;
|
|
|
|
public class Day23 : Day
|
|
{
|
|
public override int Number => 23;
|
|
public override string Name => "LAN Party";
|
|
|
|
public override void RunPart1(bool display = true)
|
|
{
|
|
var computerLinks = new Dictionary<string, HashSet<string>>();
|
|
|
|
// Parse all links
|
|
foreach (var line in Input.AsSpan().EnumerateLines())
|
|
{
|
|
var firstComputer = line[..2].ToString();
|
|
var secondComputer = line[3..].ToString();
|
|
|
|
if (!computerLinks.TryGetValue(firstComputer, out var firstLinks))
|
|
{
|
|
firstLinks = [];
|
|
computerLinks[firstComputer] = firstLinks;
|
|
}
|
|
firstLinks.Add(secondComputer);
|
|
|
|
if (!computerLinks.TryGetValue(secondComputer, out var secondLinks))
|
|
{
|
|
secondLinks = [];
|
|
computerLinks[secondComputer] = secondLinks;
|
|
}
|
|
secondLinks.Add(firstComputer);
|
|
}
|
|
|
|
var sets = new HashSet<ComputerSet>();
|
|
|
|
foreach (var (firstComputer, firstLinks) in computerLinks)
|
|
{
|
|
foreach (var secondComputer in firstLinks)
|
|
{
|
|
var thirdComputers = computerLinks[secondComputer].Intersect(firstLinks);
|
|
|
|
foreach (var thirdComputer in thirdComputers)
|
|
{
|
|
sets.Add(new ComputerSet(firstComputer, secondComputer, thirdComputer));
|
|
}
|
|
}
|
|
}
|
|
|
|
var finalCount = sets.Count(set => set.First.StartsWith('t') || set.Second.StartsWith('t') || set.Third.StartsWith('t'));
|
|
|
|
if (display)
|
|
{
|
|
AnsiConsole.MarkupLine($"[green]Amount of sets that contain at least one computer that starts with t: [yellow]{finalCount}[/][/]");
|
|
}
|
|
}
|
|
|
|
public override void RunPart2(bool display = true)
|
|
{
|
|
var computerLinks = new Dictionary<string, HashSet<string>>();
|
|
|
|
// Parse all links
|
|
foreach (var line in Input.AsSpan().EnumerateLines())
|
|
{
|
|
var firstComputer = line[..2].ToString();
|
|
var secondComputer = line[3..].ToString();
|
|
|
|
if (!computerLinks.TryGetValue(firstComputer, out var firstLinks))
|
|
{
|
|
firstLinks = [];
|
|
computerLinks[firstComputer] = firstLinks;
|
|
}
|
|
firstLinks.Add(secondComputer);
|
|
|
|
if (!computerLinks.TryGetValue(secondComputer, out var secondLinks))
|
|
{
|
|
secondLinks = [];
|
|
computerLinks[secondComputer] = secondLinks;
|
|
}
|
|
secondLinks.Add(firstComputer);
|
|
}
|
|
|
|
List<string> largestSet = [];
|
|
|
|
AnsiConsole.Status().Start("Starting check...", status =>
|
|
{
|
|
var size = 4;
|
|
while (true)
|
|
{
|
|
var ended = true;
|
|
|
|
status.Status($"Checking set size: {size}");
|
|
|
|
var i = 0;
|
|
foreach (var (firstComputer, firstLinks) in computerLinks)
|
|
{
|
|
status.Status($"Checking set size: {size} ({i++}/{computerLinks.Count})");
|
|
|
|
if (GenerateLargestSet(firstLinks, size, [ firstComputer ]) is { } largest)
|
|
{
|
|
largestSet = largest;
|
|
size++;
|
|
ended = false;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ended)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
var password = string.Join(',', largestSet.Order());
|
|
|
|
if (display)
|
|
{
|
|
AnsiConsole.MarkupLine($"[green]Password to enter lan party: [yellow]{password}[/][/]");
|
|
}
|
|
|
|
return;
|
|
|
|
List<string>? GenerateLargestSet(HashSet<string> set, int targetSize, List<string> selected)
|
|
{
|
|
if (selected.Count == targetSize)
|
|
{
|
|
return selected;
|
|
}
|
|
|
|
if (set.Count is 0 || (set.Count < (targetSize - selected.Count)))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// Next depth
|
|
foreach (var computer in set)
|
|
{
|
|
var nextSet = set.Intersect(computerLinks[computer]).ToHashSet();
|
|
var nextSelected = selected.Append(computer).ToList();
|
|
|
|
if (GenerateLargestSet(nextSet, targetSize, nextSelected) is { } largest)
|
|
{
|
|
return largest;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private record ComputerSet(string First, string Second, string Third) : IEquatable<ComputerSet>
|
|
{
|
|
public virtual bool Equals(ComputerSet? other)
|
|
{
|
|
return other is not null &&
|
|
(First == other.First || First == other.Second || First == other.Third) &&
|
|
(Second == other.First || Second == other.Second || Second == other.Third) &&
|
|
(Third == other.First || Third == other.Second || Third == other.Third);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return First.GetHashCode() * Second.GetHashCode() * Third.GetHashCode();
|
|
}
|
|
}
|
|
} |