Idiomatic Kotlin: Solving Advent of Code Puzzles, Day 2
Tags: kotlin, adventofcode, codenewbie, 100daysofcode
Published: 2021-07-21 16:25:30

## Idiomatic Kotlin: Solving Advent of Code Puzzles, Day 2

Let’s [continue](https://dev.to/kotlin/solving-advent-of-code-puzzles-in-idiomatic-kotlin-1m62) learning how to write idiomatic Kotlin code by solving the [AdventOfCode](https://adventofcode.com/) tasks! Today, we’re discussing the solution for the day 2 task.

{% youtube MyvJ7G6aErQ %}

## Day 2. Password philosophy

We need to confirm that passwords meet the corporate policy. Find the full task description at [https://adventofcode.com/2020/day/2](https://adventofcode.com/2020/day/2)*.

First, we need to read the input:


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


Each line contains the password policy and the password. Our task is to check that the password is valid and conforms to the given policy. The policies are different in the first and the second parts of the task.

In the first part, 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 once and at most 3 times. In the example, two passwords, the first and the third ones, are valid. The first contains one `a`, and the third contains nine `c`s, both within the limits of their respective policies. The second password, `cdefg`, is invalid, as it contains no instances of `b` but needs at least 1.

In the second part, the policy describes two positions in the password, where 1 means the first character, 2 means the second character, and so on (indexing starts at 1, not 0). Exactly one of these positions must contain the given letter. Other occurrences of the letter are irrelevant. Given the same example list from above:



1. `1-3 a: abcde` is valid: position 1 contains `a` and position 3 does not.
2. `1-3 b: cdefg` is invalid: neither position 1 nor position 3 contains `b`.
3. `2-9 c: ccccccccc` is invalid: both positions 2 and position 9 contain `c`.

We should count the number of passwords from the given input that are valid according to the interpretations of the policies.

As usual, if you haven’t done it, please solve the task yourself first. Here’s how you can [set up Kotlin](https://blog.jetbrains.com/kotlin/2021/07/advent-of-code-in-idiomatic-kotlin/#how-to-solve) for this purpose.


## Solution

First, we should read and parse the input. Let’s create a `data` class for storing a given password together with its policy:


```kotlin
data class PasswordWithPolicy(
   val password: String,
   val range: IntRange,
   val letter: Char
)
```


Each policy specifies an integer range and a letter that we store in the `IntRange` and `Char` types, accordingly. The modifier `data` instructs the compiler to generate some useful methods for this class, including the constructor, `equals`, `hashCode`, and `toString`.


### Parsing input

Let’s write a function that parses one input line into this class. Since it’s a function that creates an instance, let’s put it into a companion object in our data class. Then we can call it by the class name: `PasswordWithPolicy.parse()`.


```kotlin
data class PasswordWithPolicy(...) {
   companion object {
       fun parse(line: String): PasswordWithPolicy { 
           TODO()
       }
   }
}
```


While developing, you can put the `TODO()` call that throws the `NotImplementedError `exception. Because it returns the `Nothing` type, which is a subtype of any other type, the compiler won’t complain. The function is supposed to return `PasswordWithPolicy`, but throwing an exception inside is totally valid from the compiler’s point of view.

There are two ways to parse the input: by using utility functions on Strings or by using regular expressions. Let’s discuss both of these ways.

The Kotlin standard library contains many useful functions on `String`s, including `substringAfter()` and `substringBefore()` which perfectly solve the task in our case:


```kotlin
// 1-3 a: abcde
fun parse(line: String) = PasswordWithPolicy(
   password = line.substringAfter(": "),
   letter = line.substringAfter(" ").substringBefore(":").single(),
   range = line.substringBefore(" ").let {
       val (start, end) = it.split("-")
       start.toInt()..end.toInt()
   },
)
```


We provide the parameter names explicitly while calling the `PasswordWithPolicy` constructor. The input format convention requires that: 



* `password` be the string that goes right after the colon
* the letter go between the whitespace and the colon, and
* the range go before the whitespace and consist of two numbers split by “-”

To build a range, we first take the substring before the whitespace and split it with the “-” delimiter. We then use only the first two parts (`start` and `end`), and build a range using the “..” operator converting both lines to `Int`s. We use `let` to convert the result of `substringBefore()` to the desired range.

In this code, we assume that all the input lines follow the rules. In a real-world scenario, we should check that the input is correct. `substringAfter()` and similar functions take a second argument default to the string itself that should be returned in the event the given delimiter is not found. `toInt()` and `single()` have `toIntOrNull()` and `singleOrNull()` counterparts returning `null` if the string can’t be converted to an integer number or consists of more than one character.

Let’s now implement the same logic using regular expressions. Here is a regular expression describing the input format:


```
(\d+)-(\d+) ([a-z]): ([a-z]+)
```


First are two numbers split by -, then a letter and a password.

Our new `parse` function matches the line against a regular expression and then builds `PasswordWithPolicy` on the result:


```kotlin
private val regex = Regex("""(\d+)-(\d+) ([a-z]): ([a-z]+)""")
fun parseUsingRegex(line: String): PasswordWithPolicy =
   regex.matchEntire(line)!!
       .destructured
       .let { (start, end, letter, password) ->
           PasswordWithPolicy(password, start.toInt()..end.toInt(), letter.single())
       }
```


In Kotlin, you use the `Regex` class to define a regular expression. Note how we put it inside a triple-quoted string, so you don’t need to escape “`\`”. For regular strings, escaping is done in the conventional way, with a backslash, so if you need a backslash character in the string, you repeat it: `"(\\d+)-(\\d+)".`

We assume that our input is correct, which is why we use “`!!`” to throw an NPE if the input doesn’t correspond to the regular expression. An alternative is to use the safe access “`?.`” here and return `null` as the result.

The `destructured` property provides components for a destructuring assignment for groups defined in the regular expression. We use its result together with `let` and destruct it inside the lambda expression, defining `start`, `end`, `letter`, and `password` as parameters. As before, we need to convert strings to `Int`s and `Char`.


### Password validation

After we read the input, we need to validate whether the passwords comply with the given policy.

In the first part, we need to ensure that the number of occurrences of a given letter is in a range. It’s one line in Kotlin:


```kotlin
data class PasswordWithPolicy(
   val password: String,
   val range: IntRange,
   val letter: Char
) {
   fun validatePartOne() =
       password.count { it == letter } in range
       ... 
}
```


We count the occurrences of `letter` in the `password` string, and check that the result is in `range`. `in` checks that the given element belongs to a range. For numbers and other comparable elements, `x in range` is the same as writing explicitly `range.first &lt;= x && x &lt;= range.last`.

The second part isn’t difficult. We need to check that exactly one of the positions (stored in the range) contains the given letter. We use the boolean `xor` operator for that, which returns `true` if the operands are different. That’s exactly what we need here:


```kotlin
fun validatePartTwo() =
   (password[range.first - 1] == letter) xor (password[range.last - 1] == letter)
```


We need to subtract 1 from `first` and `last` because they imply indexing from one, but string indexation starts from zero.

Added all together, this gives us our `main` function that finds the result for both parts:


```kotlin
fun main() {
   val passwords = File("src/day2/input.txt")
       .readLines()
       .map(PasswordWithPolicy::parse)
   println(passwords.count { it.validatePartOne() })
   println(passwords.count { it.validatePartTwo() })
}
```


Note how we pass a member reference `PasswordWithPolicy::parse` to the `map` function to convert the strings to passwords.

That’s it! We discussed how to solve this problem, and along the way, looked at string utility functions, regular expressions, operations on collections, and how `let` helps transform the expression nicely to the form you need.

Please let us know if you find this format useful and would like us to provide solutions for more difficult tasks!

---

*Used with the permission of [Advent of Code](https://adventofcode.com/) ([Eric Wastl](https://twitter.com/ericwastl)).