Guest User

Untitled

a guest
Dec 20th, 2023
316
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.72 KB | None | 0 0
  1. using AdventLib;
  2. using Microsoft.VisualStudio.TestTools.UnitTesting;
  3.  
  4. namespace AdventOfCode2023;
  5.  
  6. /// <summary>
  7. /// Solver for [day 20](https://adventofcode.com/2023/day/20)
  8. /// </summary>
  9. public class Day20 : AdventSolver {
  10. public override string Day => "day20";
  11.  
  12. public override void Solve() {
  13.  
  14. //// Part 1
  15. Dictionary<string, Module> part1Modules = BuildModuleMap();
  16.  
  17. long sumLow = 0;
  18. long sumHigh = 0;
  19.  
  20. for (int x = 0; x < 1000; x++) {
  21. (var low, var high) = CountTriggers(part1Modules, x + 1, []);
  22. sumLow += low;
  23. sumHigh += high;
  24. }
  25.  
  26. Console.WriteLine("Solution for part 1 is: " + sumLow + "*" + sumHigh + "=" + (sumLow * sumHigh));
  27.  
  28. //// Part 2
  29. // reload the modules so they reset
  30. Dictionary<string, Module> part2Modules = BuildModuleMap();
  31.  
  32.  
  33. // Assumes that rx has 1 Source, which is a 4x Conjunction
  34. Dictionary<string, List<long>> watchlist = [];
  35.  
  36. // Get the source for the conjunction
  37. var conjunction = part2Modules["rx"].Sources[0];
  38. foreach (var conjSource in part2Modules[conjunction].Sources) {
  39. // for each input to the conjunction add it to the list
  40. watchlist.Add(conjSource, []);
  41. }
  42.  
  43. // Run until we have 2 values and can determine the period between them
  44. for (int x = 0; watchlist.Values.Any(l => l.Count < 2); x++) {
  45. CountTriggers(part2Modules, x, watchlist);
  46. }
  47.  
  48. // calculate the period between and generate an LCM
  49. Console.WriteLine("Solution for part 2 is = " + watchlist.Keys.Select(key => watchlist[key][1] - watchlist[key][0]).Lcm());
  50. }
  51.  
  52. public Dictionary<string, Module> BuildModuleMap() {
  53. List<Module> modules = [];
  54.  
  55. // Parse everything
  56. foreach (string game in ReadInputAsIEnumerable()) {
  57. if (game.StartsWith("broadcaster")) {
  58. modules.Add(new BroadcasterModule(game.Split("->")[1].Split(",").Select(s => s.Trim()).ToList()));
  59. } else if (game.StartsWith("%")) {
  60. var kvp = game.Substring(1).Split(" -> ");
  61. modules.Add(new FlipFlopModule(kvp[0], kvp[1].Split(",").Select(s => s.Trim()).ToList()));
  62. } else if (game.StartsWith("&")) {
  63. var kvp = game.Substring(1).Split(" -> ");
  64. modules.Add(new ConjunctionModule(kvp[0], kvp[1].Split(",").Select(s => s.Trim()).ToList()));
  65. }
  66. }
  67.  
  68. RxModule rx = new();
  69.  
  70. modules.Add(new ButtonModule());
  71. modules.Add(rx);
  72.  
  73. Dictionary<string, Module> moduleMap = modules.Select(module => (module.Name, module)).ToDictionary();
  74.  
  75. // Register all sources
  76. foreach (var (key, module) in moduleMap) {
  77. foreach (var target in module.Targets) {
  78. if (moduleMap.ContainsKey(target)) {
  79. moduleMap[target].RegisterSource(key);
  80. }
  81. }
  82. }
  83. return moduleMap;
  84. }
  85.  
  86. public (long, long) CountTriggers(Dictionary<string, Module> modules, int iteration, Dictionary<string, List<long>> watchlist) {
  87. long numLow = 0;
  88. long numHigh = 0;
  89.  
  90. Queue<ModuleTrigger> triggers = [];
  91. triggers.Enqueue(new ModuleTrigger("", "button", true));
  92.  
  93. while (triggers.Count > 0) {
  94. var next = triggers.Dequeue();
  95. if (modules.ContainsKey(next.Target)) {
  96. foreach (var trigger in modules[next.Target].Pulse(next.Source, next.IsLowPulse)) {
  97. //Console.WriteLine("{0} -{1}-> {2}", trigger.source, trigger.IsLowPulse ? "low" : "high", trigger.Target);
  98.  
  99. if (watchlist.TryGetValue(next.Source, out List<long>? value) && next.Target == "hf" && !next.IsLowPulse) {
  100. value.Add(iteration);
  101. }
  102.  
  103. if (trigger.IsLowPulse) {
  104. numLow++;
  105. } else {
  106. numHigh++;
  107. }
  108.  
  109. triggers.Enqueue(trigger);
  110. }
  111. }
  112. }
  113.  
  114. return (numLow, numHigh);
  115. }
  116.  
  117. public struct ModuleTrigger(string source, string target, bool isLowPulse) {
  118.  
  119. public readonly string Source = source;
  120. public readonly string Target = target;
  121. public readonly bool IsLowPulse = isLowPulse;
  122. }
  123.  
  124. public abstract class Module(string name, List<string> targets) {
  125.  
  126. public readonly string Name = name;
  127. public readonly List<string> Targets = targets;
  128.  
  129. public readonly List<string> Sources = [];
  130.  
  131. public virtual IEnumerable<ModuleTrigger> Pulse(string source, bool isLow) {
  132. foreach (var target in Targets) {
  133. yield return new ModuleTrigger(Name, target, isLow);
  134. }
  135. }
  136.  
  137. public virtual void RegisterSource(string source) {
  138. Sources.Add(source);
  139. }
  140. }
  141.  
  142. public class RxModule() : Module("rx", []) {
  143. public bool hasReceivedLow = false;
  144.  
  145. public override IEnumerable<ModuleTrigger> Pulse(string source, bool isLow) {
  146. if (isLow) hasReceivedLow = true;
  147.  
  148. return base.Pulse(source, isLow);
  149. }
  150. }
  151.  
  152. public class ButtonModule() : Module("button", ["broadcaster"]) {
  153. }
  154.  
  155. public class FlipFlopModule(string name, List<string> targets) : Module(name, targets) {
  156. private bool lastIsLow = true;
  157.  
  158. public override IEnumerable<ModuleTrigger> Pulse(string source, bool isLow) {
  159. if (isLow) {
  160. lastIsLow = !lastIsLow;
  161. // triggered after the flip, so the first time it sends high
  162. return base.Pulse(source, lastIsLow);
  163. } else {
  164. return [];
  165. }
  166. }
  167. }
  168.  
  169. public class ConjunctionModule(string name, List<string> targets) : Module(name, targets) {
  170. private readonly Dictionary<string, bool> SourceStates = [];
  171.  
  172. public override void RegisterSource(string name) {
  173. SourceStates.Add(name, true);
  174. base.RegisterSource(name);
  175. }
  176.  
  177. public override IEnumerable<ModuleTrigger> Pulse(string source, bool isLow) {
  178. SourceStates[source] = isLow;
  179. if (SourceStates.Values.All(lastPulse => !lastPulse)) {
  180. // triggered after the flip, so the first time it sends high
  181. return base.Pulse(source, true);
  182. } else {
  183. return base.Pulse(source, false);
  184. }
  185. }
  186. }
  187.  
  188. public class BroadcasterModule(List<string> targets) : Module("broadcaster", targets) {
  189. }
  190. }
Advertisement
Add Comment
Please, Sign In to add comment