Advent of code: 2020 Day 02
Tags: adventofcode, python
Published: 2020-12-02 06:48:34

**SPOILER ALERT**
This is a post with my solutions and learnings from the puzzle. Don't continue reading if you haven't tried the puzzle on your own yet.

If you want to do the puzzle, visit [adventofcode.com](https://www.adventofcode.com).

My programming language of choice is `python` and all examples below are in python.

## Key learnings

* String handling

This puzzle teaches you to handle strings. They are handled differently in every programming language and it's valuable to get comfortable with them. I find that python makes it easy to work with strings, but in other languages it might require more getting used to. You are going to need string handling a lot during Advent of Code as the input file is most often a text-file.

## Puzzle part 1

The puzzle is to `count the number of valid passwords in your input according to a policy`. 

Example input:
```
1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc
```

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

### Parse input 
First step is to save the input in a local file and parse it in python:
```python
# Open the input file
inputfile = open('02.input', 'r')

# Parse lines 
data = [x.strip() for x in inputfile.readlines()]
```

### Solution 

```python
def part1(data):
    total = 0
    for x in data:
        span, letter, password = x.split()
        start, end = map(int, span.split('-'))

        count = password.count(letter[0])

        if start <= count <= end:
            total +=1
    return total

result = part1(data)
print("Result part 1: %d" % result)
```

## Part 2
The second part has the same input, `but the policy is changed`. 

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

### Solution 
```python
def part2(data):
    total = 0
    for x in data:
        span, letter, password = x.split()
        start, end = map(int, span.split('-'))

        password1 = password[start-1] == letter[0]
        password2 = password[end-1] == letter[0]
        
        # Count if either first or the other character is correct. (xor)
        if password1 != password2:
            total +=1
    return total
```

## Alternative solutions

### Functional style

Going for a more functional style can make the code a bit cleaner. E.g there are no mutable variables or loops in this case. Though it requires the programmer to be comfortable with `filter`, `map`, `reduce` functions and so on. 

```python
def validate(line):
  span, letter, password = x.split()
  start, end = map(int, span.split('-'))
  count = password.count(letter[0])
  return start <= count and count <= end

def part1(data):
  valid_passwords = filter(validate, data) 
  return len(valid_passwords)
```

### Regex 

Regex is a powerful tool to use instead of splitting the strings. In python I find it easier to split strings as I did above. But in some cases (or other languages) it can be helpful to use regex instead. Here is an example of how the validation function could look like:

```python
import re
def validate(line):
    start, end, letter, pw = re.search(r'(\d+)-(\d+) (\w): (\w+)', line).groups()
    return int(start) <= pw.count(letter) <= int(end)
```


## Python explanations

### Splitting strings
As all lines have the same format `1-3 a: password` I know that splitting on space them will always output an array with 3 elements. In python we can automatically destruct it:
```python
span, letter, password = x.split()

# Is same as:
output = x.split(' ')
span = output[0]
letter = output[1]
password = output[2]
```

### Parsing numbers
The map function takes two parameters; a transform-function and an array. By using `int` as transform-function it will transform the strings to an integer if it's parseable. 

```python
start, end = map(int, span.split('-'))

# Is same as:
a, b = span.split('-')
start = int(a)
end = int(b)
```

### Double comparisons
Python has a sweet feature to allow two comparisons in this way:
```python
if a <= b <= c:

# Same as
if a <= b and b <= c:   
```

### Counting occurrences

Python has a built-in function `count` on strings. It takes an string as parameter and it will return the number of occurrences of that string.

```python
s = 'aabbccaabb'
count = s.count('a')
# count: 4
```

### Character position in string

```python
s = 'aabcd'
index = 2
char = s[index]
# char: b 
```