335 lines
8.6 KiB
C#
335 lines
8.6 KiB
C#
// See https://aka.ms/new-console-template for more information
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Windows.Markup;
|
|
|
|
|
|
Part01();
|
|
Console.WriteLine();
|
|
Part02();
|
|
|
|
void Part01()
|
|
{
|
|
Console.WriteLine("!! === Part 1 === !!");
|
|
Console.WriteLine(" === Example Data ===");
|
|
var examplePackets = ReadPacketPairs("example-input.txt");
|
|
//PrintPackets(examplePackets);
|
|
Console.WriteLine("Sum of combined pair indices: " + GetSumOfOrderedPairs(examplePackets));
|
|
|
|
Console.WriteLine(" === Puzzle Data ===");
|
|
var puzzlePackets = ReadPacketPairs("puzzle-input.txt");
|
|
//PrintPackets(puzzlePackets);
|
|
Console.WriteLine("Sum of combined pair indices: " + GetSumOfOrderedPairs(puzzlePackets));
|
|
}
|
|
|
|
void Part02()
|
|
{
|
|
Console.WriteLine("!! === Part 2 === !!");
|
|
Console.WriteLine(" === Example Data ===");
|
|
var examplePackets = ReadPackets("example-input.txt");
|
|
InsertDividers(examplePackets);
|
|
examplePackets.Sort();
|
|
PrintPart02Sln(examplePackets);
|
|
|
|
Console.WriteLine(" === Puzzle Data ===");
|
|
var puzzlePackets = ReadPackets("puzzle-input.txt");
|
|
InsertDividers(puzzlePackets);
|
|
puzzlePackets.Sort();
|
|
PrintPart02Sln(puzzlePackets);
|
|
}
|
|
|
|
void PrintPart02Sln(List<IComparable> packets)
|
|
{
|
|
var dividers = GetDividers();
|
|
int first = -1;
|
|
int second = -1;
|
|
int index = 1;
|
|
|
|
foreach (var packet in packets)
|
|
{
|
|
if (packet.CompareTo(dividers.Data.Item1) == 0) first = index;
|
|
if (packet.CompareTo(dividers.Data.Item2) == 0) second = index;
|
|
|
|
index++;
|
|
}
|
|
|
|
Console.WriteLine("Dividers at {0} and {1}. Key: {2}", first, second, first * second);
|
|
}
|
|
|
|
int GetSumOfOrderedPairs(List<PacketPair> packetPairs)
|
|
{
|
|
int sum = 0, index = 1;
|
|
foreach (var packet in packetPairs)
|
|
{
|
|
if (packet.IsCorrectlyOrdered()) sum += index;
|
|
index++;
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
|
|
void InsertDividers(List<IComparable> packets)
|
|
{
|
|
PacketPair pair = GetDividers();
|
|
packets.Add(pair.Data.Item1);
|
|
packets.Add(pair.Data.Item2);
|
|
}
|
|
|
|
PacketPair GetDividers()
|
|
{
|
|
return new PacketPair("[[2]]", "[[6]]");
|
|
}
|
|
|
|
void PrintPacketPairs(List<PacketPair> packets)
|
|
{
|
|
Console.WriteLine("- Printing packets -");
|
|
foreach (var packet in packets) Console.WriteLine(String.Format("{0} {1} correctly ordered.", packet.ToString(), packet.IsCorrectlyOrdered() ? "is" : "is NOT"));
|
|
//foreach (var packet in packets)
|
|
//{
|
|
// Console.WriteLine(packet.Data.Item1.ToString());
|
|
// Console.WriteLine(packet.Data.Item2.ToString());
|
|
// Console.WriteLine();
|
|
//}
|
|
Console.WriteLine("- Done -");
|
|
}
|
|
|
|
List<IComparable> ReadPackets(string filename)
|
|
{
|
|
List<IComparable> packets = new List<IComparable>();
|
|
|
|
foreach (var pair in ReadPacketPairs(filename))
|
|
{
|
|
if (pair == null) throw new InvalidDataException();
|
|
|
|
packets.Add(pair.Data.Item1);
|
|
packets.Add(pair.Data.Item2);
|
|
}
|
|
|
|
return packets;
|
|
}
|
|
|
|
List<PacketPair> ReadPacketPairs(string filename)
|
|
{
|
|
List<PacketPair> packets = new List<PacketPair>();
|
|
|
|
using (StreamReader reader = System.IO.File.OpenText(filename))
|
|
{
|
|
while (!reader.EndOfStream)
|
|
{
|
|
// Read the next two lines
|
|
string? left = reader.ReadLine();
|
|
string? right = reader.ReadLine();
|
|
|
|
if (left == null || right == null) throw new InvalidDataException();
|
|
|
|
packets.Add(new PacketPair(left, right));
|
|
|
|
// Read the empty line
|
|
reader.ReadLine();
|
|
}
|
|
}
|
|
|
|
return packets;
|
|
}
|
|
|
|
class PacketPair
|
|
{
|
|
public PacketPair(string dataLeft, string dataRight)
|
|
{
|
|
ListData left = Parse(dataLeft);
|
|
ListData right = Parse(dataRight);
|
|
|
|
Data = new Tuple<IComparable, IComparable>(left, right);
|
|
}
|
|
|
|
private int Parse(ListData list, string data, int currentIndex)
|
|
{
|
|
if (data[currentIndex] != '[') throw new InvalidDataException();
|
|
|
|
for (int i = currentIndex+1; i < data.Length; i++)
|
|
{
|
|
if (data[i] == ',') continue;
|
|
|
|
if (data[i] == '[')
|
|
{
|
|
ListData newList = new ListData();
|
|
// Found a list
|
|
i = Parse(newList, data, i);
|
|
|
|
list.Values.Add(newList);
|
|
}
|
|
else if (Char.IsDigit(data[i]))
|
|
{
|
|
int strlen = 0;
|
|
for (int j = i; Char.IsDigit(data[j]); j++,strlen++);
|
|
|
|
list.Values.Add(new IntegerData(Int32.Parse(data.Substring(i, strlen))));
|
|
|
|
while (data[i] != ',' && data[i] != ']') i++;
|
|
if (data[i] == ',')
|
|
{
|
|
// Move to the next piece of data
|
|
continue;
|
|
}
|
|
else if (data[i] == ']')
|
|
{
|
|
// We're done with the values of this object, we can exit
|
|
return i;
|
|
}
|
|
}
|
|
else if (data[i] == ']')
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
throw new InvalidDataException();
|
|
}
|
|
|
|
private ListData Parse(string data)
|
|
{
|
|
ListData list = new ListData();
|
|
|
|
Parse(list, data, 0);
|
|
|
|
return list;
|
|
}
|
|
|
|
public Tuple<IComparable, IComparable> Data {get; set;}
|
|
|
|
public bool IsCorrectlyOrdered()
|
|
{
|
|
return Data.Item1.CompareTo(Data.Item2) <= 0;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return Data.Item1.ToString() + " vs " + Data.Item2.ToString();
|
|
}
|
|
}
|
|
|
|
class IntegerData : IComparable
|
|
{
|
|
public IntegerData(int value)
|
|
{
|
|
Value = value;
|
|
}
|
|
|
|
public int Value { get; set;}
|
|
|
|
public int CompareTo(object? right)
|
|
{
|
|
var integerData = right as IntegerData;
|
|
var listData = right as ListData;
|
|
|
|
if (integerData != null)
|
|
{
|
|
return Value.CompareTo(integerData.Value);
|
|
}
|
|
else if (listData != null)
|
|
{
|
|
ListData leftList = new ListData();
|
|
leftList.Values.Add(this);
|
|
return leftList.CompareTo(listData);
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidDataException();
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return Value.ToString();
|
|
}
|
|
}
|
|
|
|
class ListData : IComparable
|
|
{
|
|
public List<IComparable> Values { get; set;} = new List<IComparable>();
|
|
|
|
public int CompareTo(object? obj)
|
|
{
|
|
var integerData = obj as IntegerData;
|
|
var listData = obj as ListData;
|
|
|
|
if (integerData != null)
|
|
{
|
|
ListData rightList = new ListData();
|
|
rightList.Values.Add(integerData);
|
|
return CompareLists(this, rightList);
|
|
}
|
|
else if (listData != null)
|
|
{
|
|
return CompareLists(this, listData);
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidDataException();
|
|
}
|
|
}
|
|
|
|
int CompareLists(ListData left, ListData right)
|
|
{
|
|
if (left.Values.Count == 0 && right.Values.Count == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (left.Values.Count == 0)
|
|
{
|
|
return -1;
|
|
}
|
|
else if (left.Values.Count > 0 && right.Values.Count == 0)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; ; i++)
|
|
{
|
|
if (i < left.Values.Count && i < right.Values.Count)
|
|
{
|
|
var result = left.Values[i].CompareTo(right.Values[i]);
|
|
|
|
if (result != 0) return result;
|
|
}
|
|
else if (i == left.Values.Count && i == right.Values.Count)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (i >= left.Values.Count)
|
|
{
|
|
return -1;
|
|
}
|
|
else if (i >= right.Values.Count)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
string str = "";
|
|
|
|
str += '[';
|
|
|
|
for (int i = 0; i < Values.Count; i++)
|
|
{
|
|
if (i > 0) str += ',';
|
|
|
|
str += Values[i].ToString();
|
|
}
|
|
str += "]";
|
|
|
|
return str;
|
|
}
|
|
}
|
|
|