Advent of Code 2024 – Day 03 – Mull it Over

This was so much easier than yesterday, since I wasn’t splitting my focus between trying to be clever and trying to write shitty code.

Day 03’s problem involved digging through a block of “corrupted code” to pull out important and usable data.  I ended up forcing myself to use the logical method here, and built a Regex string.  Despite that I write a lot of simple scripts to process and convert data for automation, I don’t really use Regex ever.  It’s been something I keep telling myself to do and use and learn better.  A lot of these challenges are actually greatly helped if you use Regex searches.

So that’s what I did.

I found this online Regex builder/tester, stuck the sample code into it, and went to work until I got what I intended out of it.  I learned two things. 

  • Adding a * to “find a digit of any size” only sometimes works, and in this case, using “+” was better.   
  • You can search on multiple strings using a pipe ( | )

Once I had the Regex working and I extracted all of the valid “mul(###,###)” instances, I used a second Regex search, mostly for practice, to extract the digits from each.

Then part two added an on off trigger.  Which was fairly simple to add in, except that I left my first Regex statement in the code, for posterity, but forgot to actually use the new one, so I was getting the same answer twice.

Anyway, here is the code.

import re
# https://www.w3schools.com/python/python_regex.asp
# https://regex101.com/

with open("Day03Input.txt") as file:
    data = file.read()

rxstring = "mul\(\d+,\d+\)"
rxstring2 = "mul\(\d+,\d+\)|do\(\)|don't\(\)"
total = 0
total2 = 0
enabler = True

def multiplier(a,b):
   return int(a)*int(b)

valid = re.findall(rxstring2,data)

for each in valid:
#   print(each)
   if "don't()" in each:
     enabler = False
   elif "do()" in each:
     enabler = True
   else:
     digits = re.findall('\d+',each)
     value = multiplier(digits[0],digits[1])
     total += value
     if enabler:
       total2 += value

print(total)
print(total2)

#Part1 - 179571322
#Part2 - 103811193

Advent of Code 2024 – Day 02 – Red-Nosed Reports

This entire Post is one big code block, because I did a stupid thing that felt like a good idea at the time.

#Lets comment the heck out of this one and flow with the process.  So it may look a little ugly.

# I am essentially just... blogging in real time, in the comments now....

#Until the end, I am using the sample data set
# 7 6 4 2 1
# 1 2 7 8 9
# 9 7 6 2 1
# 1 3 2 4 5
# 8 6 4 4 1
# 1 3 6 7 9

# I started by copying Day01, then modifying the top lines to read my Day02Input.txt file, because, lazy.
# Then just deleting everything else below the set processing, because none of it is real useful.
with open("Day02Input.txt") as file:
    data = file.read()

sets = [each.split(" ") for each in data.split("\n")]

# Then I want to test it so I add a print of the result, just to make sure it looks right against the sample data set. 
##### NOTE Removed code will just be commented out, to follow the comments.  I'll mark these as ##
# Tehre will be a lot of prints removed.  These are used gratuitously to verify things are working.

##print(sets)

# This gives
# [['7', '6', '4', '2', '1'], ['1', '2', '7', '8', '9'], ['9', '7', '6', '2', '1'], ['1', '3', '2', '4', '5'], ['8', '6', '4', '4', '1'], ['1', '3', '6', '7', '9'], ['']]
# For some reason I keep getting black sets on these, so I'm just gonna do like day one and clip it.
sets.pop()

##print(sets)

# Part of the test on this one is if the digits are ascending or descending, I have an idea to test this out quickly
# Lets see if it works.

##for each in sets:
##   print(each)
##   if each == each.sort():
##      print("Ascending")
##   print(each.sort())
# Ok, I ran into a prolem here, because it's reading everything in as strings and not integers.

# There is probably a more elegant way to do this but this will work.
int_sets = []

for each in sets:
   int_sets.append(list(map(int, each)))

## print(int_sets)

# [[7, 6, 4, 2, 1], [1, 2, 7, 8, 9], [9, 7, 6, 2, 1], [1, 3, 2, 4, 5], [8, 6, 4, 4, 1], [1, 3, 6, 7, 9]]
# Perfect, let's try again.
# Also it looks like I needed to use a different sort, for reasons.
# https://stackoverflow.com/questions/403421/how-do-i-sort-a-list-of-objects-based-on-an-attribute-of-the-objects

##for each in int_sets:
##   if each == sorted(each):
##      print("Ascending")
##   else:
##      print("Bad")

# Bad
# Ascending
# Bad
# Bad
# Bad
# Ascending

# Ok, but I also need Descending Lists

##for each in int_sets:
##   if each == sorted(each):
##      print("Ascending")
##   elif each == sorted(each, reverse=True):
##      print("Descending")
##   else:
##      print("Bad")

# Descending
# Ascending
# Descending
# Bad
# Descending
# Ascending

# Ok, things are working well, I probably need a counter for the number of good lists though.
# Despite these tess and comments, I am still "at the top" of the pure code so.

good_lists = 0

# I also need to check for the other condition in the test
# Any two adjacent levels differ by at least one and at most three.

# Since I am still "at the top", I will go ahead and just make a function to check this here.
# Note to self, post a clean version of the code below.

def check_range(a,b):
##  print(f"{a},{b}")
##  print(abs(b-a))
##  if abs(b-a) >= 3 and abs(b-a) <= 1:
  if abs(b-a) <= 3 and abs(b-a) >= 1:
##    print("OK")
    return True
  return False

# I am also going to clean up my ascending/Descending loop a bit.

##for each in int_sets:
##   if each == sorted(each) or each == sorted(each, reverse=True):
##      for i in range(len(each)-1):
##         print(i)
##         print(f"{each[i]},{each[i+1]}")
##         check_range(each[i], each[i+1])
##      print("Good")
##   else:
##      print("Bad")

# Something is not working right, so I'm modifying the defined function above a bit and adding some prints to test.

# I found it, my Greater than less than signs were reversed, oops.
# Also, all this commenting is seriously slowing this whole process

# I'm copying the above loop though, for posterity, before finding a good way to track good loops.

for each in int_sets:
   if each == sorted(each) or each == sorted(each, reverse=True):
# Lets assume a set is true
      good_set = True
      for i in range(len(each)-1):
# If the set is still good, keep checking, otherwise, don't.
         if good_set:
           good_set = check_range(each[i], each[i+1])
# I hate having these conditionals like this, but this is starting to get exhausting typing this, and it's easy.
# If the set is still good after checking the digits, add one to the total number of good sets.
      if good_set:
         good_lists +=1
# I removed the else, because I don't care if it's bad.

print(good_lists)
# This gives 2, as expected, for the sample dataset.
# Time to adjust for my personal data set as input.

# This gives 326 (data sets and answers very by person).
# This is the correct answer, on to Part 2.

# For Part 2, the system can tolorate a single bad level.  Those are what I am checking for in "check_range'.
# Normally I would modify my code to do both tests at once, but for TODAY, i am just going to make a second version.
# Basically, if a bad pair happens, it needs to try matching with the next higher number.  But it only needs to try it once.

good_lists_p2 = 0

##for each in int_sets:
##   if each == sorted(each) or each == sorted(each, reverse=True):
##      print(each)
##      good_set = True
##      dampened = False
##      for i in range(len(each)-1):
##         if good_set:
##           good_set = check_range(each[i], each[i+1])
##           if not good_set and not dampened:
##              print(f"Trying {each[i]} and {each[i+2]}")
##              print(good_set)
##              good_set = check_range(each[i], each[i+2])
##              print(good_set)
##              dampened = True
##      print(good_set)
##      if good_set:
##         good_lists_p2 +=1
##      print(good_lists_p2)

# So, this is not working out.  It's mostly working, but it's failing my Ascending/Descending check.
# Specifically, this one in the sample data fails. "1 3 2 4 5"

# What I need, is a new way to check Ascending and Descending lists.  An annoying way, that is ugly.
# I could build this in to the existing checks, but at this point, I don't want to, I just need a yes/no check
# And all these notes and comments are getting annoying.

def check_order(list):
   if list[-1] > list[0]:
     direction = "Asc"
   elif list[-1] < list[0]:
     direction = "Desc"
   else:
     direction = "Equal"
#   print(direction)

   for n in range(len(list)-1):
      if list[n+1] > list[n] and direction == "Desc":
        if n+2 < len(list):
          if list[n+2] > list[n]:
             return False
      if list[n+1] < list[n] and direction == "Asc":
        if n+2 < len(list):
          if list[n+2] < list[n]:
             return False
   return True

for each in int_sets:
#   print(each)
   if check_order(each):
      good_set = True
      dampened = False
      for i in range(len(each)-1):
         if good_set:
           good_set = check_range(each[i], each[i+1])
           if not good_set and not dampened and i+2 < len(each):
#             print(f"Trying {each[i]} and {each[i+2]}")
#             print(good_set)
              good_set = check_range(each[i], each[i+2])
#              print(good_set)
              dampened = True
#      print(good_set)
      if good_set:
         good_lists_p2 +=1
#      print(good_lists_p2)






print(good_lists_p2)


# 415 too high
# 414 too high
# 400 too high
# Ok, I started Guessing
# I got it
# 381 for my data set.






Weekly Wrap Up – 11.24.2024 – 12.01.2024

When I write these in my local copies, I don’t put the date ranges on them, just the date they were written. Its one of the most pain in the butt parts of this because it means opening some sort of calendar. I mean, its not hard, but I really do not look at calendars a lot. At least not beyond “Day of the week”.

While I am rambling about things I don’t follow, I also don’t really follow the weather. Somehow, despite decades of data, and AI and all the magic pf technology, weather predicting still seems like a complete and utter toss up 90% of the time. I prefer to just, decide when I walk put the door, or over dress with hat and gloves or whatever, that can easily just be discarded.

On to this last week. It was of course, Thanksgiving week. We went down to my mother in law’s for the day, though no real fancy dinner or anything, just sandwiches, and doing various tasks around her house that needed done.

Speaking of Thanksgiving, I lied last week, I caught, part of, the Macy’s parade. It starts earlier than I thought. The antenna hook up went way better than expected. Despite that we sort of sit “downhill” because we are nearish the lake here, and the antenna itself isn’t even above the roof line, I can receive almost all of the channels I should be here. CBS which os very far is a little iffy at time, and PBS, which is probably the farthest, shows up but never locks in. But Fox, ABC, CW, the religeous channel, all tune in with all their subchannels.

The Saturday after Thanksgiving was very busy at the shop, which was nice. The town had a holiday event and it was “Small Business Saturday” so we actually had a regular run of customers. Many first timers and many who really liked the shop. It was a good sign, hopefully.

Advent of Code 2024 – Day 01 – Historian Hysteria

Apparently I only attempt do Advent of Code every other year.  I had this vague thought about doing this thing in JavaScript this year, but considering I am way better at Python than JS, and I have yet to actually complete one of these 100%, i should stick with what am good-ish at.  

The early day are always stupid easy.  It’s usually around halfway they have some super goofy and hard problem that I get stuck on.  The main change this year is doing it through the Bash terminal.  Though I think I did it this way in 2020.  I may swap later, who knows.  The only real annoyance is opening and closing files to test run.

I also have not done a lot of coding in a while, so I had to search up on how to do a few things.  It was a good starter scenario though, it used a lot of things I have forgotten.

I don’t do anything super fancy with my code on these, I have seen some annoyingly unreadable one liners a few times.  I always prefer clean code.  The thing runs in essentially zero time anyway, I don’t need to be “milliseconds more efficient”.

Anyway, here is my solution for part 1 and 2 of Day 1.

with open("Day01Input.txt") as file:
    data = file.read()

sets = [each.split(" ") for each in data.split("\n")]
sets.pop()

list1 = []
list2 = []

for each in sets:
   list1.append(int(each[0]))
   list2.append(int(each[1]))

list1.sort()
list2.sort()

total = 0
total2 = 0
for i in range(len(list1)):
    total += abs(list1[i]-list2[i])
    total2 += list1[i]*list2.count(list1[i])

print(total)
print(total2)

Weekly Wrap Up (11.17.2024 to 11.24.2024)

I started posting these, a while back but they kind of fell by the wayside. I guess some of it just got covered in regular posting, and some of it ends up on the other blog, if I bother. Probably, I decided I didn’t really care. But maybe I should care. So here we are.

I have actually done a few of my “wishlist todo” projects this week. I have recently been hardcore digging through my too many bookmarks problem in Firefox. This has been an ongoing effort for a few months now, but I started on a phase two of this project this week. Specifically, I set up a separate bookmarking app, for some of these bookmarks. After some looking at options, I very lightly started using Raindrop.io, but I also remembered that I really want to not rely on other services that may randomly raise prices, limit features, or just plain close.

So instead, I set up LinkAce, in my docker set up. It was, surprisingly simple. Some of my attempts at docker set ups fizzle out. The biggest thing I have to watch for in the docker-compose files is for port use. Everything thinks its alone and wants to exist at port 80 or 8080. I have them numbered up now, 8080, 8081, 8082, etc.

The long term sort of idea.

  • Link Ace will be a sort of, well sorted repository of things that could be useful when I want to go look for them.
  • Anything that is a text or article gets clipped and dumped to my text archive.
  • It needs clean up, but I have been working on a series of markdown files that work as a sort of wiki for coding information.
  • Various bookmarked todos get put on a proper list. “To Read”, “To Watch” “To Play” etc.
  • Anything I may want to buy gets put in a big spreadsheet with pricing etc. I have actually already done this, since these bookmarks were already sorted together.
  • I have a zillion little projects bookmarked, these will all go in a list as well, or possibly (Probably) get sorted put into a Joplin notebook for each project. Like, sometimes I research a bit of a coding idea, them bookmark several different code snipped I may want to use.
  • Things I actually regularly use, will just stay in Firefox. The idea is to get Firefox itself down to maybe, 50 actual bookmarks. Not, 10,000. I am not sure I am exaggerating with that 10,000.

Anyway, projects this week, I got side tracked. I hung up an antenna on the side of the house today. I may put it on a proper mast later, but for now, I just stuck it on the leftover DirecTV mast that hangs off the back of the deck. I have not tested it yet. I doubt I get a ton of channels, but I should be able to get WAND and WBUI, which are both in town.

Everything else is like 40 miles away. I doubt I can get them with the antenna where it is. I literally have done this sort of thing for a living as my job for almost 20 years now. I have a “pretty good idea” of how well this placement will work. For now, it will work for what I want, which is the occasional need for local news, The Macy’s Thanksgiving Parade, and maybe The Super Bowl.

I am not even going to be here for the Macy’s Parade, so that is… Kind of a bust.

Anyway, in the past, I could get a few channels just laying the antenna out in the deck and hooking it up. If I were super cool I could use some of the spiffy work tools I have to peak the signal etc. But I am not cool like that, also, the position won’t let me actually swing the antenna all the way around to point AT 90% of the towers in the area.

Another project I made a lot of headway on, because I can do it easily while playing Throne and Liberty. Years ago I purchased a bundle of Piano courses from a teaching website. I have been, for many years, meaning to go through and capture them with OBS for offline use, and just, archival in case that teaching website ever goes offline. YT-DL did not work annoyingly. Even using browser cookies. So a manual OBS recording, then clipping them apart in Clip Champ is the way.

In other less exciting news, I got new shoes. My old ones had a big hole in one side and I threw them out. I went to three whole stores, then bought some boring Sketchers, because I almost always buy Sketchers. Then today, I went to put on my old old old shoes to go work outside and discovered my “old old old work shoes”, are the same as my new shoes. Except the work shoes are all gross and filthy.

This wasn’t intentional.

What I Listened to This Week