How to solve Advent of Code 2022 – Day 4 with Python

If you missed any previous days, click here for all my content about that: Advent of Code, if you want to know why you should participate and try to code the solution for yourself, click here: Advent Of Code 2022 – 7 Reasons why you should participate. If you’re here to see the solution of Day 4, continue reading 😉

GitHub Repository

https://github.com/GalaxyInfernoCodes/Advent_Of_Code_2022

I will upload all of my solutions there – in the form of Python (or Scala alternatives) notebooks. You have to use your own input for the “input.txt” since everyone gets their own and everyone needs to provide a different solution based on their input.

Day 4 Puzzle

On day 4 of Advent of Code, we had to find overlapping ranges in pairs of cleaning assignments to prevent the elves from doing the same task twice. For that we get pairs of ranges such as this (with both ends included in the range):

2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8

As always, I read in all lines:

with open('input.txt', 'r') as f:
    lines = f.readlines()
    assignment_pairs = [entry.strip() for entry in lines]

Part 1

For part 1, we should find ranges that completely envelop the other range on the same line.

First, the processing of the input lines is a bit more complex than the previous days. I’ve used the string-splitting function twice: first splitting on the comma, then splitting each half at the '-'. To compare numbers, we first need to convert the string parts into integers.

Afterwards we can check if one range is completely within the other by checking both the start and end value and simply count those cases.

def is_range_a_in_range_b(range_a, range_b):
    start_a, end_a = map(int, range_a.split('-'))
    start_b, end_b = map(int, range_b.split('-'))
    return start_b <= start_a and end_a <= end_b

number_of_contains = 0
for assignment_pair in assignment_pairs:
    first_range, second_range = assignment_pair.split(',')
    if is_range_a_in_range_b(first_range, second_range) or is_range_a_in_range_b(second_range, first_range):
        number_of_contains += 1
number_of_contains    

Part 2

In part 2, the elves decided that they not only care about ranges containing whole other ranges, but instead they care about every single overlap, even if just one number overlaps between the two assignments.

So here I check for 4 cases, either the start or end of the first assignment is within the second assignment or the other way around.

number_of_overlap = 0
for assignment_pair in assignment_pairs:
    first_range, second_range = assignment_pair.split(',')
    start_a, end_a = map(int, first_range.split('-'))
    start_b, end_b = map(int, second_range.split('-'))
    if start_a in range(start_b, end_b+1) or end_a in range(start_b, end_b+1) or  start_b in range(start_a, end_a+1) or end_b in range(start_a, end_a+1):
        number_of_overlap += 1
number_of_overlap    

Conclusion

A lot of number comparisons… Which are not as readable as function calls with describing names. That’s partly, why I went for a range comparison in part 2. That, however, has the disadvantage that python range does not include the upper bound unlike the specified puzzle input, so I had to add one to each end. Again, not very clean in my opinion :/

1 comment

  1. So I’ve recently finished this puzzle. I liked your solution for part 1, and I’ve altered the problem for part 2. I agree with the over usage of comparisons. So I shrunk it down a bit. If your interested, here’s the code I wrote for it. Please take any coding mistakes with a grain of salt. I’m self-taught and looking to get better in Python.

    with open(‘sections.txt’) as file:
    lines = file.readlines()
    sections = [entry.strip() for entry in lines]

    def range_finder(range_a, range_b):
    start_a, end_a = map(int, range_a.split(‘-‘))
    start_b, end_b = map(int, range_b.split(‘-‘))

    return start_a in range(start_b, end_b + 1) or end_a in range(start_b, end_b + 1)

    def check_sections(section):
    number_of_overlap = 0
    for ranges in section:
    range_a, range_b = ranges.split(‘,’)

    if range_finder(range_a, range_b) or range_finder(range_b, range_a):
    number_of_overlap += 1

    print(number_of_overlap)

    check_sections(sections)

    I like to use custom functions when ever I can bring down the typing amount. I also tried a intervals reverse, but couldn’t wrap my head around it at the time. Though now that I’ve gotten this far, I might attempt it again.

Leave a Reply

Consent Management Platform by Real Cookie Banner