Day 5 - Sewing Seeds
link
TLDR
Problem
Solution
key parts
Was a fairly tricky one today, with some repetition, but the main problem with today's example was the complexity of it all. There was a whole bunch of instructions to read through and understand.
Sorry, I'm not going to explain it in too much depth (see the link above for the problem, for more details).
TL;DR
Had to take a bunch of mappings, and find a [seed] number within a range. Once you found that range you had to manipulate the number to find its destination to be planted.
Then had to go through various other mappings and do the same, to get the right soil fertilizer, the right water for the fertilizer, and the best location.
With the result being the lowest numbered location to plant the seed (or so I think was the storyline).
To see a more in-depth breakdown follow this link.
Solution Part 1
using System.IO;
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
string filePath = Path.Combine(".", "input.txt");
string[] data = File.ReadAllText(filePath).Split("\n\n"); // Separate chunks
// Seeds: 79 14 55 13
var seeds = data[0].Split(": ")[1].Split(" ").Select(long.Parse).ToList();
// Parse all the data sets (mappings)
var dataMappingSets = data[1..].Select(DataMappingSet.Parse).ToList();
Part1(seeds, dataMappingSets);
}
static void Part1(List<long> seeds, List<DataMappingSet> dataMappingSets)
{
var locations = seeds.Select(seed =>
{
long transformed = seed;
foreach (var set in dataMappingSets)
{
transformed = set.Transform(transformed);
}
return transformed;
}).ToList();
long min = locations.Min();
Console.WriteLine($"Part1: {min}");
}
}
// Each Chunk of Data (e.g Seed -> Soil, Fertilizer -> Water, etc)
record DataMappingSet(string Label, List<DataMapping> Records)
{
public static DataMappingSet Parse(string data)
{
var split = data.Split("\n");
return new DataMappingSet(split[0], split[1..].Select(DataMapping.Parse).ToList());
}
public override string ToString() => $"DMS ({Label}, \n{string.Join("\n", Records)})";
public long Transform(long source)
{
return Records.FirstOrDefault(mapping => mapping.IsInRange(source))?.Transform(source) ?? source;
}
}
public record DataMapping(long DestinationStart, long SourceStart, long RangeLength)
{
public bool IsInRange(long source) => source >= SourceStart && source < SourceStart + RangeLength;
public long Transform(long source) => source + (DestinationStart - SourceStart);
public static DataMapping Parse(string data)
{
// 50 98 2
var parts = data.Split(" ").Select(long.Parse).ToArray();
return new DataMapping(parts[0], parts[1], parts[2]);
}
}
Key Parts
DataMappingSet
record, this holds all the individual chunks of mappings, i.e the soil-to-seed, fertlizer-to-water mappings (puzzle input).DataMapping
record this is the individual mapping (each line within the mapping chunks).50 98 2
for example.Then for each seed, we're going to run a
Select
Linq method, which takes a function to be ran on each seed.
This function, will loop through all the mapping sets we've created (sections in input file), and kick off the BeginTransformation
method.
This is turn runs the next part.
- Using the IsInRange method, Find the first mapping where the source number is in Range; This method checks to see if the given
long
(number) is within the range provided.
So we know the source start
and we know how long the range
is. We can therefore check that the given long
is GREATER THAN the source start, and LESS THAN the (source start + range)
Example:
given number = 10
source start = 9
range = 10
therefore we can check that 9 is somewhere between 9 and 19, which it is.
- Once we know that the number is within the given range, we can run the Transform method on it. This method transforms the number from its previous section number to the next one, i.e. Seed -> Soil.
We need to calculate the offset of how many numbers we need to add to our source to get the correct destination.
Example:
Let's use the seeds-to-soil mappings example.
the given number [seed] is 79
destination [soil] start is 52
source [seed] start is 50
range length is 48
So we know 50 + 48 = 98, so we know 50 is in that range of numbers.
Now to find the offset, we do this by [seed] start - [soil] start giving us two.
Meaning our end mapping result from seed 79, is soil 81.
I hope this makes sense 😅
Next Step:
Now we have this value we continue to iterate through each of the other DataMappingSets
with our newly transformed number (81) and find the correctly mapped, fertilizer, water, light, temperature, humidity, and finally location.
Each time we hit the end of the DataSetMappings, we add the location value to a List<long>
, and then can simply call .Min()
on the list, giving us the smaller location.
Part 1 - COMPLETE 🙌