# Advent of Code 2022, Day 4 - Part Two

## Preface

In this part of the advent of code, we need to check if two ranges overlap at all. So we can take the code from our previous part and change a couple of lines.

Because the assignment is almost the same but with the only exception that we need to check how many ranges overlap at all compared to how many ranges overlap completely.

## Design

Let’s take a look at our design from the previous post.

1
2
3
4
5
6

fun isRangeInsideAnother(rangeA: Pair<Int, Int>, rangeB: Pair<Int, Int>): Boolean {
val isStartInsideRangeA = rangeB.first >= rangeA.first && rangeB.first <= rangeA.second
val isEndInsideRangeA = rangeB.second >= rangeA.first && rangeB.second <= rangeA.second
return isStartInsideRangeA && isEndInsideRangeA
}

In this method we check if the start of rangeB and the end of rangeB is inside rangeA. The keyword here is *and*. If we change the operation by checking if the start of rangeB is inside rangeA *or* if the end of rangeB is inside rangeA we get all the ranges that overlap at some point. So it’ll look like this.

1
2
3
4
5
6

fun doesRangeOverlap(rangeA: Pair<Int, Int>, rangeB: Pair<Int, Int>): Boolean {
val isStartInsideRangeA = rangeB.first >= rangeA.first && rangeB.first <= rangeA.second
val isEndInsideRangeA = rangeB.second >= rangeA.first && rangeB.second <= rangeA.second
return isStartInsideRangeA || isEndInsideRangeA
}

For this to work both ways, we need to call the above method twice in the order of `doesRangeOverlap(rangeA, rangeB)`

and `doesRangeOverlap(rangeB, rangeA)`

. And if we then `or`

the result, we get the expected behaviour.

## Implementation

### Business logic

Now we have an idea of our design, let’s start implementing it in our PartTwo class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

class PartTwo(
private val sanitizer: Sanitizer
) {
fun getResult(): Int {
val rangesThatOverlap = sanitizer
.getItems()
?.filter { // Step 1
doesRangeOverlap(it.first, it.second) ||
doesRangeOverlap(it.second, it.first)
}
?.count()
return rangesThatOverlap ?: -1
}
/***
* Check if rangeB overlaps somewehere with rangeA
*
* @param rangeA the range that is used to check rangeB against
* @param rangeB the range that is checked against rangeA
*/
private fun doesRangeOverlap(rangeA: Pair<Int, Int>, rangeB: Pair<Int, Int>): Boolean {
val isStartInsideRangeA = rangeB.first >= rangeA.first && rangeB.first <= rangeA.second
val isEndInsideRangeA = rangeB.second >= rangeA.first && rangeB.second <= rangeA.second
return isStartInsideRangeA || isEndInsideRangeA
}
}

At *Step 1* we filter the input elements based on the overlapping ranges. We do this by validating that rangeB overlaps with rangeA or if rangeA overlaps with rangeB.

### Test case

We have written our business logic, and for our test input we now that the expected number of overlapping ranges is **4**. So we can start setting up our test case.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

class PartTwoTest {
@Test
fun testGetResult() {
// Arrange
val resource = {}::class.java.getResource("/input.txt")
val sanitizer = Sanitizer(resource)
val sut = PartTwo(sanitizer)
val expectedNumberOfOverlappingPairs = 4
// Act
val result = sut.getResult()
// Assert
assertEquals(expectedNumberOfOverlappingPairs, result)
}
}