Grant Riordan

Posted on

# Advent of Code 2023: Day 5 - Seeds

## Day 5 - Sewing Seeds

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).

## 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

1. `DataMappingSet` record, this holds all the individual chunks of mappings, i.e the soil-to-seed, fertlizer-to-water mappings (puzzle input).

2. `DataMapping` record this is the individual mapping (each line within the mapping chunks). `50 98 2` for example.

3. 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.

1. 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.

1. 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 ðŸ™Œ