Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //Advent of Code 2020 Day 13 Parts 1 and 2 solution by Mike LeSauvage
- public class BusScheduleAnalyzer : MonoBehaviour
- {
- [SerializeField] TextAsset busScheduleTextfile = null; //Hooked up in the input text in the Unity editor.
- [SerializeField] long startTime = 100000000000000; //Chosen as the test guide says it will surely be a larger number than this. SURELY!
- //In practice, effect on calculation time in negligible. Probably included as a
- //warning of the need to use long vs int.
- void Start()
- {
- string[] busScheduleStrings = busScheduleTextfile.text.Split('\n');
- SolvePartOne(busScheduleStrings);
- SolvePartTwo(busScheduleStrings);
- }
- void SolvePartTwo(string[] busScheduleStrings)
- {
- List<(int busNum, int requiredDepartureOffset)> busDepartureInfo = new List<(int, int)>();
- string[] allBusNumbersAsStrings = busScheduleStrings[1].Split(',');
- //Fill out the list of bus numbers and their required arrival offsets. In format (busNumber, offset)
- for (int i = 0; i < allBusNumbersAsStrings.Length; i++)
- {
- try
- {
- busDepartureInfo.Add((int.Parse(allBusNumbersAsStrings[i]), i));
- }
- catch (FormatException)
- {
- //Nothing to do here!
- }
- }
- //Choose the initial start time by finding the nearest or greater departure time of the first bus as we did in part 1.
- startTime = GetEqualOrGreaterDepartureTime(startTime, busDepartureInfo[0].busNum);
- long incrementAmount = busDepartureInfo[0].busNum; //As each periodicity pairing is found, increase the increment.
- int lockedIn=0; //Keeps track of which bags have been matched to a periodicity with the group.
- // Solution approach
- //-------------------
- // For any two elements a and b that each have their own periodicty, when treated as a group they have periodicity a*b.
- // EG: one planet does a loop in 50 days, another in 70 days, if they line up at day=0 they'll line up again at 50*70 = 3500 days.
- // So, this approach is to find the match with the next bus, then change the periodicity by multiplying by that bus's loop time
- // Then, move on to add another bus to the match and repeat.
- for (long testTime=startTime; true; testTime+=incrementAmount)
- {
- int nextBusToLookFor = lockedIn + 1;
- long requiredDepartureTime = testTime + busDepartureInfo[nextBusToLookFor].requiredDepartureOffset;
- long nearestDepartureTime = GetEqualOrGreaterDepartureTime(requiredDepartureTime, busDepartureInfo[nextBusToLookFor].busNum);
- if(requiredDepartureTime == nearestDepartureTime)
- {
- incrementAmount *= busDepartureInfo[nextBusToLookFor].busNum;
- lockedIn = nextBusToLookFor;
- if (lockedIn == busDepartureInfo.Count - 1) //They're all lined up!
- {
- Debug.Log($"Part Two: Earliest departure is Bus ID {busDepartureInfo[0].busNum} on departure {testTime}");
- break;
- }
- }
- }
- }
- void SolvePartOne(string[] busScheduleStrings)
- {
- int targetDepartureTime = int.Parse(busScheduleStrings[0]);
- string[] allBusNumbersAsStrings = busScheduleStrings[1].Split(',');
- Dictionary<int, int> busDeparturesDict = new Dictionary<int, int>();
- //Fill the dictionary with the bus numbers.
- //Departure time is -1 until analyzed.
- foreach (string busNumString in allBusNumbersAsStrings)
- {
- try
- {
- int busNum = int.Parse(busNumString);
- busDeparturesDict.Add(busNum, -1);
- }
- catch (FormatException)
- {
- //Nothing to do here.
- }
- }
- List<int> busNumbers = new List<int>(busDeparturesDict.Keys); //Get a list of the dictionary keys as dictionaries cannot be modified in a foreach loop.
- //Fill out the dictionary of bus IDs with their departure times equal to or greater than the target (From line 0 of the file).
- foreach (int busNum in busNumbers)
- {
- busDeparturesDict[busNum] = (int)GetEqualOrGreaterDepartureTime(targetDepartureTime, busNum);
- }
- //Choose one bus departure time arbitrarily for seed of shortest time.
- int bestBus = busNumbers[0];
- foreach (int busNum in busNumbers)
- {
- if (busDeparturesDict[busNum] < busDeparturesDict[bestBus])
- {
- bestBus = busNum;
- }
- }
- int waitTime = busDeparturesDict[bestBus] - targetDepartureTime;
- int partOneSolution = waitTime * bestBus;
- Debug.Log($"Part One Best bus is {bestBus} departing at {busDeparturesDict[bestBus]}");
- Debug.Log($"Part One Time to wait is: {waitTime}");
- Debug.Log($"Part One Solution: {partOneSolution}");
- }
- long GetEqualOrGreaterDepartureTime(long targetDepartureTime, int busNum)
- {
- //Busses get around the loop in the time equal to their bus number.
- //All busses depart at t=0.
- //Find the time the bus is at the station greater than or equal to the target departure.
- //To find it:
- // 1) Find the number of cycles the bus runs in the target departure time.
- // 2) If there's a remainder, round up to the next highest number of cycles.
- // 3) Multiply the number of cycles by the bus' loop time to get the arrival that is >= the desired departure time.
- //
- // An earlier solution used Mathf.CeilToInt() but that approach failed when using long values (it would wrap to -ve numbers)
- // So this more manual solution was needed.
- long quotient = targetDepartureTime / busNum; // (1)
- long remainder = targetDepartureTime % busNum;
- if(remainder > 0)
- {
- quotient++; // (2)
- }
- long earliestDepartureTime = quotient * busNum; // (3)
- return earliestDepartureTime;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement