Day 2 of Advent of Code is here! Check out Day 1 for what this is all about.

Let’s do it!

But first, the site also provides a leaderboard, so I went and created one. I invite you to join my board, and we can see who can win it ;) Go to “Leaderboard” in the top nav and enter `1030369-e174b794` to join my board.

I have also loaded up the pure code on github, you can follow along there too: pretty pages or the repo.

I highly encourage you to get through the day’s challenge on your own. I would love to hear how you did though! Did you find a better approach than I did?

### Day 2: Passport Philsophy

#### Part I

We have a page with a long list of “passwords” with their “policies”.

The definition is as follows: “Each line gives the password policy and then the password. The password policy indicates the lowest and highest number of times a given letter must appear for the password to be valid. For example, `1-3 a` means that the password must contain `a` at least `1` time and at most `3` times.” ref

The challenge is to find how many of these passwords are correct.

I opened dev toolbar again, and start by grabbing all of the passwords from the page:

```var nums = window.document.getElementsByTagName("pre")[0]
nums = nums.innerText.split('\n')
```

Now `nums` is an array containing each row of the text.

I then grabbed one of the string values and created a quick regex to match the string pattern:

```var p = "5-11 t: glhbttzvzttkdx"
var a = p.match(/([0-9]*)-([0-9]*)\s(.):\s([a-zA-Z]*)/)
```

I could’ve went with splitting a string, but found regex is much more elegant, gets me everything I need in 1 swoop.

What is that regex doing?

• `([0-9]*)` matches the first number, before the `-`
• the `( )` group that value into it’s own value in the output, you’ll see below
• `-` signifies the dash in the string, I don’t need it, but need what comes around it
• `([0-9]*)` matches the second number, after the `-`
• `\s` is a space, like
• `(.)` is any letter
• `:\s` is the colon and space in the string
• `([a-zA-Z]*)` is the password string, any letter, lower or upper case

And the output looks like

```["5-11 t: glhbttzvzttkdx", "5", "11", "t", "glhbttzvzttkdx", index: 0, input: "5-11 t: glhbttzvzttkdx", groups: undefined]
```

As you can see, the match() function returns an array of objects. The first element is the entire string it matched, but then the next few are the specific values I wanted. In my regex, I wrapped the values I wanted in `( )` which groups that value and outputs it into unique params.

Let’s now apply some logic to determine if the password is correct. Let’s get the values we want out of the above array

```var min = Number(a[1])
var max = Number(a[2])
var letter = a[3]
var password = a[4]
```

Now the fun part, checking for the policy in the password:

```if(password.indexOf(letter) > -1) {
var regx = new RegExp(letter, 'ig')
var letterCount = password.match(regx)

if(letterCount.length >= min && letterCount.length <= max) {
counter++;
}
}
```

Here’s what we’re doing:

• Check if the letter even exists, if not, don’t bother doing anything else
• We then create a little regular expression to find the letter, the `ig` at the end indicates case-insensitive and globally, basically, find all references to it.
• Then we match the regex against the password, this returns an array of matches, which will be the count of occurrences of the letter.

Now we piece it all together and get a count!

```var counter = 0;
nums.forEach(pwd => {
var a = pwd.match(/([0-9]*)-([0-9]*)\s(.):\s([a-zA-Z]*)/)
if(a && a.length > 4) {
var min = Number(a[1])
var max = Number(a[2])
var letter = a[3]
var password = a[4]
if(password.indexOf(letter) > -1) {
var regx = new RegExp(letter, 'ig')
var letterCount = password.match(regx)

if(letterCount.length >= min && letterCount.length <= max) {
counter++;
}
}
} else {
console.error(pwd, 'not a valid password and policy')
}
});
console.log(counter, 'out of', nums.length, 'passwords are legit')
```

I had a pain point here, I forgot about the `g` in the regex, without that, it will only find the first instance of the letter, not all letters.

#### Part II

Ah, the password policy was wrong, well, poorly interpreted by the team. (requirements gathering is really important, understanding the requirements is even more important :D)

For part 2, the actual password policy is: “Each policy actually describes two positions in the password, where `1` means the first character, `2` means the second character, and so on. (Be careful; Toboggan Corporate Policies have no concept of “index zero”!) Exactly one of these positions must contain the given letter. Other occurrences of the letter are irrelevant for the purposes of policy enforcement.” ref

Let’s start with our previous function and update it for these new rules

```var counter = 0;
nums.forEach(pwd => {
var a = pwd.match(/([0-9]*)-([0-9]*)\s(.):\s([a-zA-Z]*)/)
if(a && a.length > 4) {
var min = Number(a[1]) - 1
var max = Number(a[2]) - 1
var letter = a[3]
var password = a[4]
var hasMin = password.substring(min, min+1) === letter
var hasMax = password.substring(max, max+1) === letter
if(hasMin !== hasMax) {
counter++;
}
} else {
console.error(pwd, 'not a valid password and policy')
}
});
console.log(counter, 'out of', nums.length, 'passwords are legit')
```

The big changes are right in the middle of the code set.

• Checking if the letter at the min and max location is the right letter, `hasMin` and `hasMax` would be true if the letter exists
• Then we do a check, if `hasMin` does not equal `hasMax`, then we have a valid password.
• Does that make sense? If `hasMin` is true, and `hasMax` is `true`, then this will fail since they don’t match each other. If they are both `false` then it’ll fail since they match. Only if one is `true` and one is `false` will it be valid, per the requirements

### How did you do?

How did you find the answer on your own? How did you do it? I’d love to hear how you did! Please comment below!

Series Navigation<< Advent of Code, Day 3Advent of Code, Day 1 >>