using System.Diagnostics; namespace MirageMaintenance; public class Program { public static async Task Main(string[] args) { if (args.Length is 0) { Console.WriteLine("Please provide a path to the input file."); return -1; } if (File.Exists(args[0]) is false) { Console.WriteLine("The provided file does not exist."); return -2; } var isPart2 = args.Length > 1 && args[1] == "part2"; var input = await File.ReadAllLinesAsync(args[0]); var stopwatch = new Stopwatch(); stopwatch.Start(); var result = OasisReport.Parse(input).CalculateSumOfNextValues(isPart2); stopwatch.Stop(); Console.WriteLine($"The sum of all next values is {result}. ({stopwatch.ElapsedMilliseconds}ms)"); return (int)result; } } /// /// Represents a report from the Oasis. /// /// The value histories. /// An instance of . public class OasisReport( List valueHistories ) { /// /// Gets the value histories. /// public List ValueHistories { get; init; } = valueHistories; /// /// Calculates the sum of all next values. /// /// if set to true will extrapolate next values backwards /// The sum of all next values. public long CalculateSumOfNextValues(bool backwards = false) => ValueHistories .Select(valueHistory => valueHistory.CalculateNextValue(backwards)) .Sum(); /// /// Parses the specified oasis report input. /// /// The oasis report input. /// An instance of . public static OasisReport Parse(string[] oasisReportInput) { var valueHistories = new List(); foreach (var line in oasisReportInput) { var values = line .Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) .Select(long.Parse) .ToList(); var valueHistory = new ValueHistory(values); valueHistories.Add(valueHistory); } return new OasisReport(valueHistories); } } /// /// Represents a value history. /// /// The values. /// An instance of . public class ValueHistory( List values ) { /// /// Gets the values. /// List Values { get; init; } = values; /// /// Calculates the differences between each value. /// /// The values. /// The differences between each value. public List CalculateDifferences(List values) => Enumerable .Range(0, values.Count - 1) .Select(i => values[i + 1] - values[i]) .ToList(); /// /// Calculates the history. /// /// The history. public List> CalculateHistory() { var allHistoricalValues = new List>(); var currentValues = Values; while ( allHistoricalValues.Count is 0 || allHistoricalValues.Last().Any(value => value is not 0) ) { var historicalValues = CalculateDifferences(currentValues); allHistoricalValues.Add(historicalValues); currentValues = historicalValues; } return allHistoricalValues; } /// /// Calculates the next value. /// /// if set to true will extrapolate next value backwards /// The next value. public long CalculateNextValue(bool backwards = false) { var historicalValues = CalculateHistory(); var values = historicalValues.Prepend(Values).Reverse().ToList(); if (backwards) { values.ForEach(value => value.Reverse()); } for (var i = 0; i < values.Count; i++) { var currentValues = values[i]; if (i is 0) { currentValues.Add(0); continue; } var previousValues = values[i - 1]; var extrapolatedValue = backwards ? currentValues.Last() - previousValues.Last() : currentValues.Last() + previousValues.Last(); currentValues.Add(extrapolatedValue); } return values.Last().Last(); } }