Advent of Code 2023: Day 6 - Wait For It
Tags: programming, adventofcode, csharp
Published: 2023-12-06 23:00:42

## Day 6: Wait For It

I have enjoyed doing this challenge immensely. It's been a lot of fun, predominantly because the instructions and requirements were so easy to follow, unlike some previous days.

**Table of Contents**
[Link to Challenge](https://adventofcode.com/2023/day/6)
[TLDR](#tldr)
[Solution](#solution)
   [Breakdown of Code Part 1](#breakdown-of-code)
   [Part 2 Breakdown of Code Part 2](#part-2)

## TLDR

You're given a time and distance to beat.
 
You can inform your boat to increase its speed for the race by making it wait to increase the speed at the beginning of the race (but this costs you time). 

Once you've reached your preferred speed for the race (from boost), you have the remaining time to get as far as you can to beat the distance (world record). 

You are required to calculate the number of combinations of boost time/race time, in which you can beat the world record. 

## Solution

This was a straight brute force on the combinations, no real clever maths equations, (I'm not that good at Maths).

```csharp
using System.Text.RegularExpressions;

string[] data = File.ReadAllText("./puzzle.txt").Split("\n");
List<Boat> boats = Boat.ParseMultipleBoats(data);
Boat boat = Boat.ParseBoat(data);

long Part1() => boats
  .Select(boat => boat.FindPossibilities())
  .Aggregate((x, y) => x * y);

long Part2() => boat.FindPossibilities();


Console.WriteLine($"Part 1: {Part1()}");
Console.WriteLine($"Part 2: {Part2()}");


record Boat(long Time, long Distance)
{
  bool CanBeat(long boost)
  {
    var timeRemaining = Time - boost;
    return (timeRemaining * boost) > Distance;
  }

  public long FindPossibilities() =>
    Enumerable.Range(1, (int)Distance)
      .Where(x => CanBeat(x) == true)
      .Count();

  public static Boat ParseBoat(string[] lines)
  {
    string time = "";
    string distance = "";
    if (lines.Length >= 2)
    {

      string times = lines[0].Trim();
      string distances = lines[1].Trim();

      time = string.Join("", Regex
             .Matches(times.Trim(), @"\d+")
             .Select(match => match.Value)
           );

      distance = string.Join("", Regex
              .Matches(distances.Trim(), @"\d+")
              .Select(match => match.Value)
            );
    }
    return new Boat(long.Parse(time), long.Parse(distance));
  }

  public static List<Boat> ParseMultipleBoats(string[] lines)
  {
    List<Boat> boats = new();
    if (lines.Length >= 2)
    {
      string[] times = lines[0].Split(' ', StringSplitOptions.RemoveEmptyEntries);
      string[] distance = lines[1].Split(' ', StringSplitOptions.RemoveEmptyEntries);

      for (int i = 1; i < times.Length; i++)
      {
        boats.Add(new Boat(long.Parse(times[i]), long.Parse(distance[i])));
      }
    }
    return boats;
  }
}
```

### Breakdown of Code

**Part 1 **

**Boat** object - this is the record which will store our methods, and details (time, distance). 

We parse the lines of the text file (luckily for us there wasn't too much today oddly). Into boats, and store their time and distance for each one, using the `ParseBoats` method. 

We also do this for the `ParseBoat` method, to get the single boat (Part 2), we'll get to that later. 

**FindPossibilities** - is the brute force element of the solution. 

Let's break this down further:

```csharp
public long FindPossibilities() =>
    Enumerable.Range(1, (int)Distance)
      .Where(x => CanBeat(x) == true)
      .Count();
```

1. Create a range of numbers from 1 (we discount 0 as we've been told in the instructions that 0 means no speed/distance is covered) to Distance. 

**Example**
1...5 => 1,2,3,4,5

2. We filter out the numbers that `CanBeat` the distance the boat set for the World Record. We do this using the CanBeat Function
   `CanBeat` - this method simply applies some Math in order to work out if the time remaining * the speed the boat has accrued from waiting boost, is GREATER THAN the World Record distance. 

3. We count the number of entries from the range, that were returned true from _CanBeat_.


Then all we have to do is run an `Aggregate` extension function on the count for each boat.

### What is the Aggregate function?

It's a method that iteratively applies a specified function to the elements of a list, accumulating a result. You can also provide a starting value, which can be added to the first value. If you do not provide a starting point, the first two values are ran against the lambda function and this forms the accumulator value. 

It takes a lambda function, combining elements and the accumulated result. 

Example:

```csharp

var numbers = [1,2,3,4];

var output = numbers.Aggregate((x,y) => x + y);
//Output = 10
```
1st Iteration x = 1, y = 2 , x + y = 3
2nd Iteration x = 3, y = 3, x + y = 6
3rd Iteration x = 6, y = 4, x + y = 10

Result = 10

**Solved** - That's Part 1


### Part 2 

This is the same as Part 1 - however now the 3 columns for th initial part, have all been combined to make 1 large time and distance, meaning the combination total is a lot bigger. 

However now, we only need to know the answer of this combination count. Therefore there wasn't much to change to our brute force solution. 

Simply a case of parsing the 2 lines of text as 1 boat rather than multiple boats, and running it through our pre-existing flow, removing the need to aggregate the counts.

Solved - Part 2