AdventOfCode/AdventOfCode.Solutions/2023/Day 05/Day05.cs
2023-12-05 22:49:41 +01:00

166 lines
7.3 KiB
C#

using AdventOfCode.Core;
namespace AdventOfCode.Solutions._2023
{
public class Day05(InputReader reader) : IChallange
{
private readonly InputReader _inputReader = reader;
public const string SeedSoil = "seed-to-soil map:";
public const string SoilFertilizer = "soil-to-fertilizer map:";
public const string FertilizerWater = "fertilizer-to-water map:";
public const string WaterLight = "water-to-light map:";
public const string LightTemperature = "light-to-temperature map:";
public const string TemperatureHumidity = "temperature-to-humidity map:";
public const string HumidityLocation = "humidity-to-location map:";
public async Task<string> GetSolutionPart1()
{
List<string> data = new(await _inputReader.ReadAsArrayString());
SeedLocationMapper[] seeds = data[0].Split(' ').Skip(1).Select(s => new SeedLocationMapper { Seed = long.Parse(s) }).ToArray();
// creating maps
int stringSeperator = data.IndexOf(SeedSoil) + 1;
List<InOutMapper> soil = MapData(data, stringSeperator, data.IndexOf(string.Empty, stringSeperator));
stringSeperator = data.IndexOf(SoilFertilizer) + 1;
List<InOutMapper> fertilizer = MapData(data, stringSeperator, data.IndexOf(string.Empty, stringSeperator));
stringSeperator = data.IndexOf(FertilizerWater) + 1;
List<InOutMapper> water = MapData(data, stringSeperator, data.IndexOf(string.Empty, stringSeperator));
stringSeperator = data.IndexOf(WaterLight) + 1;
List<InOutMapper> light = MapData(data, stringSeperator, data.IndexOf(string.Empty, stringSeperator));
stringSeperator = data.IndexOf(LightTemperature) + 1;
List<InOutMapper> temperature = MapData(data, stringSeperator, data.IndexOf(string.Empty, stringSeperator));
stringSeperator = data.IndexOf(TemperatureHumidity) + 1;
List<InOutMapper> humidity = MapData(data, stringSeperator, data.IndexOf(string.Empty, stringSeperator));
stringSeperator = data.IndexOf(HumidityLocation) + 1;
List<InOutMapper> location = MapData(data, stringSeperator, data.Count);
foreach (SeedLocationMapper seed in seeds)
{
seed.Soil = GetTargetLocation(soil, seed.Seed);
seed.Fertilizer = GetTargetLocation(fertilizer, seed.Soil);
seed.Water = GetTargetLocation(water, seed.Fertilizer);
seed.Light = GetTargetLocation(light, seed.Water);
seed.Temperature = GetTargetLocation(temperature, seed.Light);
seed.Humidity = GetTargetLocation(humidity, seed.Temperature);
seed.Location = GetTargetLocation(location, seed.Humidity);
}
return seeds.Min(seed => seed.Location).ToString();
}
public async Task<string> GetSolutionPart2()
{
List<string> data = new(await _inputReader.ReadAsArrayString());
int stringSeperator = data.IndexOf(SeedSoil) + 1;
List<InOutMapper> soil = MapData(data, stringSeperator, data.IndexOf(string.Empty, stringSeperator));
stringSeperator = data.IndexOf(SoilFertilizer) + 1;
List<InOutMapper> fertilizer = MapData(data, stringSeperator, data.IndexOf(string.Empty, stringSeperator));
stringSeperator = data.IndexOf(FertilizerWater) + 1;
List<InOutMapper> water = MapData(data, stringSeperator, data.IndexOf(string.Empty, stringSeperator));
stringSeperator = data.IndexOf(WaterLight) + 1;
List<InOutMapper> light = MapData(data, stringSeperator, data.IndexOf(string.Empty, stringSeperator));
stringSeperator = data.IndexOf(LightTemperature) + 1;
List<InOutMapper> temperature = MapData(data, stringSeperator, data.IndexOf(string.Empty, stringSeperator));
stringSeperator = data.IndexOf(TemperatureHumidity) + 1;
List<InOutMapper> humidity = MapData(data, stringSeperator, data.IndexOf(string.Empty, stringSeperator));
stringSeperator = data.IndexOf(HumidityLocation) + 1;
List<InOutMapper> location = MapData(data, stringSeperator, data.Count);
long[] seedData = data[0].Split(' ').Skip(1).Select(long.Parse).ToArray();
long lowestLocation = long.MaxValue;
List<long> proccessed = [];
for (int seedDataIndex = 0; seedDataIndex < seedData.Length; seedDataIndex += 2)
{
for (long seedLocaton = seedData[seedDataIndex]; seedLocaton < seedData[seedDataIndex] + seedData[seedDataIndex + 1]; seedLocaton++)
{
if (proccessed.Contains(seedLocaton))
continue;
long soilLocation = GetTargetLocation(soil, seedLocaton);
long fertilizerLocation = GetTargetLocation(fertilizer, soilLocation);
long waterLocation = GetTargetLocation(water, fertilizerLocation);
long lightLocation = GetTargetLocation(light, waterLocation);
long temperatureLocation = GetTargetLocation(temperature, lightLocation);
long humidityLocation = GetTargetLocation(humidity, temperatureLocation);
long locationLocation = GetTargetLocation(location, humidityLocation);
if (locationLocation < lowestLocation)
lowestLocation = locationLocation;
proccessed.Add(seedLocaton);
}
}
return lowestLocation.ToString();
}
private static List<InOutMapper> MapData(List<string> data, int startIndex, int endIndex)
{
return data
.Skip(startIndex)
.Take(endIndex - startIndex)
.Select(line => line
.Split(' ')
.Select(long.Parse)
.ToArray())
.Select(values =>
new InOutMapper {
DestinationStart = values[0],
SourceStart = values[1],
Range = values[2]
})
.ToList();
}
private static long GetTargetLocation(List<InOutMapper> mapping, long location)
{
InOutMapper? mapper = mapping.FirstOrDefault(mapping => mapping.Intersect(location));
return mapper != null ? location + mapper.Delta : location;
}
private class SeedLocationMapper
{
public long Seed { get; set; }
public long Soil { get; set; }
public long Fertilizer { get; set; }
public long Water { get; set; }
public long Light { get; set; }
public long Temperature { get; set; }
public long Humidity { get; set; }
public long Location { get; set; }
}
private class InOutMapper
{
public long SourceStart { get; set; }
public long DestinationStart { get; set; }
public long Range { get; set; }
public long Delta => DestinationStart - SourceStart;
public bool Intersect (long value) => value >= SourceStart && value < SourceStart + Range;
}
}
}