197 lines
5.4 KiB
C#
197 lines
5.4 KiB
C#
using System.Runtime.InteropServices;
|
|
|
|
var exParsed = new Day05Parsed("example-input.txt");
|
|
|
|
Console.WriteLine("Example Part01: {0}", exParsed.GetPart01());
|
|
Console.WriteLine("Example Part02: {0}", exParsed.GetPart02());
|
|
|
|
var pzParsed = new Day05Parsed("puzzle-input.txt");
|
|
|
|
Console.WriteLine("Puzzle Part01: {0}", pzParsed.GetPart01());
|
|
Console.WriteLine("Puzzle Part02: {0}", pzParsed.GetPart02());
|
|
|
|
class Day05Parsed : AdventCommon.ParsedInput
|
|
{
|
|
public class Page : IComparable<Page>
|
|
{
|
|
public static Dictionary<int, HashSet<int>> RulesByPage = new Dictionary<int, HashSet<int>>();
|
|
|
|
public Page(int value) => Value = value;
|
|
|
|
public int Value { get; set; }
|
|
|
|
public int CompareTo(Page? other)
|
|
{
|
|
if (other == null) throw new Exception("Other is null");
|
|
|
|
if (this.Value == other.Value) return 0;
|
|
|
|
if (!RulesByPage.ContainsKey(this.Value))
|
|
{
|
|
// If there's no key, then this MUST be at the end so its the "biggest"
|
|
return 1;
|
|
}
|
|
|
|
if (RulesByPage[this.Value].Contains(other.Value))
|
|
{
|
|
return -1;
|
|
}
|
|
else if (RulesByPage[other.Value].Contains(this.Value))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
throw new Exception("Unable to compare!");
|
|
}
|
|
}
|
|
public class OrderingRule
|
|
{
|
|
public OrderingRule(string line)
|
|
{
|
|
LeftPage = Int32.Parse(line.Split('|')[0]);
|
|
RightPage = Int32.Parse(line.Split('|')[1]);
|
|
}
|
|
|
|
public int LeftPage { get; set; }
|
|
public int RightPage { get; set; }
|
|
}
|
|
|
|
public class Update
|
|
{
|
|
public Update(string[] pages)
|
|
{
|
|
foreach (var page in pages)
|
|
{
|
|
Pages.Add(Int32.Parse(page));
|
|
}
|
|
}
|
|
|
|
public List<int> Pages { get; set; } = new List<int>();
|
|
}
|
|
|
|
public Dictionary<int, HashSet<int>> RulesByPage { get; set; } = new Dictionary<int, HashSet<int>>();
|
|
|
|
public List<OrderingRule> Rules { get; set; } = new List<OrderingRule>();
|
|
public List<Update> Updates { get; set; } = new List<Update>();
|
|
|
|
public Day05Parsed(string fileName) : base(fileName)
|
|
{
|
|
foreach (var rule in Rules)
|
|
{
|
|
if (RulesByPage.ContainsKey(rule.LeftPage))
|
|
{
|
|
RulesByPage[rule.LeftPage].Add(rule.RightPage);
|
|
}
|
|
else
|
|
{
|
|
RulesByPage.Add(rule.LeftPage, new HashSet<int>() { rule.RightPage });
|
|
}
|
|
}
|
|
|
|
Page.RulesByPage = RulesByPage;
|
|
}
|
|
|
|
public override int GetPart01()
|
|
{
|
|
List<Update> validUpdates = new List<Update>();
|
|
|
|
Updates.ForEach(update => {
|
|
if (IsUpdateValid(update)) validUpdates.Add(update);
|
|
});
|
|
|
|
// We have all the valid updates, now get the "middle" item
|
|
int middlePageNumberSum = 0;
|
|
|
|
foreach (var update in validUpdates)
|
|
{
|
|
middlePageNumberSum += update.Pages[update.Pages.Count / 2];
|
|
}
|
|
|
|
return middlePageNumberSum;
|
|
}
|
|
|
|
public override int GetPart02()
|
|
{
|
|
List<Update> invalidUpdates = new List<Update>();
|
|
|
|
Updates.ForEach(update => {
|
|
if (!IsUpdateValid(update)) invalidUpdates.Add(update);
|
|
});
|
|
|
|
|
|
int middleSum = 0;
|
|
|
|
foreach (var update in invalidUpdates)
|
|
{
|
|
List<Page> pages = new List<Page>();
|
|
|
|
foreach (var page in update.Pages)
|
|
{
|
|
pages.Add(new Page(page));
|
|
}
|
|
|
|
pages.Sort();
|
|
|
|
middleSum += pages[pages.Count / 2].Value;
|
|
}
|
|
|
|
return middleSum;
|
|
}
|
|
|
|
|
|
private bool IsUpdateValid(Update update)
|
|
{
|
|
bool isUpdateValid = true;
|
|
|
|
for (int pageIndex = 0; pageIndex < update.Pages.Count; pageIndex++)
|
|
{
|
|
if (!RulesByPage.ContainsKey(update.Pages[pageIndex]))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var rules = RulesByPage[update.Pages[pageIndex]];
|
|
|
|
// Make sure current page has rules that say its before all the subsequent pages
|
|
for (int subIndex = pageIndex + 1; subIndex < update.Pages.Count; subIndex++)
|
|
{
|
|
if (!rules.Contains(update.Pages[subIndex]))
|
|
{
|
|
isUpdateValid = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Go backwards and make sure none of the previous pages have an existing rule
|
|
for (int i = 0; i < pageIndex; i++)
|
|
{
|
|
if (rules.Contains(update.Pages[i]))
|
|
{
|
|
isUpdateValid = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return isUpdateValid;
|
|
}
|
|
|
|
public override bool ParseLine(string line, object? context = null)
|
|
{
|
|
if (line.Contains('|'))
|
|
{
|
|
// It's a rule
|
|
Rules.Add(new OrderingRule(line));
|
|
}
|
|
else if (!String.IsNullOrWhiteSpace(line))
|
|
{
|
|
// Must be an update
|
|
string[] pages = line.Split(',');
|
|
|
|
Updates.Add(new Update(pages));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|