Advertisement
Guest User

Infi - Advent of Code 2024

a guest
Dec 2nd, 2024
34
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 9.74 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4.  
  5. namespace MonkeyIslandAdventure;
  6.  
  7. // Represents a coordinate in the 3D treasure map.
  8. public readonly record struct IslandCoordinate(int X, int Y, int Z);
  9.  
  10. // Base class for all pirate commands.
  11. public abstract record PirateCommand
  12. {
  13.     public abstract void Execute(Guybrush guybrush);
  14. }
  15.  
  16. // Hoist instruction class.
  17. public sealed record HoistInstruction(Func<IslandCoordinate, int> ValueProvider) : PirateCommand
  18. {
  19.     public override void Execute(Guybrush guybrush)
  20.     {
  21.         int piecesOfEight = ValueProvider(guybrush.CurrentLocation);
  22.         guybrush.LootSack.Push(piecesOfEight);
  23.         guybrush.CompassPointer++;
  24.     }
  25. }
  26.  
  27. // Plunder instruction class.
  28. public sealed record PlunderInstruction() : PirateCommand
  29. {
  30.     public override void Execute(Guybrush guybrush)
  31.     {
  32.         if (guybrush.LootSack.Count < 2)
  33.             throw new InvalidOperationException("Ye don't have enough booty for plunderin'!");
  34.  
  35.         int val1 = guybrush.LootSack.Pop();
  36.         int val2 = guybrush.LootSack.Pop();
  37.         guybrush.LootSack.Push(val1 + val2);
  38.         guybrush.CompassPointer++;
  39.     }
  40. }
  41.  
  42. // SetSail instruction class.
  43. public sealed record SetSailInstruction(int Offset) : PirateCommand
  44. {
  45.     public override void Execute(Guybrush guybrush)
  46.     {
  47.         if (guybrush.LootSack.Count < 1)
  48.             throw new InvalidOperationException("Ye can't set sail without any loot!");
  49.  
  50.         int piecesOfEight = guybrush.LootSack.Pop();
  51.         if (piecesOfEight >= 0)
  52.             guybrush.CompassPointer += Offset;
  53.  
  54.         guybrush.CompassPointer++;
  55.     }
  56. }
  57.  
  58. // Dock instruction class.
  59. public sealed record DockInstruction() : PirateCommand
  60. {
  61.     public override void Execute(Guybrush guybrush)
  62.     {
  63.         if (guybrush.LootSack.Count < 1)
  64.             throw new InvalidOperationException("No booty to dock with!");
  65.  
  66.         guybrush.BootyValue = guybrush.LootSack.Peek();
  67.         guybrush.QuestComplete = true;
  68.     }
  69. }
  70.  
  71. // Guybrush class that represents our hero on his adventure.
  72. public class Guybrush
  73. {
  74.     public Stack<int> LootSack { get; } = new();
  75.     public int CompassPointer { get; set; }
  76.     public bool QuestComplete { get; set; }
  77.     public int BootyValue { get; set; }
  78.     public IslandCoordinate CurrentLocation { get; }
  79.  
  80.     private readonly List<PirateCommand> _pirateCommands;
  81.  
  82.     public Guybrush(List<PirateCommand> pirateCommands, IslandCoordinate location)
  83.     {
  84.         _pirateCommands = pirateCommands ?? throw new ArgumentNullException(nameof(pirateCommands));
  85.         CurrentLocation = location;
  86.     }
  87.  
  88.     public int EmbarkOnQuest()
  89.     {
  90.         while (!QuestComplete && CompassPointer >= 0 && CompassPointer < _pirateCommands.Count)
  91.         {
  92.             PirateCommand command = _pirateCommands[CompassPointer];
  93.             command.Execute(this);
  94.         }
  95.  
  96.         if (!QuestComplete)
  97.             throw new InvalidOperationException("Guybrush didn't find the treasure!");
  98.  
  99.         return BootyValue;
  100.     }
  101. }
  102.  
  103. // Reads the treasure map and interprets the pirate commands.
  104. public static class MapReader
  105. {
  106.     public static List<PirateCommand> ReadPirateCommands(string[] lines)
  107.     {
  108.         var pirateCommands = new List<PirateCommand>();
  109.  
  110.         foreach (string line in lines)
  111.         {
  112.             if (string.IsNullOrWhiteSpace(line))
  113.                 continue;
  114.  
  115.             PirateCommand command = ParseCommand(line);
  116.             pirateCommands.Add(command);
  117.         }
  118.  
  119.         return pirateCommands;
  120.     }
  121.  
  122.     private static PirateCommand ParseCommand(string line)
  123.     {
  124.         string[] parts = line.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries);
  125.         if (parts.Length == 0)
  126.             throw new InvalidOperationException("Empty pirate command!");
  127.  
  128.         string command = parts[0].ToLowerInvariant();
  129.         string[] args = parts.Length > 1 ? parts[1..] : Array.Empty<string>();
  130.  
  131.         return command switch
  132.         {
  133.             "push" => CreateHoistInstruction(args),
  134.             "add" => new PlunderInstruction(),
  135.             "jmpos" => CreateSetSailInstruction(args),
  136.             "ret" => new DockInstruction(),
  137.             _ => throw new InvalidOperationException($"Unknown pirate command: {line}")
  138.         };
  139.     }
  140.  
  141.     private static PirateCommand CreateHoistInstruction(string[] args)
  142.     {
  143.         if (args.Length != 1)
  144.             throw new InvalidOperationException("Invalid hoist instruction.");
  145.  
  146.         string valueStr = args[0].ToLowerInvariant();
  147.  
  148.         Func<IslandCoordinate, int> valueProvider = valueStr switch
  149.         {
  150.             "x" => coord => coord.X,
  151.             "y" => coord => coord.Y,
  152.             "z" => coord => coord.Z,
  153.             _ => int.TryParse(valueStr, out int intValue)
  154.                 ? _ => intValue
  155.                 : throw new InvalidOperationException($"Invalid hoist value: {valueStr}")
  156.         };
  157.  
  158.         return new HoistInstruction(valueProvider);
  159.     }
  160.  
  161.     private static PirateCommand CreateSetSailInstruction(string[] args)
  162.     {
  163.         if (args.Length != 1)
  164.             throw new InvalidOperationException("Invalid setsail instruction.");
  165.  
  166.         if (!int.TryParse(args[0], out int offset))
  167.             throw new InvalidOperationException($"Invalid setsail offset: {args[0]}");
  168.  
  169.         return new SetSailInstruction(offset);
  170.     }
  171. }
  172.  
  173. // Represents the treasure map (3D grid).
  174. public class TreasureMap
  175. {
  176.     private readonly int[,,] _data;
  177.     public int Width { get; }
  178.     public int Height { get; }
  179.     public int Depth { get; }
  180.  
  181.     public TreasureMap(int width, int height, int depth)
  182.     {
  183.         Width = width;
  184.         Height = height;
  185.         Depth = depth;
  186.         _data = new int[width, height, depth];
  187.     }
  188.  
  189.     public int this[int x, int y, int z]
  190.     {
  191.         get => _data[x, y, z];
  192.         set => _data[x, y, z] = value;
  193.     }
  194.  
  195.     public IEnumerable<IslandCoordinate> GetIslands()
  196.     {
  197.         for (int x = 0; x < Width; x++)
  198.             for (int y = 0; y < Height; y++)
  199.                 for (int z = 0; z < Depth; z++)
  200.                     yield return new IslandCoordinate(x, y, z);
  201.     }
  202. }
  203.  
  204. // Counts the number of ghost ships (clouds) on the map.
  205. public static class GhostShipCounter
  206. {
  207.     private static readonly (int dx, int dy, int dz)[] WindDirections = new[]
  208.     {
  209.         (-1, 0, 0), (1, 0, 0),
  210.         (0, -1, 0), (0, 1, 0),
  211.         (0, 0, -1), (0, 0, 1)
  212.     };
  213.  
  214.     public static int CountGhostShips(TreasureMap map)
  215.     {
  216.         int ghostShipCount = 0;
  217.         var visited = new bool[map.Width, map.Height, map.Depth];
  218.  
  219.         foreach (var coord in map.GetIslands())
  220.         {
  221.             if (map[coord.X, coord.Y, coord.Z] > 0 && !visited[coord.X, coord.Y, coord.Z])
  222.             {
  223.                 SailTheSevenSeas(map, visited, coord);
  224.                 ghostShipCount++;
  225.             }
  226.         }
  227.  
  228.         return ghostShipCount;
  229.     }
  230.  
  231.     private static void SailTheSevenSeas(TreasureMap map, bool[,,] visited, IslandCoordinate startCoord)
  232.     {
  233.         var stack = new Stack<IslandCoordinate>();
  234.         stack.Push(startCoord);
  235.         visited[startCoord.X, startCoord.Y, startCoord.Z] = true;
  236.  
  237.         while (stack.Count > 0)
  238.         {
  239.             var coord = stack.Pop();
  240.  
  241.             foreach (var (dx, dy, dz) in WindDirections)
  242.             {
  243.                 int nx = coord.X + dx;
  244.                 int ny = coord.Y + dy;
  245.                 int nz = coord.Z + dz;
  246.  
  247.                 if (nx >= 0 && nx < map.Width &&
  248.                     ny >= 0 && ny < map.Height &&
  249.                     nz >= 0 && nz < map.Depth &&
  250.                     map[nx, ny, nz] > 0 &&
  251.                     !visited[nx, ny, nz])
  252.                 {
  253.                     visited[nx, ny, nz] = true;
  254.                     stack.Push(new IslandCoordinate(nx, ny, nz));
  255.                 }
  256.             }
  257.         }
  258.     }
  259. }
  260.  
  261. // The ScummBar is where our adventure begins!
  262. public class ScummBar
  263. {
  264.     private const int IslandSize = 30;
  265.     private static List<PirateCommand> _pirateCommands;
  266.  
  267.     public static void Main(string[] args)
  268.     {
  269.         try
  270.         {
  271.             // Guybrush enters the Scumm Bar and finds a mysterious map.
  272.             Console.WriteLine("Ahoy! Welcome to Guybrush Threepwood's grand adventure!");
  273.  
  274.             // Read the pirate commands from the treasure map.
  275.             string[] lines = File.ReadAllLines("pirate_commands.txt");
  276.             _pirateCommands = MapReader.ReadPirateCommands(lines);
  277.  
  278.             // Chart the seas and find the treasure.
  279.             TreasureMap treasureMap = new(IslandSize, IslandSize, IslandSize);
  280.             long totalTreasure = ChartTheSeas(treasureMap);
  281.  
  282.             Console.WriteLine($"Total treasure collected: {totalTreasure} pieces of eight");
  283.  
  284.             // Count the number of ghost ships.
  285.             int ghostShipCount = GhostShipCounter.CountGhostShips(treasureMap);
  286.             Console.WriteLine($"Number of ghost ships spotted: {ghostShipCount}");
  287.  
  288.             Console.WriteLine("Ye've completed the quest! Time to celebrate at the Scumm Bar!");
  289.         }
  290.         catch (Exception ex)
  291.         {
  292.             Console.Error.WriteLine($"Curse ye scurvy code! Error: {ex.Message}");
  293.         }
  294.     }
  295.  
  296.     private static long ChartTheSeas(TreasureMap map)
  297.     {
  298.         long totalTreasure = 0;
  299.  
  300.         foreach (var coord in map.GetIslands())
  301.         {
  302.             int booty = EmbarkOnQuest(coord);
  303.             map[coord.X, coord.Y, coord.Z] = booty;
  304.             totalTreasure += booty;
  305.         }
  306.  
  307.         return totalTreasure;
  308.     }
  309.  
  310.     private static int EmbarkOnQuest(IslandCoordinate location)
  311.     {
  312.         var guybrush = new Guybrush(_pirateCommands, location);
  313.         return guybrush.EmbarkOnQuest();
  314.     }
  315. }
  316.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement