This is a diary of impressions, feelings, lessons learned from the Advent of Code 2019. Days are ordered by completion. Solutions with code can be found on https://github.com/okomarov/aoc.

What’s the Advent of Code

From the About page:

Every day of December until the 25th you get a coding challenge. The first 100 participants to submit a correct answer get points. More details on the leaderboard page.

Why am I doing this

When I started the challenge I just wanted to benchmark myself.

I consider myself pretty average…but how average?

But now, as I am writing this on day 4, I don’t want to be just average. I’d like to get into the top 100 to finish a problem at least once.

I was also hoping I would have something to show for, if I ever look for a job in software engineering. In any case it’s a bit of time-sensitive prep.

My background

I’ve read in the past about the Advent of Code on Hacker News but I never participated nor tried a simple problem before the 2019 edition.

A few years back I tried a dozen problems from Project Euler, so I am not completely new to programming challenges. I used those to test myself, have some fun and learn some C++.

I do have a PhD in Financial Economics and prior “programming” experience with Matlab and SQL. You could say my financial knowledge is not in the average.

However, I am pretty much self-taught in computer science, with maaaany gaps here and there. Sometimes it’s embarrassing 😳.

I was a data scientist for Carv, a cool ski wearable, for about two years after completing my studies. I fully transitioned to Python and C++ during that period.

So, my skillset is a mix of time-series statistical analysis, a lot of data wrangling, basic mathematical modelling and algorithms (and backend software engineer, and aspiring entrepreneur, but that is another story).

I also used to play a lot of Dota 2, so here you go, thousands of hours into the bin. And Counter-Strike when I was in college.

If only I used those hours to <insert your dream here…>

I am also a slow reader. Tested this with several people. I am usually twice as slow as others on average.

The problems

Enough with the bla bla.

Here’s a collection of thoughts for each problem. I’ll add days as I keep competing in the Advent of Code.

Day 1

Saw post on Hacker News sometime midday. Decided to procrastinate and indulge in the problem.

Took a very casual look, copy-pasted the input into a Google sheet, and answered the first part of the problem in a few minutes while thinking if I should set up a dedicated folder with a Python environment.

Took my time with the second part. Texted a friend asking if the recursive mathematical series could be rewritten in closed form. Looked up on the web about recursive sequences. Stopped after a while, as I could not think of how to get rid of the floor() or max() functions.

or functions. Before completing the second part, I set up the environment.

I pasted the input directly into the .py file and added commas using VSCode’s multi cursor. Solved the problem with a loop.

Day 2

Changed attitude, woke up at 4:50 am. The challenge is released at 5 am. I am in London.

Solved the problem in bed. First part in 17 minutes and second part in 8 minutes ranking 1214 and 978 respectively.

Not too bad but still too slow. This is the first benchmark as Day 1 was late in the day and very causal.

I feel that overall Top 100 is doable.

I was definitely slow at reading the problem text, so could improve there, and skip some noise.

Started looking at problems from the previous year. Maybe, I can get a better idea of how to optimize the environment/setup and cut down on all unnecessary time frictions.

Again pasted the input into the .py file and manually added commas.

Day 3

Woke up at about 4:10, casually looked at a past problem, Day 2 or 3 of 2018.

Solved the problem in bed. First part at 01:52:45 rank 3504 and second part, after giving up to finish sequentially, at 04:15:02 rank 4820.

Disappointed. Getting into Top 100 is NOT attainable. First to complete took 5 minutes for the first part and 2 minutes for second part… oh boy.

I hope I can complete the whole calendar. Right now THIS feels like the challenge.

I expected the problems to be more mathy, like Project Euler, and not so much about speed. Feels like the advantage is in the experience with similar solutions. I am clearly looking for a scapegoat :(.

Still, I chose an inefficient approach. Tested on the whole input (Bad!!! duh…). Frustrated with the tooling. VSCode + run code, still need to print() to debug. I think I finally understand what REPL is.

to debug. I think I finally understand what REPL is. Didn’t want to look at what other people did, but caved in and checked r/adventofcode on Reddit. Should have done it earlier. Understood the mistakes in my approach. The thinking wasn’t too off though.

I pasted the input into a separate file ready to be loaded but I still wasted time pre-processing the data in Excel.

Also wasted a loooot of time debugging my first solution, just couldn’t get the indexing right.

I created two boards of zeros. Filled in the wires by masking with ones (this is where I was getting the indexed infill wrong). Then I overlapped the two boards to find intersections.

A simple loop with a Snake-game point-by-point approach was the best choice here, as I learned in the Reddit thread. Especially for part 2 but you only kinda know it afterwards…

Day 4

Woke up at 4:20, struggled a bit although went to bed at 20:30. Tired from the early wake of the previous day. Properly got up, had breakfast, listened to some music to wake up my brain.

I prepared a jupyter notebook this time, to get faster iteration and debugging.

Did much better than Day 3! Finished first part at 00:08:18 rank 1016 and second part at 00:26:22 rank 1653.

I got excited when I completed the first part. Especially comparing to the previous day! Pushed hard for the second bit but got a bit stuck.

The cut-off for the first part was at 6:25 and I did 8:18. So now I feel I can rank within top 100 at least once.

Had to Google how to split a number in digits. After thinking about the log10 approach, it was as simple as [int(d) for d in str(number)] 🤦‍♂. Also, should have not refactored into readable variables, e.g. has_adjacent_dgts = any(diff == 0) , waste of time.

🤦‍♂. Also, should have not refactored into readable variables, e.g. , waste of time. Also, I still keep reading the problem too slowly, afraid that I am misunderstanding something.

For the second part, since I got burned with my preferred approach on Day 3, which turned out to be overly complex and time consuming, I thought I’ll K.I.S.S. it and use a dumb loop.

So, here I went with a loop on the digits with conditions on previous and current digit, but could not get it right. Instead, I could’ve calculated the start and end positions of a streak of 0s in the diffed digits…which I had 90% ready from work I do with run-length encoding… I feel regret.

Checked solutions on Reddit. Counter(str(num)) can be used to check for 2-digit pairs since digits are monotonically increasing! Wow. So, understanding the problem is KEY. No S**t Sherlock!

Day 5

Worst so far. Set alarm at 4:20am snoozed until 4:40am, struggled to get up, had tea and biscuits.

It’s one minute to the start and I’m getting a bit of a rush. Why!? Not like I’m gonna have a chance. More like it’s gonna take me at least 10 minutes. Well, I’ll take the rush, might help me wake up.

5:32 Still trying to make sense of the input text, only copy-pasted input into file and solution from day 2. Arghhhhhhhhh

I need help, started posting on Reddit and as I wrote out my interpretation of opcode 3 and 4 I understood what I needed to do…

5:50am: I thought I got it but no, code 1100 makes no sense, what is opcode 0?

Self modifying input!!!!! 1100 becomes 1101 and trying to make sense of the sequence manually tricked me to read 1100 all the time… IT’s 1101!!!

Lesson learned: careful when testing by hand a self-modifying input

It’s more than an hour and I gave up. Checked out solutions and used one. Couldn’t even make it work at first as I had the input defined in a separate Jupyter cell, so after running the first part the input is modified and won’t work for the second part. Dumb! 🤦‍♂

Also what’s the point of using someone’s solution? Faking stats to avoid feeling like a complete failure? Lying to myself. Should have just gone back to bed, waited and solved later… feel s**t. Anger. Frustration.

This makes me think to abandon the competition and just work the problem day by day at my time. If I ever get any close to top 100 timing, try waking up early again.

10:50 Ok slept some more. Giving it a second go. Restart from own Day 2 solution. I need to learn how to extend my existing solutions.

I realised that on the first run I was mentally stuck on Day 2’s description and could not process the idea that instructions could vary in length or that actions could be anything else than modifying the sequence. Getting old…Pepperidge Farm remembers…

11:21 managed to extend Day 2 solution but stuck again…

12:19 was also commuting to my office space… but got stuck at dereferencing, especially for code 4, I thought it was always like opcode 3, i.e. always mode 0, but it turns out it’s not as I got a instruction 104.

12:37 Nevermind! Everything has to support parameter mode. Made it to part 2.

Stuck again in an endless loop at opcodes 5 and 6 not incrementing pointer at all. Tried incrementing by 4. Turns out should increment by 3 if condition is false… Why 3? Just guessed there was no third parameter.

12:52 Finished. So again 2 hours, was stuck at reading and re-reading and re-reading…not sure where I’ll be without the solutions.

Will watch some video and commentaries. Biggest issue here for me is not being able to keep in memory the text that I read and not able to interpret it correctly.

Overall, I abandoned, used an existing solution, then tried again and in the end would estimate position 6885 in 3.5 hours to complete both parts… Ufff

Does not matter at this point as long as I learn something.

Makes me laugh I thought 10 minutes could be enough…(in my defence it was an expectation BEFORE the release of the problem)

Day 6

Not bad, not good. Finished first part at 00:55:25 rank 2661 and second part at 01:10:27 rank 2206.

Set alarm at 4:25am snoozed until 4:32am, didn’t struggle physically, although went to bed late at 00:40 and went climbing during the day, so was pretty knackered. Maybe I was preparing some excuses for not getting up. The struggle was more on the mental side. I kept thinking “leave it to the big boys”, but at the same time “what are the chances that smt easier comes after the IntCode machine?”

Had tea and toast with butter and honey. Started listening to Greyhound by Swedish House Mafia to wake up but stopped as soon as the problem was released.

2 min in, Panic, don’t know what to do… text is not difficult but the tree scares me. Why?? Not the first time I work with them!

Thought of pre-sorting input in Excel, to get some insight…? Did it, and stopped checking any further almost immediately

Googled for “find node in tree python”, copied solution from StackOverflow and started building a tree with the count of ancestors iteratively. This will turn out to be like building a spaceship for a trip to the grocery shop…

5:34 first guess, incorrect, checked subreddit, solutions got unlocked at minute 11, so not super easy but not difficult, gonna stop feeling pressured , try until 6 am, then go to bed and have a second go later, not checking hints for now. There must be a simpler way!

, try until 6 am, then go to bed and have a second go later, not checking hints for now. There must be a simpler way! 5:43 tried simple set difference between children and parents

5:49 tried descending form leaf nodes only, this feel simple enough and the right direction, should insist

5:55 NOT JUST THE LEAVES!!!!!!!!!!! Part 1 done. The problem was that I lost track of the objective.

6:10 Descended from SAN and from YOU. At first tried to print out the paths and do it “quickly” in Excel. Then just took set differences between paths and counted nodes adding 1 for common intersection…that 1 was wrong…wasted 5 minutes. Also wasted another few minutes on a typo 🙄. Part 2 done.

First part was definitely off. Should review trees. But second part took 15 min and the cutoff for the leaderboard was 5:51. Now, while it’s almost 3 times slower, it’s not catastrophically far away as part 1.

I should stop using Excel. Only wasted time (or who knows, maybe Excel helps me realise a stupid approach faster than code). Will try to make it a rule not to use it and see what happens.

Also, need to be more careful when copy-pasting, was overwriting SAN’s path with YOU and getting empty set differences.

Will need to double check the count and why I was wrong with the initial sum, made me try different approaches and wasted time unnecessarily.

I feel that without the Excel fiddling and the typo bug I could’ve made it (with the caveat that I get the count right; need to double check what was the wrong assumption there).

Yesterday I “prepared” a bit and watched Jonathan Paulson solve Day 5 on Youtube and read Tips for getting on the leaderboard by mcpower.

While I can’t type as quickly as Jonathan (but hey I am not aiming at position 26…) I can see how the “get it done and refactor later” is the way to go.

A huge difference is how he skimmed through the text, filtering out noise… it took him 1–2 minutes and me 30!

I think my friend is right. If you’ve done IntCode before, you know more or less what to expect, so don’t need to get acquainted with the concept, adjust your thinking between Day 2 and 5 etc… I kinda knew from Computerphile videos what a tape machine is, yet struggled to translate that knowledge into practice.

Tips by mcpower suggest to check out other tough past problems, will do as I don’t want to be surprised and mentally stuck on concepts. If you’ve seen it once, you’ve seen it all (the last famous words of an average fool).

Also, I reverted to VSCode. A Jupyter Notebook is only gonna slow me down with cells, still need to print() stuff, so might as well do in VSCode and run the file in the terminal with a shortcut.

Day 7

Gave up… actually already from Day 6 (Friday) when someone mentioned Saturday puzzles are usually tough and I had plans for Friday evening. No way I am getting up early…

In fact, got up “late” around 6am. Didn’t feel the pressure, probably already out of the leaderboard anyways.

The puzzle is about IntCode again and I haven’t cleaned up my Day 5 yet. Doesn’t look too difficult! Should have tried to get up in time…

Managed to adapt the code from Day 5 fairly quickly, in about 7 minutes , but getting issue with test samples. I think I need to revisit Day 5 and clean it up.

, but getting issue with test samples. I think I need to revisit Day 5 and clean it up. Too tired, it’s almost 30 minutes I’m debugging and I can’t think clearly so going back to bed and will try later.

It’s evening, looking at a few solutions on Reddit.

OMG… “The first amplifier’s input value is 0”, and I kept testing with 1! WHY!?? Why do I keep reading wrong stufffffff from the text.

My IntCode machine is still wrong though, not sure what.

Comparing against benediktwerner’s solution. Why so much complexity with scheduler etc… Ahhh he’s the author of the Incode compiler, assembler and VM, so probably this is a very cleaned up version. Will take a break to make sense of this.

Resuming on Day 8 at 19:37 (London time), looking at part 1, trying to figure out where the bug is. It all looks ok though.

Arghhhhh!!! Use explicit form in conditionals, Dummy! This took me hours/days, at my own pace yes, but could have been the difference between a part 1 solved in 7 minutes and not solved at all.

I was hacking the phase as first read with this code thinking it will be False only on None but totally forgot about phase = 0. What a rookie mistake🤦:

if phase:

seq[write_to] = phase

phase = None

else:

seq[write_to] = input

Besides, I should probably use a queue of inputs from which to pop(). Part 1 Done. Trying to do part 2.

Day 9, still doing Day 7 part 2. Have I lost my resolve ?

? So, my program has been running correctly for part 1 but I can’t figure out how to make part 2 work. I’ve spent maybe already 5 ours. Looking at code from benediktwerner’s solution, mateoeh’s solution and the stream by Jonathan Paulson but still can’t make sense of it.

Giving another scroll at Reddit and I read [2019 Day 7 (Part 2)] Confused with the question. It’s finally clear… or the last famous words?

I completely misunderstood how amplifiers and the feedback loop works . I thought all amplifiers share the program but reset the position. So when an amplifiers outputs, the next amplifiers uses phase for first read, then reads previous output as input, resets the position to 0 BUT uses the same program from the previous amplifier.

. I thought all amplifiers share the program but reset the position. So when an amplifiers outputs, the next amplifiers uses phase for first read, then reads previous output as input, resets the position to 0 BUT uses the same program from the previous amplifier. Really tired of IntCode

Really tired of feeling stupid

Really tired of learning CS concepts from competition text.

Not enjoying this at all anymore . Will copy paste a working solution and move to Day 8. I am already behind Day 9 and knowing it’s about IntCode again not looking forward at all.

. Will copy paste a working solution and move to Day 8. I am already behind Day 9 and knowing it’s about IntCode again not looking forward at all. Any suggestions for Computer Science class slides that cover these concepts in a clear way?

Day 8

21:16 London time of Day 9, trying the problem while cooking. Taking it easy but giving myself some time pressure… or I burn the food 😂

Again, read for too long…There was an example, I should’ve checked that first, then previewed the question and started going.

11 minutes to get a running but wrong solution. Started with a list of lists of lists instead of just using numpy’s reshape()

Going for numpy’s reshape() but getting a weird printed output. For example:

>>> np.reshape(range(12), (2, 3, -1))

array([[[ 0, 1],

[ 2, 3],

[ 4, 5]],



[[ 6, 7],

[ 8, 9],

[10, 11]]])

For the love of Jimmy (who’s Jimmy!??), why are rows printed as columns!?? Anyways tried some bit-masking and a running minimum to find the layer of interest and got an answer…which was wrong, obviously.

Anyways tried some bit-masking and a running minimum to find the layer of interest and got an answer…which was wrong, obviously. I honestly can’t make sense of numpy’s display of multidimensional arrays. Unfriendly.

So, tried third approach with Counter, i.e. just getting a 25*6 chunk from the data, and checking the counts. Part 1 done .

. Start part 2, of course I need those layers and not just the counts! Back to numpy reshape. Figure out that I need 'F' ordering and to swap the first two axes (piece of advice, don’t trust numpy’s printed display of multidimensional arrays! I know I am repeating myself.)

ordering and to swap the first two axes (piece of advice, don’t trust numpy’s printed display of multidimensional arrays! I know I am repeating myself.) Implement a triple loop 😳. Gosh I am more embarrassed by this than by all my previous failures.

After years in Matlab I should be able to set transparent pixels to NaN and bubble up the missing values with the first non missing value (black or white).

and bubble up the missing values with the first non missing value (black or white). Got the output…can’t read it. Wouldn’t be too much of an issue if I didn’t waste a few attempts at getting plotting matplotlib.spy() 🙄. I decide to simply print a comma delimited array of zeros and ones, paste into excel, convert text to data, and use conditional formatting.

🙄. I decide to simply print a comma delimited array of zeros and ones, paste into excel, convert text to data, and use conditional formatting. GJYEA…pfff. To myself: “breath deeply, breath deeply”

Will check Reddit for efficient answers and the usual streams.

Also need to humble the f*** down and be patient (Ain’t nobody got time for that).

Day 10

Skipped Day 9, will pick up after reviewing second part of Day 7

Trying this day at around noon London time, so not competing for points but timing myself

Puzzle is about geometry and trigonometry. The latter is a pain, I can never remember formulas and mix stuff up. All the time. With geometry, on the other hand, I can derive formulas on paper but it takes more time than I would want to spend here.

So, googling for smt like “test if C lies on segment between A and B”. Found an easy solution from this SO question

I do again a triple loop 😳. For point A select point B then select point C, and test none of the Cs lie on segment AB. Add B to the observable asteroids from point A. Part 1 done, 24 minutes . Slow.

. Slow. Second part, figured decently quickly that I needed to order asteroids by rotation angle. Maybe in 5 min or so…

Then got stuck in measuring the angle between two points. Could not shift the basis axis to the x axis. Also probably because y is inverted.

I actually lost a looot of time on trying to debug with points drawn in each quadrant trying to figure out how much angle to take away to shift the base axis to point upwards (noon).

Once figured out, I was printing y, x coordinates instead of x, y. So got an answer but it was wrong

At first, I thought I was vaporising aligned asteroids in the wrong order, so debugged that. It turned out it didn’t really matter. My 200th asteroid was the sole on its path and the rotation didn’t even complete by then, so I could’ve randomed those which shared the same path. It would have not affected my 200th asteroid.

Then I thought my angle calculation was still wrong so landed onto this SO question, used it, and got exactly the same result. It’s here that I realised that the whole shift in the base axis was by 270 degrees because the y is inverted!

Finally, checked how I was printing my coordinates. Again, could not wrap my head around the top-left origin and just tried swapping (y, x) and got the right solution, yay. Part 2 done, and it’s after 2 hours ! Wow. I was doing other things, like chatting here and there but still…

! Wow. I was doing other things, like chatting here and there but still… The main problem was that I stored coordinates as (row, col) which is effectively (y, x) but called the variables themselves as (x, y). This was my biggest mistake .

. I was also weak on the geometry side, figuring out how to shift rotation angles. The inverted y-axis really did not help and I still have not internalised the concept. Should probably review the formulas in the base case and apply them myself to the inverted case.

After this day I am definitely changing my objective from trying to score in the top 100 at least once to avoiding big mistakes.

from trying to score in the top 100 at least once to avoiding big mistakes. In other words, I want to improve the confidence with which I write solutions. I still keep testing things multiple times before actually writing it correctly in one go. It has more to do with the general way I code. I write partial code and test it as I progress rather than write out the whole designed solution and test it at the end.

I dunno why, but it feels like I am actually improving (although my timing definitely isn’t).

(although my timing definitely isn’t). Other things to improve. The basics! I find often asking myself or googling if I can pop an element from a list by value or by index. I never had good memory but this is definitely a deal breaker for competitions.

Day 7 — Update to part 2

Today is Day 11 but I am going back to Day 7 part 2. I want to figure out why my IntCode machine, which runs fine for any input of Part 1, does not work in a feedback loop.

I tried to debug this for many hours now on 3 separate days (9 to 11).

I used benediktwerner’s solution to compare how the program was modified by my implementation as opposed to his. I rewrote parts of my code, checked VM only once.

It all checked out but I still could not find the bug.

Several years later… I finally found the 🐞 . I feel a sense of bitter accomplishment.

. I feel a sense of bitter accomplishment. It turns out I was mixing state between VMs by declaring class-wide inputs and outputs. A common theme re-emerges again. I need to be more solid on the basics of the language. What a rookie mistake:

class VM:

input = []

output = []



def __init__(self, program):

self.program = program.copy()

self.pointer = 0

When initialising the five VMs, all inputs were shared, so effectively the first VM consumed all its inputs and the phases of the other VMs, i.e. [phase0, 0, phase1, phase2, phase3, phase4]

I am glad this has been such an expensive lesson. I’ve always known in theory that class attributes will be shared by each instance of that class. Now I know in practice too. There is no better way for me to internalise a concept than to struggle on it like this.

As a side note, I debug with print() statements. I used a debugger in the past but got burned a couple of times with C++. Maybe I should give the VSCode debugger for Python another chance. I would have probably caught the bug much earlier.

Day 12

Trying Day 12 from Moscow, so release is at 8am, a very decent time.

I started ok and got first answer in 16 minutes, wrong. Can’t really pinpoint any specific problem of why so slow. Me being just old?

Found a bug in the when updating position with velocity and gave second answer at 27 minutes. Still wrong…

Had calculated the system energy incorrectly. I was sloppy in reading the text. Submitted third answer in 34. Wrong again 😫

Ok, 1000 steps…had 100 from the test sample. Part 1 done in 35m 32s, rank 1169, my second best for part 1.

in 35m 32s, rank 1169, my second best for part 1. My previous feeling that I was improving… uhm not sure anymore.

Trying part 2. It’s 51 minutes and I am out of the leaderboard. Problem still running…will take ages and need to leave soon, started refactoring with numpy trying to leverage matrix ops to speed things up. Can’t come up with any other faster way at the moment. Will let it run while showering and try again later. Don’t wanna look at solutions for any smart shortcuts, want to find it myself.

trying to leverage matrix ops to speed things up. Can’t come up with any other faster way at the moment. Will let it run while showering and try again later. Don’t wanna look at solutions for any smart shortcuts, want to find it myself. Thought about checking when velocities are all 0, but still need to update state, so that is not going to save me much. Don’t think this is the right approach.

Resumed in the evening, tried for an hour or more and gave up. Could not come up with anything smart and as I saw a hint about GCD on Reddit I knew I wasn’t going anywhere with my attempts.

Looked at a couple of solutions and understood the logic… was kinda obvious (or not, unsure I would have figured it out on my own).

Part 2 done, rank 4889 🤷

Day 14

Got up at 7:30, ready to take the release at 8am Moscow time. Skipped day 13 (I’ve skipped IntCode since day 9 so far but planning to catch up somehow)

Been trying to solve part 1 for a while now, it’s 9:09. Will go and have breakfast. Not getting any close .

. So, I resume at 9:35 and apparently I skipped too much text when (not) reading. I was taking ratios between desired amount and the produced outputs in order to minimise the input of ORE…

Added ceils to ensure I am running the correct number of recipes and it seems all ok but can’t figure out why I am using too much ORE .

. Peeked at some hints from Reddit and saw some surplus management . I think in the back of my mind I realised I needed that but was in denial…was looking for a non existing and quick-to-fix bug…Oh well.

. I think in the back of my mind I realised I needed that but was in denial…was looking for a non existing and quick-to-fix bug…Oh well. Feel stupid, don’t wanna do it anymore.

Side consideration. I need to learn shortcuts in VSCode to jump to the closing brace… and train that muscle memory.

Decided to take a shower and resuming again at 11:19. I put some music on, now feeling calmer.

To think positively , I think I’m improving at writing a solution in one go which is something I noticed I was not able to do during day 4–5. The solution is still incorrect but the problems are also getting tougher.

, I think I’m improving at writing a solution in one go which is something I noticed I was not able to do during day 4–5. The solution is still incorrect but the problems are also getting tougher. 11:51 Success! Part 1 done . Rank 1527 in about 2.5 hours (net of breakfast, shower and other distractions).

. Rank 1527 in about 2.5 hours (net of breakfast, shower and other distractions). Overall I had issues concentrating today, lost it and got overwhelmed. While solving I feel I get close to getting some points but then I burst under the pressure and get stuck. My brain also shuts down and instead of thinking about the problem I think about how I am not gonna make it on time.

Another thing to improve is parsing the input into an appropriate data structure. Took me too long to organise the formulas into a dictionary which ended up unnecessarily sophisticated.

into a dictionary which ended up unnecessarily sophisticated. Yet another thing, I struggle to think about recursion . Although, I hope practice will get me used to it. Trying to think about a terminal condition first, then a fixed structure for the recursive input. Maybe it’s the wrong way.

. Although, I hope practice will get me used to it. Trying to think about a terminal condition first, then a fixed structure for the recursive input. Maybe it’s the wrong way. Part 2 works for all input samples but not for my input, wot!? 😫

Just tried upping the the result by one, it worked …ok, will ask on reddit what’s wrong or compare against other answers.

…ok, will ask on reddit what’s wrong or compare against other answers. Done with part 2 in about 20 minutes… rank 1280, second best for my part 2.

Not sure where my count was going wrong but I adopted binary search and it returns always the correct answer…gotta review this issue some time

Day 16

Got up at 7:40 for the release at 8. Had a quick breakfast and prepared my template dayX.py file, and two input files, one for tests and one for the real input.

file, and two input files, one for tests and one for the real input. Lots of text. I start writing down a few inputs like the base pattern. Quickly peek at the final question to see if I can skip some of the text and concentrate on examples. Nope. Go back reading.

I get confused by “When applying the pattern, skip the very first value exactly once. (In other words, offset the whole pattern left by one.)” and proceed to create this monstrosity:

signal = list(map(int, '12345678'))

base = [0, 1, 0, -1]

n = len(signal)



def get_pattern_monster(i, n):

match = []

p = 0

c = 0

while len(match) < n:

if i == 0 and c == 0:

p += 1

to_append = [base[p]] * (i + 1)

if c == 0 and i > 0:

match += to_append[1:]

else:

match += to_append

p = (p + 1) % len(base)

c += 1

return match[:n]

I later reviewed a few solutions. One approach is to index directly without creating the extended pattern, e.g. bluepichu’s solution, or to use itertools ’s iterables, i.e. (returning a list for clarity):

def get_pattern_iterable(i, n):

match = [itertools.repeat(b, i+1) for b in base]

match = itertools.cycle(itertools.chain(*match))

next(match)

return [next(match) for _ in range(n)]

After a few bugs in creating the extended pattern, I am finally done with part 1 at 47 minutes. Pretty slow. Rank 1256.

at 47 minutes. Pretty slow. Rank 1256. At 9:08 I check if all points have been handed out. Don’t want to stress about the top100 anymore. They have, good.

At 9:37 my implementation works on all test cases but is waaaay too slow. I give in and check hints on Reddit.

At 9:56 I try the hint “at that length is just a sum” and complete Part 2 . Lower rank compared to my previous attempts but totally felt like cheating.

. Lower rank compared to my previous attempts but totally felt like cheating. At first I haven’t noticed what now looks like a very obvious pattern… and it could’ve taken me another 1–2 hours to figure it out or maybe I would have not figured it at all.

Honestly I think I just gave up but I also had the excuse that I needed to leave…

Reflecting on the problem during the day I noticed that since Day 14, but I skipped Day 15, the problems require a change of gears in my mental readiness/willingness.

in my mental readiness/willingness. I wasn’t ready to search harder for a solution. In the next days I will see if I hit some intelligence limit.

Day 9

It’s Day 15 and I’ve got a mental block. Wanted to start catching up with IntCode puzzles today since it’s also IntCode day, but I only opened the page of the problem and did not even read it.

Trying again on Day 17 at 11:12. Copy pasted solution from Day 7, which I previously cleaned up.

At 11:40 all input samples seems to work, but the program throws the 203 error .

. After a bit of debugging I remembered someone mentioning this issue on Reddit.

At 11:55 I am looking at test cases to solve the 203 error from this Reddit answer.

Fixed the bug and I am done with part 1 at 12:13. With some minor distractions here and there it took me about 1 hour.

at 12:13. With some minor distractions here and there it took me about 1 hour. The bug: I wasn’t adding the relative base to the write position for opcode 3. I was treating write values as relative positions since immediate mode never applies to them…

Part 2 done straight away in 1 min. Code was efficient already.

in 1 min. Code was efficient already. Considering that 100 people finished it in 14 minutes…I am more than 4 times slower, not to mention that I had a bug which would have probably taken me another 1–2 hours to debug without the hints.

Overall this was an easy task if the IntCode machine was ready and shiny. Which I thought it was…but then again, the wording with the modes and the exceptions for writes…

Day 11

It’s Day 17 and I completed the problem for the day. I have some more time, so, I’ll try to catch up on a few IntCode problems.

I started Day 11 at about 15:10

At 15:22 I’m like pfff… don’t wanna do it. I already envision lots of bugs, double counting and stuff. Will take a break instead.

At 21:49 looking at the problem again. I am not the freshest but don’t want to go to bed yet…

First answer at 22:15, too high.

Can’t deal with this. DO NOT WANT TO DEBUG INTCODE. It’s 22:25 and I am gonna check some hints.

Ok, I resisted. Did not check hints nor other solutions. The rational side won. It was telling me that the intcode machine should be correct since Day 9 had a debug feature in it. I/it was right :D.

I persisted and figured the bug was somewhere else in my program. I was painting AFTER moving!

Part 1 Done. It’s 22:35.

It’s 22:35. Part 2 done at 22:47. Took me time to figure out that I could scatter plot… I am really tired or lacking inventive…axes ratio was unequal so couldn’t get the picture at first…duh 🤦‍♂️.

at 22:47. Took me time to figure out that I could scatter plot… I am really tired or lacking inventive…axes ratio was unequal so couldn’t get the picture at first…duh 🤦‍♂️. Sidenote. The statement “Before you deploy the robot, you should probably have an estimate of the area it will cover: …” is totally unnecessary! I learnt from Day 3 — Crossed Wires that you can use a dictionary to store (x,y) coordinates and the value. Happy to see that some earlier puzzles are paying off.

Day 13

Still Day 17, wanna try Day 13. Got my setup ready, waiting to start at 23:00, to make it easy to track time.

Part 1 done in 6 min. Nice.

in 6 min. Nice. 23:47 FIRST FREAKING RUN and Part 2 is done !!!!!!!!! SOOOOOOOO PROUD!!

!!!!!!!!! SOOOOOOOO PROUD!! Now checking leaderboard times. Part 1 ranges from 1:33–3:23 😐. So, twice as slow and Part 2 max time in only 20 min and 26 sec…

The second part took me 40 minutes. Why?

At first I thought to run the game, get a score and see how many blocks have disappeared. Then calculate final_score = (score / destroyed_blocks) * total_blocks . However, I could not figure out how to get the before and after the ball hits a block, so did not investigate this approach any further.

. However, I could not figure out how to get the before and after the ball hits a block, so did not investigate this approach any further. I was trying to avoid figuring out what to do with the joystick. Spent too long mentally avoiding this.

Also lost quite a bit of time plotting the ball and the paddle with matplotlib.pyplot . Gotta figure out how to do it faster in the terminal.

. Gotta figure out how to do it faster in the terminal. Finally I just took a leap of faith and went with the idea that the game would ask for joystick input for every change in coordinates of the ball. And that was it. I reckon this is the next big thing to improve. It’s closely linked to text interpretation and taking reasonable assumptions.

and went with the idea that the game would ask for joystick input for every change in coordinates of the ball. And that was it. I reckon this is the next big thing to improve. It’s closely linked to text interpretation and taking reasonable assumptions. Overall very happy with coding a solution in one go and getting it right at the first try this time. Even though it took me a lot of time to decide what to code. It’s something that I posted about on Day 10 and 14. So, good personal progress.

Day 15

Today is Day 21, and I haven’t done any puzzles since Day 19 (apart from short-lived attempts to Day’s 18 part 2).

I am at the airport, it’s 14:11 local time (the release is at 8am) and I am trying Part 1.

At 14:26 I implemented BFS but it’s either buggy or too slow. Will take a break.

At 14:40 I realised the data is modified on each run of the IntCode machine. So, with BFS I will need to preserve state on each step, which sounds pretty inefficient.

Trying DFS with backtracking and I lost track of how much time I invested in this.

I rewrote DFS three times. I did not like how I was storing the path and had issues in the backtracking.

I got epically stuck on the endless sequence 1, 2, 1,… thinking it was Up, Right, Up,… as I usually list directions in clockwise order, i.e. U-R-D-L.

Instead, it was Up, Down, Up… i.e. the loop was stuck in an endless back-and-forth because I did not store visited coordinates. Rookie and expensive mistake 😳. At least now the concept is well ingrained in my brain.

coordinates. 😳. At least now the concept is well ingrained in my brain. I also feel that my debugging skills have failed me. To help me debug I ran mcpower’s solution to check that I was backtracking correctly…well I wasn’t.

I really need to setup VSCode’s debugger… what a drag. What can I do to get over this feeling?

Other things I’ve done that were over-engineered: I would move in all 4 directions and backtrack just to list the next possible movies, i.e. those not into a wall. I was also using f(x): x + (x mod 2) * 2 — 1 to get reverse direction of x . A hardcoded map of 4 fields is 1000 times easier to read and maintain.

I would move in all 4 directions and backtrack just to list the next possible movies, i.e. those not into a wall. I was also using to get reverse direction of . A hardcoded map of 4 fields is 1000 times easier to read and maintain. Part 1 done on Day 22. Gonna try part 2 tomorrow as I need to record the board and then I can apply BFS until I find the last and longest path.

on Day 22. Gonna try part 2 tomorrow as I need to record the board and then I can apply BFS until I find the last and longest path. It’s Day 23. Taking it easy. Spent time reorganising code into a class for personal practice. It took me more time than I wanted as I was not updating the position correctly… hopefully I learned the lesson.

Used BFS to traverse the board, similarly to Day 18 which I attempted a few days earlier.

Part 2 done . Wrote the correct solution in one go. I am starting to memorise the algorithm, good :)

. Wrote the correct solution in one go. I am starting to memorise the algorithm, good :) Overall, I shifted my focus from competing for points to learning/training for a couple of reasons.

from competing for points to learning/training for a couple of reasons. First, can’t get in the top 100 anyways. Puzzles are getting tougher and I need to fill knowledge gaps.

Although I noticed improvements in my problem solving and coding skills, my best attempt to date remains part 2 from Day 2, rank 978.

Second, I don’t want to get at 5:30am to make the release at 6:00am. After trying on the first week, and waking up for the London release at 5am, I got increasingly tired/jetlagged and eventually got sick.

So instead I just practice at my pace. I systematically review other solutions and rewrite mine to memorise common algorithms. I try puzzles for longer before checking hints.

Day 17

Trying Day 17 on Day 24 at 14:33. Not competing so will take my time.

First attempt to Part 1 at 14:55, result is too high. Also, why do I have two empty rows in the board?

At 14:57 tried the multiplication minus the two rows per intersection… still wrong!!?

Ok, found a bug . Apart from the 4 connected neighbours, the intersection needs to have a # in the middle 😐, nc.

. Apart from the 4 connected neighbours, the intersection needs to have a in the middle 😐, nc. At 15:05 I guessed 4 times and it tells me to wait 5 minutes …what!!!??? Never had this before.

…what!!!??? Never had this before. Feeling frustrated. At 15:12 I am checking hints on Reddit, looking at Jonathan Paulson’s solution… I was popping the board in reverse order argh… 😩

Part 1 done at 15:18.

at 15:18. For Part 2 at 15:53 I am done with counting the L/R sequence manually on Excel.

Not sure why it took me so long and why I used Excel again instead of code.

Don’t wanna check any more hints, so will think about the best way to approach this. Will take a shower.

I checked the leaderboard and the cutoffs are at 8 minutes for the first part and at 45 for the total. My first solution could’ve been at 22 minutes.That is, without the reverse board and wrong intersection check bugs 😳.

It’s Day 25 and I am deriving the L/R sequence programmatically as an exercise. Spent like an hour on this… too looooong. On the other hand, I had a typo in my manual sequence…

At 18:10 I am writing an algorithm do determine the 3 functions such that the instruction set fits into 20 characters.

I read on the previous days that the problem is about compression, so I am making an effort to come up with something smart rather than hackish.

I know that the objective is to achieve highest compression, so I am counting occurrences of subsequences and the total saved space.

The idea is to iterate over the subsequences, picking first the ones that save the most space and progressively substituting into the initial sequence until it only contains the A, B, C functions.

At 22:17 I got the program working but passing the inputs as strings does not work?

Ok, converted to ord() and Part 2 done . Submitted and got it right at the first try, no bugs! Happy that my thinking was right.

and . Submitted and got it right at the first try, no bugs! Happy that my thinking was right. The solution could be improved to short-circuit on combinations of sequences that cannot yield a full substitution. But will review it after watching a few other solutions. Better start anew than try to polish a 💩. Maybe I am too harsh with myself.

Day 26 watched video by Jonathan Paulson. He hacked the compression manually 🙄, pffft.

🙄, pffft. However, I learned a couple of things. I too tried to pick subsequences manually by inspecting the highlighted subsequence in VSCode but abandoned almost immediately. Instead, I should have printed the substituted sequence like Jonathan did.

I also noticed that for my initial grid parsing I was pointlessly differentiating between # and . and ^ . Just appending any character to the row and restarting the row after a new line would have reduced the program from 14 to 8 lines.

and and . Just appending any character to the row and restarting the row after a new line would have reduced the program from 14 to 8 lines. I also took a more convoluted approach to generate the L/R sequence.

I was saving the Up, Right, Down and Left coordinates in a deque , and rotating it so I would have the Left on -1 and the Right on +1 at all times. Rotating the coordinates was superfluous since I was already using the mod to wrap around. I managed to reduce the program from 56 to 30 lines.

, and rotating it so I would have the Left on -1 and the Right on +1 at all times. Rotating the coordinates was superfluous since I was already using the to wrap around. I managed to reduce the program from 56 to 30 lines. While the length of the program is hardly an indicator of quality, I just had unnecessary complexity and the line reduction is a simple and imperfect proxy to quantify that.

Day 19

I used to dread IntCode problems but now I realise it’s been a couple of times that I actually look forward to them.

Days 3 and 5 were a nightmare to debug, but now that the IntCode machine is consolidated it feels like magic. I trust the abstraction .

. Anyways, it’s the 27th of December, 8:43am.

At 8:51 I submit the first answer and Part 1 is done ! Felt quicker than other problems. I suspect the leaderboard is much faster though.

! Felt quicker than other problems. I suspect the leaderboard is much faster though. The 100th competitor finished the first part in 3:40 minutes. What does it take to be this fast?

Well, I didn’t immediately realise that I needed to restart the VM with the original input every time. Or was I just slow at reading again? Maybe I did not feel the pressure since I am actually not competing…

I start Part 2 without a real plan, thinking to just print portions of the beam at hardcoded offsets, paste it into Excel and manually find the top-left corner of the square fitting the beam.

After a couple of iterations I realise this is not going anywhere…Python is too slow to run. The workflow is error-prone and fiddly!

I am really struggling to drop Excel from my toolset . I feel it’s hurting my progress but it’s sooooo nice to visualize what I am doing.

. I feel it’s hurting my progress but it’s sooooo nice to visualize what I am doing. On the other hand, what if I used C++? It sounds like this could have been the fastest approach…

Then I think of a simple algorithm. I am basically moving right or down until current position + 100 in both directions (right and down) is still within the beam.

At 9:56 Part 2 is done .

. Still took a long time. First, because of the manual + Excel waste of time. Then had a bug since the board did not have any beam in some initial rows, so I was going right endlessly. Starting the row offset at 100 fixed that. Then I had a bug in the inclusion condition. I was checking the bottom right corner instead of the bottom left one for the down condition.

Did not particularly like this problem. Also watched Jonathan’s video and he too got stuck but still was waaayyy faster than me (but not in the top 100). I don’t feel like there is much to learn from this puzzle. Would love to be proven wrong.

Day 20

It’s the 29th of Dec, I am at the airport again, and planning to do Part 1 on the plane.

Part 1 is done in about 1:30 hours, although I can’t check the answer as I don’t have wifi.

in about 1:30 hours, although I can’t check the answer as I don’t have wifi. Slow! Although I was doing it with several interruptions and distractions, the problem is basically Part 1 of Day 18. The only difference is how you organise portals.

I wasted time in parsing the input. I was trying a generic approach, when the portal orientation can easily be detected by checking where the path connects to the letter.

I submit the answer to Part 1 on the 31st. It’s incorrect 😐. Debug in 5–10 minutes. I wasn’t counting the teleporting step.

Although I now tried the VSCode debugger (it really takes less than a minute to setup) the lack of F1–12 keys on my laptop makes me hate it. Guess the brand… print() for the win!

for the win! At 11:40 I am reading Part 2, and it’s a 🤯 WTF!? moment.

Ok, reading a couple more times and looking at the example. Not too bad after all.

Basically, taking the inner portals, those with the labels inside the central empty space, increase your layer count. Taking the outer portals reduce the layer count. And you can only take portal AA and ZZ from layer 0.

So, I need to organise the portals in two sets and add the layer level to the visited set of nodes when traversing with BFS and a condition for the exit to be at level 0.

At 11:25 running with pypy , still a bit slow… 3 later minutes and the answer is correct! Part 2 done .

, still a bit slow… 3 later minutes and the answer is correct! . This could’ve been done in 2 minutes, IFF speed reading + pypy + no bugs.

It took me 10–15 minutes to understand the problem and about 30 minutes to change and debug.

One of the slowdowns was that I tested on the sample input, after the main input was taking too long to run with bare python , but forgot to change the hardcoded bounds for detecting the inner vs outer portals.

, but forgot to change the hardcoded bounds for detecting the inner vs outer portals. I also allowed negative layers at first, which slowed down the solution, although the requirement is clearly positive or null.

Nonetheless I am happy with the improvement in rank from 4296 for Part 1 to 3609 for Part 2.

Day 21

Really liked this problem! Different, challenging but not overly difficult. I learned something new 💃.

Today is the 2nd of January 2020, time 16:00, and I am trying Day 21. Happy New Year 🎉!

At 16:07 I finished reading the puzzle and taking notes. While slow, I feel there is a slight improvement compared to how slow I was in the first week of the AOC.

At 16:44 the puzzle is more difficult than expected…registers and boolean logic… I am so bad.

At 16:57 Part 1 done … Slow.

… Slow. This is something I have never done before and I panicked. I wanted to bail several times and kept thinking of how slow I was, instead of re-focusing and trying a different approach.

I feel of a bit of regret as my solution at minute 30 was 1–2 instructions short of my final instruction list.

I also wasted time: on conversions, i.e. string to list of ord , on wrappers for the AND, OR, NOR and WALK instructions, and on creating the final list of instructions.

to list of , on wrappers for the AND, OR, NOR and WALK instructions, and on creating the final list of instructions. I still feel I do not completely understand how to convert conditional statements to boolean logic with a limited amount of registers .

. Anyways, I try Part 2 and solve it at 17:09, i.e. in 12 minutes. Luck?

it at 17:09, i.e. in 12 minutes. Luck? I check out Jonathan Paulson’s video to gain insights.

At 6 minutes he was already testing the input and writing some logic. It’s wasn’t a very linear process, i.e. reads first then codes, but I estimate it took him half my time to read and understand the problem. So, I do think I am slowly improving at reading/understanding the text.

at reading/understanding the text. Happy I watched his explanations. While this might be obvious to most, I especially liked the assumptions he took to solve the puzzle and the explanations on how to handle the boolean logic with the registers T and J.

As a side note, I thought of Part 1 in terms of the following conditional statements:

if not A and D:

jump

elif not B and D:

jump

elif not C and D:

jump

and translated it to:

NOT A T

AND D T

OR T J NOT B T

AND D T

OR T J NOT C T

AND D T

OR T J

First, I don’t need the if ... else but simple sequential if conditions. This is what I actually do with the logic. I am actually unsure how to properly translate if .. else without a GOTO. Finally, I could've wtitten the above as:

if not (A or B or C) and D:

jump

which translates to:

NOT A T

NOT B J

OR T or J

NOT C T

OR T or J

AND D J

Day 23

It’s still the 2nd of January, trying Day 23 at 19:14, it’s my second puzzle today.

I decided to skip Day 22, as I know it’s a tough one. Will do it when I have more time to avoid deferring as I did with Day 18 Part 2.

At 19:30 Part 1 is done . Felt fast.

. Felt fast. Wrote part 2, submitted answer. Too high. Tried another one…too high again. I think my implementation is wrong as it’s not properly async and parallel and was surprised Part 1 worked out.

At 20:00 Part 2 is done . I guessed after printing NAT values and picking the last one before the system went into permanent IDLE.

. I guessed after printing NAT values and picking the last one before the system went into permanent IDLE. At 20:03 figured where the bug was, although I am still unsure why it works. I was checking when the repeated y value is received by the NAT instead of checking for the repetition in the sent values!

by the NAT instead of checking for the repetition in the sent values! Pretty happy with the current speed and the overall code.

Top 100 was sooo close with cutoff at 11:48 while I finished in 16 minutes (yet so far :D).

The second part was much slower in comparison to the leaderboard. The cutoff is at 21 minutes and it took me 46. I guess I lost time with the wrong IDLE condition. First, I was resetting the IDLE to False in the wrong place. Then had to change the IDLE condition to trigger only after two rounds. Finally, I was printing the packets received by the NAT instead of those sent.

in the wrong place. Then had to change the IDLE condition to trigger only after two rounds. Finally, I was printing the packets received by the NAT instead of those sent. I had a thought about my turn-based implementation while writing these notes. Implementing the solution in a fully asynchronous and parallel fashion is irrelevant.

Running a VM with a -1 is an idempotent operation, it just sets it to IDLE. What matters is that we consume the transmitted packets in the order they are enqueued to each VM. Hence, the output is fully deterministic.

Day 18