public List <LuggageRule> ParseRules(List <string> rules) { var luggageRules = new List <LuggageRule>(); foreach (var line in rules) { var parts = line.Split("bags contain"); var color = parts[0].Trim(); var luggageRule = new LuggageRule(color); var requiredContent = parts[1].Split(","); foreach (var requiredBag in requiredContent) { if (requiredBag.Contains("no other bags")) { continue; } var bagParts = requiredBag.Trim(' ').Split(" "); var requiredBagQuantity = Int32.Parse(bagParts[0]); var bagColor = bagParts[1] + " " + bagParts[2]; var bagContent = new BagContent(bagColor, requiredBagQuantity); luggageRule.RequiredContent.Add(bagContent); } luggageRules.Add(luggageRule); } return(luggageRules); }
async static Task Main(string[] args) { var containsRegex = new Regex( "(?'tag'[a-z\\s]+)\\sbags\\scontain(?:\\s(?'bagcount'[0-9]+)\\s(?'bagtype'[a-z\\s]+)\\sbag[s]?,)*\\s(?'bagcount'[0-9])\\s(?'bagtype'[a-z\\s]+)\\sbag[s]?\\.", RegexOptions.Compiled); var noBagsRegex = new Regex("(?'tag'[a-z\\s]+)\\sbags\\scontain\\sno\\sother\\sbags\\.", RegexOptions.Compiled); using var file = new FileStream("input.txt", FileMode.Open); using var reader = new StreamReader(file); var bagDescriptors = new List <BagDescriptor>(); while (true) { var line = await reader.ReadLineAsync(); if (line == null) { break; } var contents = default(BagContent[]); var name = default(string?); var match = containsRegex.Match(line); if (match.Success) { name = match.Groups["tag"].Value; var countCaptures = match.Groups["bagcount"].Captures; var typeCaptures = match.Groups["bagtype"].Captures; if (countCaptures.Count != typeCaptures.Count) { throw new Exception("Bagcontent mismatch"); } contents = countCaptures .Zip(typeCaptures, (a, b) => (count: int.Parse(a.Value), type: b.Value)) .Select(c => new BagContent(c.count, c.type)) .ToArray(); } else { match = noBagsRegex.Match(line); if (match.Success) { name = match.Groups["tag"].Value; contents = new BagContent[0]; } else { throw new Exception("Unknown line"); } } bagDescriptors.Add(new BagDescriptor(name, contents)); } var bagNodes = bagDescriptors .Select(bd => new BagNode { Name = bd.Name }) .ToDictionary(b => b.Name, b => b); foreach (var descriptor in bagDescriptors) { var outsideBag = bagNodes[descriptor.Name]; foreach (var content in descriptor.Content) { var insideBag = bagNodes[content.Bagname]; var edge = new BagEdge(outsideBag, insideBag, content.Count); outsideBag.OutgoingEdges.Add(edge); insideBag.IncomingEdges.Add(edge); } } var workQueue = new Queue <BagNode>(); var initial = bagNodes["shiny gold"]; workQueue.Enqueue(initial); while (workQueue.Any()) { var entry = workQueue.Dequeue(); entry.Marked = true; foreach (var edge in entry.IncomingEdges) { if (!edge.ContainingNode.Marked) { workQueue.Enqueue(edge.ContainingNode); } } } var numReached = bagNodes.Count(kvp => kvp.Value.Marked) - 1; Console.WriteLine(numReached); var bagCounter = 0; var contentQueue = new Queue <(BagNode item, int multiplier)>(); contentQueue.Enqueue((initial, 1)); while (contentQueue.Any()) { var entry = contentQueue.Dequeue(); foreach (var edge in entry.item.OutgoingEdges) { bagCounter += edge.Count * entry.multiplier; contentQueue.Enqueue((edge.ContentNode, entry.multiplier * edge.Count)); } } Console.WriteLine(bagCounter); }
static void Main(string[] args) { var lines = File.ReadAllLines("input.txt"); var listOfBags = new List <Bag>(); var baseColours = new List <Bag>(); // Grab all of the distinct bag names to give us a place to start foreach (var line in lines) { var components = line.Split("contain"); var bagColourRaw = components[0]; var bagColour = bagColourRaw.Substring(0, bagColourRaw.Length - 6); // -4 because "bags", 2 for spaces if (!baseColours.Any(b => b.Colour == bagColour)) { baseColours.Add(new Bag() { Colour = bagColour }); } } // baseColours now has a list of Bags that have all the top level colours // now need to iterate again to fill up each Bag with the correct contents, using existing Bag refs as // the content for the bags // Step through it all again but this time add bags to the list using references saved from above // Might be able to do this in one loop, but making the assumption that the contents of // the input file is NOT in order. If it is in order, can do this in one loop foreach (var line in lines) { var components = line.Split("contain"); var bagColourRaw = components[0]; var bagColour = bagColourRaw.Substring(0, bagColourRaw.Length - 6); // -4 because "bags", 2 for spaces var contentColours = components[1]; var baseBag = baseColours.First(b => b.Colour == bagColour); if (contentColours.Trim() == "no other bags.") { listOfBags.Add(baseBag); continue; } var contentBagsRaw = contentColours.Split(','); foreach (var content in contentBagsRaw) { var cnt = content.Trim(); var pieces = cnt.Split(' '); var quantity = pieces[0]; var colour = pieces[1] + " " + pieces[2]; var bag = baseColours.First(v => v.Colour == colour); var bagContent = new BagContent() { Bag = bag, Quantity = Convert.ToInt32(quantity) }; baseBag.Contents.Add(bagContent); } listOfBags.Add(baseBag); } // By here the list is fully populate with nodes that reference bags properly var numberOfBagsContainingAtLeastOne = 0; foreach (var bag in listOfBags) { // Solution for Part 2 if (bag.Colour == "shiny gold") { var amountInThisBag = CountBags(bag.Contents); Console.WriteLine("Shiny gold:" + amountInThisBag); } // Solution for Part 1 else { var amountInThisBag = CountContent("shiny gold", bag.Contents); if (amountInThisBag > 0) { numberOfBagsContainingAtLeastOne++; } } } Console.WriteLine(numberOfBagsContainingAtLeastOne); }