Day 10: Hoof It

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

  • @[email protected]
    link
    fedilink
    2
    edit-2
    2 days ago

    C#

    using System.Diagnostics;
    using Common;
    
    namespace Day10;
    
    static class Program
    {
        static void Main()
        {
            var start = Stopwatch.GetTimestamp();
    
            var sampleInput = Input.ParseInput("sample.txt");
            var programInput = Input.ParseInput("input.txt");
    
            Console.WriteLine($"Part 1 sample: {Part1(sampleInput)}");
            Console.WriteLine($"Part 1 input: {Part1(programInput)}");
    
            Console.WriteLine($"Part 2 sample: {Part2(sampleInput)}");
            Console.WriteLine($"Part 2 input: {Part2(programInput)}");
    
            Console.WriteLine($"That took about {Stopwatch.GetElapsedTime(start)}");
        }
    
        static object Part1(Input i) => GetTrailheads(i)
            .Sum(th => CountTheNines(th, i, new HashSet<Point>(), false));
    
        static object Part2(Input i) => GetTrailheads(i)
            .Sum(th => CountTheNines(th, i, new HashSet<Point>(), true));
    
        static int CountTheNines(Point loc, Input i, ISet<Point> visited, bool allPaths)
        {
            if (!visited.Add(loc)) return 0;
            
            var result =
                (ElevationAt(loc, i) == 9) ? 1 :
                loc.GetCardinalMoves()
                    .Where(move => move.IsInBounds(i.Bounds.Row, i.Bounds.Col))
                    .Where(move => (ElevationAt(move, i) - ElevationAt(loc, i)) == 1)
                    .Where(move => !visited.Contains(move))
                    .Sum(move => CountTheNines(move, i, visited, allPaths));
            
            if(allPaths) visited.Remove(loc);
            
            return result;
        }
    
        static IEnumerable<Point> GetTrailheads(Input i) => Grid.EnumerateAllPoints(i.Bounds)
            .Where(loc => ElevationAt(loc, i) == 0);
    
        static int ElevationAt(Point p, Input i) => i.Map[p.Row][p.Col];
    }
    
    public class Input
    {
        public required Point Bounds { get; init; }
        public required int[][] Map { get; init; }
        
        public static Input ParseInput(string file)
        {
            using var reader = new StreamReader(file);
            var map = reader.EnumerateLines()
                .Select(l => l.Select(c => (int)(c - '0')).ToArray())
                .ToArray();
            var bounds = new Point(map.Length, map.Max(l => l.Length));
            return new Input()
            {
                Map = map,
                Bounds = bounds,
            };
        }
    }
    
    • @[email protected]
      link
      fedilink
      22 days ago

      Straightforward depth first search. I found that the only difference for part 2 was to remove the current location from the HashSet of visited locations when the recurive call finished so that it could be visited again in other unique paths.