Advent Of Code: Day 1 & 2

Published

I discovered Advent of Code by accident when looking at a post on Robb Knight’s blog this morning. I figured, “hey, this could be fun,” so I’m going to share my progress. Even though I’m late

I’m going to use Python for this, in contrast with Robb’s PHP1. I’ve kinda forgotten how to use it, so it’s good practice in my book.

Day 1

Part 1

The challenge starts with giving you getting the first and last integer from a string. The Advent of Code site gives the following example:

1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet

Which result in 12, 38, 15, and 77. We then get the sum which is 142.

To reproduce this in Python, I’m going to start by making a fileinput.txt to store my input, then a script to convert this to a list, like this:

with open("input.txt", "r") as ff:
    strings = ff.read()

strings = strings.splitlines()

print(strings) # ['1abc2', 'pqr3stu8vwx', 'a1b2c3d4e5f', 'treb7uchet']

We also need to remove all non-numeric characters from our strings. For this, I’m going to use RegEx with the re module. Using the RegEx `` and re.findall(), we can remove anything that isn’t a number.

import re

with open("input.txt", "r") as ff:
    strings = ff.read()

regex = "[0-9\n]"
x = re.findall(regex, strings)
x = "".join(x)

x = x.splitlines()

print("Numbers:", x) # Numbers: ['12', '38', '12345', '7']

Note the \n in the RegEx. This preserves the newlines so we can still have our list. Then we concatenate the first and last characters of each string, then get our total using sum()

# Continuing from last codeblock
final = []

for number in x:
    final.append(int(number[0] + number[-1]))

print("Numbers:\t", final) # Numbers: [12, 38, 15, 77]
print("Total:\t\t", sum(final)) # Total: 142

Now we just have to change our input to the one given by Advent of Code, give them the total and…

That's the right answer! You are one gold star closer to restoring snow operations.

Neat. Let’s go onto part 2.

Part 2

In part 2, we’re told that the word forms of numbers (one, two, three, etc.) should also be valid. So, it’s time to break out good ol’ RegEx again. I’ll use this input for testing:

two1nine
eightwothree
abcone2threexyz
xtwone3four
4nineeightseven2
zoneight234
7pqrstsixteen

This should result in 281

I’m going to do a find-and-replace on the unmodified string so we don’t need to modify our original script. My first attempt was to run something like this before the regex:

replacements = [ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" ]

for word in replacements:
    index = replacements.index(word)
    strings = strings.replace(word, str(index))

print(strings)

Which resulted in this:

/usr/bin/python3.11 /mnt/code/adventofcode/2023/01/day1.py 
219
eigh23
abc123xyz
xtw134
49872
z1ight234
7pqrst6teen
Numbers:	 [29, 23, 13, 14, 42, 14, 76]
Total:	 211

Process finished with exit code 0

Hm. The total is wrong. Why is that? Let’s see what the set of numbers should be:

numbers = { 29, 83, 13, 24, 42, 14, 76 }

So the issue seems to lie with the line eightwothree. The words eight and two share a t, which is causing confusion. Eight should be the first number, but my code is registering Two instead. This is to do with my find and replace strategy. In my list of numbers, two comes before eight, so the t for eight gets eaten. So I modified my RegEx to include word numbers and put the replacement code after that.

regex = "[0-9\n]|zero|one|two|three|four|five|six|seven|eight|nine"
x = re.findall(regex, strings)
x = "".join(x)

replacements = [ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" ]

for word in replacements:
    index = replacements.index(word)
    x = x.replace(word, str(index))

x = x.splitlines()

This did indeed work. Putting the required input in and……..

That’s not the right answer; your answer is too low.

Aw nuts. Why is that? Notice my replacements list. It includes zero. But the AoC website clearly says:

one, two, three, four, five, six, seven, eight, and nine also count as valid “digits”.

Not zero. Removing that gives me the correct an—

your answer is too low.

What. We have another bug.

Looking at the output (it’s large so I won’t republish it here), I can see there’s something not right. Take a look at this:

Numbers = [79, 83, 33, 86, 71, 24, 15, 87, 91, 24, 69, 3, 49, ... ]

Note the 3 there. this is supposed to be a list of two-digit numbers. Why is it there? It’s actually because of the same bug as before. 0 isn’t considered a valid number. Removing it from my RegEx (making it /[1-9\n]) solves the puzzle.

At this point, I grew frustrated2, so I went looking for answers. Robb’s post links to Lewis’ post1, which has this RegEx:

(?=(\d|one|two|three|four|five|six|seven|eight|nine))

This worked, and I don’t know why.

Day 2

After that, I’m feeling tired. (And I’m busy.)

I’ll do Day 2 some other day. Please remind me to!!

Comments

Comment system is a WIP. Check back soon!