Advertisement
mgla

Advent of Code 2023 - Day 19

Dec 19th, 2023 (edited)
770
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.55 KB | None | 0 0
  1. var input = File.ReadAllText("input.txt").Split("\r\n\r\n");
  2.  
  3. var workflows = input[0].Split("\r\n").Select(workflow => new Workflow(workflow)).ToDictionary(w => w.Name);
  4.  
  5. var messages = input[1].Split("\r\n");
  6. var parts = new List<Dictionary<string, int>>();
  7.  
  8. foreach (var message in messages)
  9. {
  10.     var part = new Dictionary<string, int>();
  11.     var values = message[1..^1].Split(',').Select(r => r.Split('='));
  12.  
  13.     foreach (var xmas in values)
  14.     {
  15.         part[xmas[0]] = int.Parse(xmas[1]);
  16.     }
  17.  
  18.     parts.Add(part);
  19. }
  20.  
  21. var part1 = 0;
  22. foreach (var part in parts)
  23. {
  24.     var workflow = workflows["in"];
  25.     var processing = true;
  26.  
  27.     while (processing)
  28.     {
  29.         foreach (var rule in workflow.Rules)
  30.         {
  31.             // If there is no condition, the rule is valid and we process it.
  32.             var isValid = rule.Comparison == default;
  33.  
  34.             if (!isValid)
  35.             {
  36.                 var value = part[rule.Xmas];
  37.                 isValid = rule.Comparison == '>' && value > rule.Value ||
  38.                           rule.Comparison == '<' && value < rule.Value;
  39.             }
  40.  
  41.             if (isValid)
  42.             {
  43.                 switch (rule.Destination)
  44.                 {
  45.                     case "A":
  46.                         part1 += part.Sum(p => p.Value);
  47.                         processing = false;
  48.                         break;
  49.                     case "R":
  50.                         processing = false;
  51.                         break;
  52.                     default:
  53.                         workflow = workflows[rule.Destination]; // Process the next workflow.
  54.                         break;
  55.                 }
  56.  
  57.                 break; // We found a valid rule, so we can stop processing the current workflow.
  58.             }
  59.         }
  60.     }
  61. }
  62.  
  63. Console.WriteLine($"Part 1: {part1}");
  64.  
  65. var candidates = new Dictionary<string, (int Min, int Max)>
  66. {
  67.     ["x"] = (1, 4000),
  68.     ["m"] = (1, 4000),
  69.     ["a"] = (1, 4000),
  70.     ["s"] = (1, 4000)
  71. };
  72.  
  73. Console.WriteLine($"Part 2: {ProcessRanges("in", candidates)}");
  74.  
  75. return;
  76.  
  77. long ProcessRanges(string position, Dictionary<string, (int Min, int Max)> ranges)
  78. {
  79.     switch (position)
  80.     {
  81.         case "A":
  82.             return ranges.Values
  83.                 .Aggregate<(int Min, int Max), long>(1, (current, range) => current * (range.Max - range.Min + 1));
  84.         case "R":
  85.             return 0;
  86.     }
  87.  
  88.     long result = 0;
  89.     var workflow = workflows[position];
  90.  
  91.     foreach (var rule in workflow.Rules)
  92.     {
  93.         var (min, max) = string.IsNullOrEmpty(rule.Xmas) ? (0, 0) : ranges[rule.Xmas];
  94.  
  95.         switch (rule.Comparison)
  96.         {
  97.             case '<':
  98.                 if (max < rule.Value) // Entire range fits. Recursively process the next workflow.
  99.                 {
  100.                     result += ProcessRanges(rule.Destination, ranges);
  101.                     return result;
  102.                 }
  103.  
  104.                 if (min < rule.Value) // Range needs to be split.
  105.                 {
  106.                     // Recursively process the fitting range into the next workflow.
  107.                     var newRanges = new Dictionary<string, (int Min, int Max)>(ranges)
  108.                     {
  109.                         [rule.Xmas] = (min, rule.Value - 1)
  110.                     };
  111.                     result += ProcessRanges(rule.Destination, newRanges);
  112.  
  113.                     ranges[rule.Xmas] = (rule.Value, max); // Use the remaining range for the next rule.
  114.                 }
  115.                 break;
  116.             case '>':
  117.                 if (min > rule.Value) // Entire range fits. Recursively process the next workflow.
  118.                 {
  119.                     result += ProcessRanges(rule.Destination, ranges);
  120.                     return result;
  121.                 }
  122.  
  123.                 if (max > rule.Value) // Range needs to be split.
  124.                 {
  125.                     // Recursively process the fitting range into the next workflow.
  126.                     var newRanges = new Dictionary<string, (int Min, int Max)>(ranges)
  127.                     {
  128.                         [rule.Xmas] = (rule.Value + 1, max)
  129.                     };
  130.                     result += ProcessRanges(rule.Destination, newRanges);
  131.  
  132.                     ranges[rule.Xmas] = (min, rule.Value); // Use the remaining range for the next rule.
  133.                 }
  134.                 break;
  135.             default:
  136.                 // No conditions - recursively process the next workflow.
  137.                 result += ProcessRanges(rule.Destination, ranges);
  138.                 break;
  139.         }
  140.     }
  141.  
  142.     return result;
  143. }
  144.  
  145. internal struct Workflow
  146. {
  147.     public Workflow(string pattern)
  148.     {
  149.         Name = pattern.Split('{')[0];
  150.         var rules = pattern.Split('{')[1].TrimEnd('}').Split(',').ToList();
  151.         foreach (var rule in rules)
  152.         {
  153.             Rules.Add(new Rule(rule));
  154.         }
  155.     }
  156.  
  157.     public string Name { get; set; }
  158.     public List<Rule> Rules { get; set; } = new();
  159. }
  160.  
  161. internal struct Rule
  162. {
  163.     public Rule(string rule)
  164.     {
  165.         var splitRule = rule.Split('<', '>');
  166.  
  167.         if (splitRule.Length == 2)
  168.         {
  169.             var right = splitRule[1].Split(':');
  170.  
  171.             Xmas = splitRule[0];
  172.             Value = int.Parse(right[0]);
  173.             Destination = right[1];
  174.             Comparison = rule[1];
  175.         }
  176.         else
  177.         {
  178.             Destination = rule;
  179.         }
  180.     }
  181.     public string Xmas { get; set; } = string.Empty;
  182.     public char Comparison { get; set; }
  183.     public int Value { get; set; }
  184.     public string Destination { get; set; }
  185. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement