aoc2017/csharp/BScottDay7.cs

148 lines
5.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text.RegularExpressions;
namespace AOC2017
{
class BScottDay7 : BScottSolution
{
public override string Name => "Day 7: Recursive Circus";
public override void Run()
{
// Sample Problem
string[] input = File.ReadAllLines("BScottDay7Sample.txt");
Node rootNode = ProcessList(input);
Console.WriteLine($"Part 1 Example Answer: {rootNode.Name}");
int weightDifference = FindWeightDifference(rootNode);
Node badProgram = FindBadProgram(rootNode);
Console.WriteLine("Part 2 Example Answer: " + (badProgram.Weight + weightDifference));
// Main problem
input = File.ReadAllLines("BScottDay7.txt");
rootNode = ProcessList(input);
Console.WriteLine($"Part 1 Answer: {rootNode.Name}");
// I have no idea if this convoluted solution will work for other inputs,
// but it's printing out the right answer and I am too tired and fed up with this
// problem to care if it's not perfect.
weightDifference = FindWeightDifference(rootNode);
badProgram = FindBadProgram(rootNode);
Console.WriteLine("Part 2 Answer: " + (badProgram.Weight + weightDifference));
}
static Node ProcessList(string[] input)
{
List<string> removalList = new List<string>();
Dictionary<string, Node> nodeList = new Dictionary<string, Node>();
Regex regex = new Regex(@"([a-z]+) \((\d+)\)(?: -> )?(?:([a-z]+)*(?:, )?)*");
for (int i = 0; i < input.Length; i++)
{
Match match = regex.Match(input[i]);
if (match.Success)
{
// create a new node
Node node = new Node(match.Groups[1].Value, int.Parse(match.Groups[2].Value));
// add any sub items
if (match.Groups[3].Captures.Count > 0)
{
foreach (Capture capture in match.Groups[3].Captures)
{
node.ChildNames.Add(capture.Value);
}
}
nodeList.Add(match.Groups[1].Value, node);
}
}
foreach (KeyValuePair<string, Node> kvpNode in nodeList)
{
if (kvpNode.Value.ChildNames.Count > 0)
{
foreach (string s in kvpNode.Value.ChildNames)
{
if (nodeList.ContainsKey(s))
{
kvpNode.Value.ChildNodes.Add(nodeList[s]);
removalList.Add(s); // a list of nodes to remove from dictionary
}
}
}
}
// Remove everything from root colllection that was a child node of something else.
// This should leave just 1 node remaining which is the root node.
foreach (string key in removalList)
nodeList.Remove(key);
return nodeList.First().Value; // hopefully this is the fully populated root node...
}
static int GetWeight(Node parentNode)
{
if (parentNode.ChildNodes.Count == 0)
return parentNode.Weight;
int weight = parentNode.Weight;
foreach (Node t in parentNode.ChildNodes)
weight += GetWeight(t);
return weight;
}
/// <summary>
/// Finds the weight difference of the inbalance
/// </summary>
/// <param name="rootNode">The root node of the entire stack</param>
/// <returns>The weight difference of the offending program.</returns>
static int FindWeightDifference(Node rootNode)
{
int[] weights = new int[rootNode.ChildNodes.Count];
for (int i = 0; i < rootNode.ChildNodes.Count; i++)
weights[i] = GetWeight(rootNode.ChildNodes[i]);
List<int> result = weights.GroupBy(i => i).OrderBy(g => g.Count()).Select(g => g.Key).ToList();
return result.Last() - result.First();
}
static Node FindBadProgram(Node parentNode)
{
// only find nodes that have at least 3 children to compare
if(parentNode.ChildNodes.Count >= 3) {
int[] weights = new int[parentNode.ChildNodes.Count];
// calulate the weights
for (int i = 0; i < parentNode.ChildNodes.Count; i++)
weights[i] = GetWeight(parentNode.ChildNodes[i]);
// find the least common weight
int result = weights.GroupBy(i => i).OrderBy(g => g.Count()).Select(g => g.Key).ToList().First();
Node nextNode = parentNode.ChildNodes[Array.IndexOf(weights, result)];
if (nextNode.ChildNodes.Count > 0)
{
// dig into the node with the uncommon weight
return FindBadProgram(parentNode.ChildNodes[Array.IndexOf(weights, result)]);
}
}
return parentNode;
}
class Node
{
public string Name { get; set; }
public int Weight { get; set; }
public List<Node> ChildNodes { get; set; }
public List<string> ChildNames { get; set; }
public Node(string name, int weight)
{
Name = name;
Weight = weight;
ChildNodes = new List<Node>();
ChildNames = new List<string>();
}
}
}
}