this post was submitted on 18 Dec 2024
7 points (81.8% liked)

Advent Of Code

1006 readers
2 users here now

An unofficial home for the advent of code community on programming.dev!

Advent of Code is an annual Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language you like.

AoC 2024

Solution Threads

M T W T F S S
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25

Rules/Guidelines

Relevant Communities

Relevant Links

Credits

Icon base by Lorc under CC BY 3.0 with modifications to add a gradient

console.log('Hello World')

founded 2 years ago
MODERATORS
 

Day 18: Ram Run

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

you are viewing a single comment's thread
view the rest of the comments
[โ€“] [email protected] 2 points 1 month ago

C#

Part 1 was straight forward Dykstra with a cost of 1 for each move. Part 2 was a binary search from the number of corrupted bytes given to us for Part 1 (where we know a path can be found) to the total number of corrupted bytes.

using System.Collections.Immutable;
using System.Diagnostics;
using Common;

namespace Day18;

static class Program
{
    static void Main()
    {
        var start = Stopwatch.GetTimestamp();

        var sampleInput = ReceiveInput("sample.txt");
        var sampleBounds = new Point(7,7);
        
        var programInput = ReceiveInput("input.txt");
        var programBounds = new Point(71, 71);

        Console.WriteLine($"Part 1 sample: {Part1(sampleInput, 12, sampleBounds)}");
        Console.WriteLine($"Part 1 input: {Part1(programInput, 1024, programBounds)}");

        Console.WriteLine($"Part 2 sample: {Part2(sampleInput, 12, sampleBounds)}");
        Console.WriteLine($"Part 2 input: {Part2(programInput, 1024, programBounds)}");

        Console.WriteLine($"That took about {Stopwatch.GetElapsedTime(start)}");
    }

    static int Part1(ImmutableArray<Point> input, int num, Point bounds) => FindBestPath(
        new Point(0, 0),
        new Point(bounds.Row - 1, bounds.Col - 1),
        input.Take(num).ToImmutableHashSet(),
        bounds);

    static object Part2(ImmutableArray<Point> input, int num, Point bounds)
    {
        var start = num;
        var end = input.Length;
        
        while (start != end)
        {
            var check = (start + end) / 2;
            if (Part1(input, check, bounds) < 0) end = check;
            else start = check + 1;
        }

        var lastPoint = input[start - 1];
        return $"{lastPoint.Col},{lastPoint.Row}";
    }

    record struct State(Point Location, int Steps);

    static int FindBestPath(Point start, Point end, ISet<Point> corruptedBytes, Point bounds)
    {
        var seenStates = new Dictionary<Point, int>();

        var queue = new Queue<State>();
        queue.Enqueue(new State(start, 0));
        while (queue.TryDequeue(out var state))
        {
            if (state.Location == end) return state.Steps;
            
            if (seenStates.TryGetValue(state.Location, out var bestSteps))
            {
                if (state.Steps >= bestSteps) continue;
            }
            
            seenStates[state.Location] = state.Steps;
            queue.EnqueueRange(state.Location.GetCardinalMoves()
                .Where(p => p.IsInBounds(bounds) && !corruptedBytes.Contains(p))
                .Select(p => new State(p, state.Steps + 1)));
        }

        return -1;
    }

    static ImmutableArray<Point> ReceiveInput(string file) => File.ReadAllLines(file)
        .Select(l => l.Split(','))
        .Select(p => new Point(int.Parse(p[1]), int.Parse(p[0])))
        .ToImmutableArray();
}