Advertisement
mgla

Advent of Code - 2024 - Day 15

Dec 15th, 2024 (edited)
162
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.60 KB | None | 0 0
  1. var input = await File.ReadAllTextAsync("input.txt");
  2.  
  3. var directions = new Dictionary<char, Direction>
  4. {
  5.     ['^'] = Direction.Up,
  6.     ['v'] = Direction.Down,
  7.     ['<'] = Direction.Left,
  8.     ['>'] = Direction.Right
  9. };
  10.  
  11. var boxes = new List<Position>();
  12. var walls = new List<Position>();
  13. var boxes2 = new List<DoubleNode>();
  14. var walls2 = new List<DoubleNode>();
  15. var start = new Position(-1, -1);
  16.  
  17. var mapInput = input.Split($"{Environment.NewLine}{Environment.NewLine}")[0].Split(Environment.NewLine);
  18.  
  19. for (var row = 0; row < mapInput.Length; row++)
  20. {
  21.     for (var col = 0; col < mapInput[row].Length; col++)
  22.     {
  23.         var cell = mapInput[row][col];
  24.         switch (cell)
  25.         {
  26.             case '#':
  27.                 walls.Add(new Position(row, col));
  28.                 walls2.Add(new DoubleNode(new Position(row, col * 2), new Position(row, col * 2 + 1)));
  29.                 break;
  30.             case 'O':
  31.                 boxes.Add(new Position(row, col));
  32.                 var box = new DoubleNode(new Position(row, col * 2), new Position(row, col * 2 + 1));
  33.                 if (boxes2.All(b => b.Right != box.Left))
  34.                 {
  35.                     boxes2.Add(box);
  36.                 }
  37.                 break;
  38.             case '@':
  39.                 start = new Position(row, col);
  40.                 break;
  41.         }
  42.     }
  43. }
  44.  
  45. var moves = new List<Direction>();
  46. var movesInput = input.Split($"{Environment.NewLine}{Environment.NewLine}")[1].Split(Environment.NewLine);
  47.  
  48. foreach (var line in movesInput)
  49. {
  50.     moves.AddRange(line.Select(move => directions[move]));
  51. }
  52.  
  53. //Part 1
  54. var robot = start;
  55. foreach (var direction in moves)
  56. {
  57.     var next = robot.Move(direction);
  58.  
  59.     if (walls.Contains(next))
  60.     {
  61.         continue;
  62.     }
  63.  
  64.     if (boxes.Contains(next))
  65.     {
  66.         var nextBox = next.Move(direction);
  67.  
  68.         while (boxes.Contains(nextBox))
  69.         {
  70.             nextBox = nextBox.Move(direction);
  71.         }
  72.  
  73.         if (walls.Contains(nextBox))
  74.         {
  75.             continue;
  76.         }
  77.  
  78.         boxes.Remove(next);
  79.         boxes.Add(nextBox);
  80.     }
  81.  
  82.     robot = next;
  83. }
  84.  
  85. Console.WriteLine($"Part 1: {boxes.Sum(b => b.GpsCoordinates)}");
  86.  
  87. //Part 2
  88. robot = start with { Col = start.Col * 2 };
  89. foreach (var direction in moves)
  90. {
  91.     var next = robot.Move(direction);
  92.  
  93.     if (walls2.Any(w => w.Contains(next)))
  94.     {
  95.         continue;
  96.     }
  97.  
  98.     var nextBox = boxes2.FirstOrDefault(b => b.Contains(next));
  99.     var canMove = true;
  100.  
  101.     if (nextBox != null)
  102.     {
  103.         var boxesToMove = new HashSet<DoubleNode> { nextBox };
  104.         var queue = new Queue<DoubleNode>();
  105.         queue.Enqueue(nextBox);
  106.  
  107.         while (queue.Count > 0)
  108.         {
  109.             var box = queue.Dequeue();
  110.             var nextLeft = box.Left.Move(direction);
  111.             var nextRight = box.Right.Move(direction);
  112.  
  113.             if (walls2.Any(w => w.Contains(nextLeft)) || walls2.Any(w => w.Contains(nextRight)))
  114.             {
  115.                 canMove = false;
  116.                 break;
  117.             }
  118.  
  119.             var nextLeftBox = boxes2.FirstOrDefault(b => b.Contains(nextLeft));
  120.             if (nextLeftBox != null && boxesToMove.Add(nextLeftBox))
  121.             {
  122.                 queue.Enqueue(nextLeftBox);
  123.             }
  124.  
  125.             var nextRightBox = boxes2.FirstOrDefault(b => b.Contains(nextRight));
  126.             if (nextRightBox != null && boxesToMove.Add(nextRightBox))
  127.             {
  128.                 queue.Enqueue(nextRightBox);
  129.             }
  130.         }
  131.  
  132.         if (canMove)
  133.         {
  134.             foreach (var box in boxesToMove)
  135.             {
  136.                 boxes2.Remove(box);
  137.                 boxes2.Add(new DoubleNode(box.Left.Move(direction), box.Right.Move(direction)));
  138.             }
  139.         }
  140.     }
  141.  
  142.     if (canMove)
  143.     {
  144.         robot = next;
  145.     }
  146. }
  147.  
  148. Console.WriteLine($"Part 2: {boxes2.Sum(b => b.Left.GpsCoordinates)}");
  149.  
  150. internal record DoubleNode(Position Left, Position Right)
  151. {
  152.     public bool Contains(Position position) => Left.Row <= position.Row && position.Row <= Right.Row &&
  153.                                                Left.Col <= position.Col && position.Col <= Right.Col;
  154. }
  155.  
  156. internal record Direction(int Row, int Col)
  157. {
  158.     public static readonly Direction Up = new(-1, 0);
  159.     public static readonly Direction Down = new(1, 0);
  160.     public static readonly Direction Left = new(0, -1);
  161.     public static readonly Direction Right = new(0, 1);
  162. }
  163.  
  164. internal record Position(int Row, int Col)
  165. {
  166.     public Position Move(Direction dir) => new(Row + dir.Row, Col + dir.Col);
  167.  
  168.     public int GpsCoordinates => Row * 100 + Col;
  169. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement