Advent of Code 2017: Day 01: Part 01

Because Christmas should be a time of PowerShell and debugging rather than this “joy” thing…

Words: 826

Time to read: ~ 4 minutes

So we have our Pester test but I never actually said what we are writing the code for, did I?

Well, taking the main points straight from the website itself, we are required to…

[…] review a sequence of digits (your puzzle input) and find the sum of all digits that match the next digit in the list. The list is circular, so the digit after the last digit is the first digit in the list.

In case that was in anyways confusing, which it can be since it’s basically just a description of the problem, they even provide samples.

  • 1122 produces a sum of 3 (1 + 2) because the first digit (1) matches the second digit and the third digit (2) matches the fourth digit.
  • 1111 produces 4 because each digit (all 1) matches the next.
  • 1234 produces 0 because no digit matches the next.
  • 91212129 produces 9 because the only digit that matches the next one is the last digit, 9.

These are what we’ve used to create our Pester test.

Now comes the fun bit; creating our function to pass our Pester test!

Yes, I said “fun”

Let’s ask ourselves what we know.

Problem Description

  1. We have a sequence of digits.
  2. We have to compare one digit with the next digit.
  3. We have to compare the first digit with the last digit.

Pester Assumption

  1. We have a function called “Get-AOCDay01Part01”
  2. It has a parameter called “InputObject” that can take in our sequence.
  3. We compare the result only i.e. not `$Result.Sum` so we spit out the result only.

Objective 1.

First things first, we have to figure our a way to take our input and split it out into the individual numbers.

Easy enough since we know that there exists in PowerShell a `split` operator which can split a string apart based on a delimiter, defaulting to whitespace.

Is there a delimiter that we can use for our numbers though? There’s no comma or semi-colon between each number that we can split on. In fact, there’s nothing!

Hmmm…let’s see if we can split on nothing

SplittingOnNothing
It actually works!

Only problem appears to be that it creates a blank space before and after the digits, which makes sense when you think about it. We’re splitting the digits based on the nothing between them, it’s only our assumptions that they start and end with digits.

Maybe they also start and end with nothing? It’s simple enough to remove them anyway…

SplittingRemovingNothing
That seems to cut it!

Great! We’ve completed objective 1 – creating a sequence of digits.

Let’s move onto the next objective.

Objective 2.

Can we compare one digit against the next digit?

This one is simple enough. Since we’ve been able to split our input into a sequence of digits and we want to do something to each digit, it’s only right that we use ForEach-Object.

We can then

  1. input a number,
  2. check it against the previous number,
    1. If it matches, then we add it on.
    2. If it doesn’t match, we don’t add it on.
  3. Mark that number as the “previous”
  4. Wash, rinse, and repeat.

Simples!

If you’re asking what happens with the first number then I know that you’re paying attention. We’re casting our variables as [int], so at the start they have an initial placeholder of $null.

As you can see from the below screenshot, $null becomes 0. I find this okay because I looked ahead and saw that 0 + 0 = 0 😉

 

ProcessBlock
With some examples just to show

Now that we have this, we can just change it slightly so that if they match, we add them to a variable (let’s call it $Sum) and, if they don’t, we just move onto the next one…

FinalProcessBlock
$Sum += works because we cast to [int]
Objective 2 complete!

Objective 3.

Objective 3 is potentially a bit trickier, given that we have to compare the first digit against the last digit.

Or, at least, it would be if we hadn’t already looked at the ForEach-Object and seen that it’s not the just -Process block but the -Begin, -Process, and -End blocks. Well the same is true for functions, mainly they too have a -Begin, -Process, and -End blocks.

So we can use the -Begin blocks to figure out the first and last digits and the -End block to check if they match!

BeginBlock
Nice little array trick to get the last one too
EndBlock
Why are we finally calling $Sum? Well we have to output something, right?

With that our objective 3 should be complete.

All together! Right now! Over me!

Now that we have the individual bits all set up and correct, all that is left to do is to turn them into a single solid function.

Looking back over our Pester Assumptions, we better call our parameter InputObject otherwise Pester is going to throw a tantrum!


function Get-AOCDay01Part01 {
[CmdletBinding()]
param (
[string]$InputObject
)
begin {
#Initialize a holding variable
[int]$Sum = $null
#Split the input
$Digits = (($PuzzleNumber -split '') -ne '')
# First number
[int]$StartNumber = $Digits[0]
# Last number (yeah, -1 means the last!)
[int]$EndNumber = $Digits[-1]
}
process {
$Digits | ForEach-Object {
$CurrentNumber = $PSItem
# It they match, we add them
if ($CurrentNumber -eq $PreviousNumber)
{
$Sum += $CurrentNumber
}
$PreviousNumber = $CurrentNumber
}
}
end {
# Finally, check if we add the first number if it matches the last ("The list is circular")
if ($StartNumber -eq $EndNumber)
{
[int]$Sum += $StartNumber
}
$Sum
}
}

Function done and complete, we can go back and re-run our Pester tests to ensure that they pass all the TestCases that we gave them!

PesterTestsPassing.PNG
WOOHOO!

HAHA! Now ain’t that a sense of achievement 🙂 Let’s see what the next day brings!

 

 

 

Author: Shane O'Neill

DBA, T-SQL and PowerShell admirer, Food, Coffee, Whiskey (not necessarily in that order)...

Leave a Reply

%d bloggers like this: