Advertisement
mgla

Advent of Code 2023 - Day 21

Dec 21st, 2023 (edited)
1,304
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 3.03 KB | None | 0 0
  1. var input = File.ReadAllLines("input.txt");
  2. // The grid is a square of 131x131 tiles. S is in the exact center at (65, 65).
  3. // The edge rows and columns are all open, and S has a straight path to all of them.
  4. // It takes 65 steps to reach the first set of edges, then 131 more to reach every next set.
  5. // When we reach the first edges, the points form a diamond.
  6. // Then we run to the next edges, and to the ones after that, making the diamond grow.
  7. // For each of those 3 runs, we will store the number of steps taken (x) and the number of open tiles at that step (y).
  8. // 3 pairs are enough to interpolate the growth function - y = f(x),
  9. // so I went searching for an online Lagrange interpolation calculator,
  10. // because that is all I can remember about numerical methods from college. :)
  11. // I found this, and it helped: https://www.dcode.fr/lagrange-interpolating-polynomial
  12. // It's a quadratic formula! (it's a square grid, and with every step we form a perfect diamond, so it makes sense)
  13. // So we can just calculate the formula for X = 26501365, and we get the answer.
  14.  
  15. const long totalSteps = 26501365L;
  16.  
  17. var sequenceCounts = new List<(int X, int Y)>();
  18. var startPosition = input.Length / 2; // 65
  19. var start = new Position(startPosition, startPosition);
  20. var visited = new HashSet<Position> { start };
  21. var steps = 0;
  22.  
  23. for (var run = 0; run < 3; run++)
  24. {
  25.     for (; steps < run * 131 + 65; steps++) // First run is 65 steps, the rest are 131 each.
  26.     {
  27.         var nextOpen = new HashSet<Position>();
  28.         foreach (var position in visited)
  29.         {
  30.             foreach (var dir in new[] { Direction.Up, Direction.Down, Direction.Left, Direction.Right })
  31.             {
  32.                 var dest = position.Move(dir);
  33.                 if (input[Modulo(dest.Row)][Modulo(dest.Col)] != '#')
  34.                 {
  35.                     nextOpen.Add(dest);
  36.                 }
  37.             }
  38.         }
  39.  
  40.         visited = nextOpen;
  41.  
  42.         if (steps == 63)
  43.         {
  44.             Console.WriteLine($"Part 1: {visited.Count}");
  45.         }
  46.     }
  47.     sequenceCounts.Add((steps, visited.Count));
  48. }
  49.  
  50. // Lagrange interpolation
  51. double result = 0;
  52.  
  53. for (var i = 0; i < 3; i++)
  54. {
  55.     // Compute individual terms of formula
  56.     double term = sequenceCounts[i].Y;
  57.  
  58.     for (var j = 0; j < 3; j++)
  59.     {
  60.         if (j != i)
  61.         {
  62.             term = term * (totalSteps - sequenceCounts[j].X) / (sequenceCounts[i].X - sequenceCounts[j].X);
  63.         }
  64.     }
  65.  
  66.     // Add current term to result
  67.     result += term;
  68. }
  69.  
  70. Console.WriteLine($"Part 2: {result}");
  71.  
  72. return;
  73.  
  74. static int Modulo(int number)
  75. {
  76.     return ((number % 131) + 131) % 131;
  77. }
  78.  
  79. internal record Direction(int Row, int Col)
  80. {
  81.     public static Direction Up = new(-1, 0);
  82.     public static Direction Down = new(1, 0);
  83.     public static Direction Left = new(0, -1);
  84.     public static Direction Right = new(0, 1);
  85. }
  86.  
  87. internal record Position(int Row, int Col)
  88. {
  89.     public Position Move(Direction dir)
  90.     {
  91.         return new Position(Row + dir.Row, Col + dir.Col);
  92.     }
  93. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement