Disclaimer
This is actually the last thing I’m writing but I was proofreading the post, and since I don’t have time to really rewrite it I just wanted to say sorry if it’s a bit disjointed. I’m still trying to find the balance of technical stuff and letting my personality through with these longer posts, it’s not awful or anything but I was writing the post as each day happened so I didn’t forget anything and it definitely has a bit of a weird flow so hopefully you can bear with me as I figure this stuff out. Anyways, Enjoy!
What is advent of code?
Advent of code is an annual collection of programming challenges, much like an advent calendar that many programmers take part in. A lot of people use this as an opportunity to learn new languages or just practice programming in a more fun way. The general structure is that each day has a challenge (in the past it was all 25 days before christmas but this year it was only 12) and each challenge has two parts which each give you a gold star upon completion. At the end of the event, if you got all the stars you get to see a cool art piece like the one below (some are even animated!) and brag to all your programmer friends.
Shout out to Eric Wastl for putting in all the effort for creating the event. If you end up doing the event and enjoy it, go let him know.
Also since this isn’t a tutorial or anything, and making a tutorial would actually defeat the purpose of the event, I won’t be putting my full solutions in this post, just the interesting parts or parts I had a lot of trouble with. That being said my solutions will be on my codeberg if you want to take a look but you should do the event yourself if you haven’t already. As far as I’m aware all previous aoc events are available on the website so if you’re like me and you’ve never done one before or you see things about it and it’s not December you should still be able to do the puzzles!
Day 1(Dec 18)
Due to life circumstances, I am starting 18 days late which happens to just be enough time to complete the event before the month is over (how serendipitous). As is to be expected of a thing like this, day 1 was not too challenging for the most part so not much to say here.
D1 Part 1
The challenge for this part of day 1 was to take an input file and calculate the position of a dial on a safe based on the contents of the file. With the caveat that the real answer was actually how many times the dial landed on 0 and the dial ranges from 0 to 99. Below is an example file:
L10
R15
L2
L56
R3
...
The actual inputs were much longer than that but that’s enough to get the idea across. So for the example above with a starting position of 50 like in the puzzle, the answer would be 1.
The main difficulty of this part for me was remembering how to take inputs from a file in C since I haven’t used C in a few months so I’m a bit rusty, other than that it was pretty straighforward. On to to part 2!
D1 Part 2
Part 2 takes the same input file and base rules but now you also have to check whether the dial passes 0 at all and count that.
L51
R1
...
A rather short example but using the same rules as part 1 and the new rules, the answer for the example above from a starting position of 50 would be 2 since you pass 0 once then move and land on 0. Hopefully that explanation makes sense.
Embarassingly, I was unable to complete part 2. I’m not sure what the problem was, and I was able to get to the password - 3 but never actually the password and I’m not really sure why the specific code that got me that close… got me that close so I don’t count that. After about 5 hours of staring at the problem and getting nowhere I decided it was best to just move on and hope the next day fares better.
Note: I wasn’t really sure what would be the best way to do this since I am doing this after the first day but I still want things to make sense without too much jumping around so hopefully this isn’t too bad. fix/thoughts
Day 2(Dec 19)
Since I failed at day 1 part 2, I no longer had that worm in my brain telling me I had to get all the starts and do a perfect run so I was actually able to have fun on this puzzle. That being said, I was pretty busy today and ran out of time to complete the challenge. I could try and do it tomorrow but I would then be running a day behind and would not have a chance to attempt all of the puzzles… plus I feel like using more than 1 day to do the challenges is against the spirit of the event.
As with the first day, I feel like I’m really close to the answer and my solution worked perfectly on the example input but undercounted on the real input again and I wish I knew what little logic thing I was missing about the puzzle/code to make these work! At the very least I am consistent in the problem so far so that’s a plus I suppose. Anyways on to day 3 after some of my thoughts about this one.
D2 Part 1
The challenge for this part of day 2 was to find invalid IDs within a range of comma separated numbers, where an ID is invalid if it starts with a 0 (i.e. 0230) or is made of a sequence of digits repeated twice (i.e. 5050). Using a shortened version of the example given on the site, the following input would have 4 invalid IDs:
11-22,95-115,998-1012
The invalid IDs would 11, 22, 99, and 1010. Pretty self-explanatory.
Initially I was having an issues parsing the input because while I had unsigned int variables, I was accessing them as signed ints so I was getting some overflow problems… oops.
Side note 1
- while (fscanf(file, "%d-%d,", &start, &end) == 2)
+ while (fscanf(file, "%u-%u,", &start, &end) == 2) // fixedPart of the process for me was reversing an array of the digits in the numbers, and I finally got to use a neat trick I read like 1.5 years ago on some stackoverflow page2. By using XORs as shown in my code below, you can swap two elements in place without the use of an extra variable! Pretty pointless here other than to talk about and share, but could be useful if you’re ever working in space constrained environments like embedded.
while( left < right){
digits[left] = digits[left] ^ digits[right];
digits[right] = digits[right] ^ digits[left];
digits[left] = digits[left] ^ digits[right];
left++;
right--;
}Day 3(Dec 20)
Initially I had started working on this days part 1 in the morning but I quickly made no progress and lost motivation and developed a headache… a short nap and some pizza later I was ready to get back to work!
Full disclosure: I was a bit lost as where to start so the get_batteries() function in both parts are unfortunately partially vibe-coded. It is a tool and I understand the code so while I don’t feel great about it, I also don’t feel that bad since I’m also using a computer to do these challenges instead of by hand. That being said I would not blame you for discounting this day as not complete based on that and I will be mentioning anytime I do end up using code generated by A.I. Also, I did not use generative A.I in any of the previous challenges, those failures (and one success) are all me.
As a rule of thumb, I avoid generative A.I unless I am totally and completely stuck and no searches are able to help (like 20th page of Google and 4+ hours of searching type searches). When I do end up using it, I do my best to avoid actual code generation as much as possible and always start with assistance on the logic of problem instead. I also have UBlock set to mark the A.I sites as spam so I have to do more work to get to them which usually results in me not going to them in moments of weakness.
Anyways rant over… I just thought this was an important thing to mention and explain how/why I use it if I do.
D3 Part 1
The challenge for this part of day 3 was to supply power to an escalator to get further down in to the base by turning on batteries inside of banks such as the one below.
987654321111111
811111111111119
234234234234278
818181911112111
Each line of digits is one bank and the goal is to pick out the two numbers that create the highest “joltage”, such that the second number has to come after the first and the batteries cannot be rearranged. For example, in the banks above the best combinations would be “98”,“89”,“78”, and “92”.
I had two main problems with this part, the first being the input file size. I originally tried to make my storage a two-dimensional array which while that could work was a bit too complicated for my migrain addled brain, luckily after a bit of reading around I realized I can read any sized file with the modification below since it reads it one line at a time.
- char rows[FILE_LENGTH][LINE_LENGTH] = {0}
+ char rows[LINE_LENGTH] = {0}
- int row_count = 0;
- while(row_count < FILE_LENGTH && (fgets(rows[row_count],LINE_LENGTH,file)){
- pass += get_batteries(rows[row_count]);
- }
+ while (fgets(rows, LINE_LENGTH, file)){
+ pass += get_batteries(rows);
+ }The second problem I had was actually storing the inputs. Since the inputs were much larger than anything stock C can store numerically, I chose to store each row as an array of characters which also had the additional problem of me not knowing how to make those numerical to do the calculations. Thankfully stackoverflow and other sites like it exist so after a pretty quick search + read session, I learned that you can convert any char that happens to be a number into a numerical representation of that (in this case int) by just subtracting the ASCII value for 0 as shown below. This is a neat trick that I think I knew at some point but never used it so I forgot… anyways it’s useful.
char cnums = {'1','2','3','4'};
int nums[4] = {0};
for(int i = 0; i < 4; i++){
nums[i] = cnums[i] - '0';
}
// nums now contains {1,2,3,4} and NOT {'1','2','3','4'}I actually managed to complete this one (with assistance) so another star got! On to part 2.
D3 Part 2
This part is exactly the same as part 1 except now we are looking for the top 12 batteries to make the best combination instead of the top 2.
The actual battery picking logic is largely the same, however I needed to make the following modification to avoid overflow errors as the “joltage” values were now much much higher.
- unsigned short pass = 0;
+ unsigned long long pass = 0;Again, I was able to complete this challenge (with assistance) so another star gotten and my first full day completed! Hopefully I’m feeling a bit better mentally + physically in the following days.
Day 4(Dec 21)
Today was a day of relearning quite a few things really. Mainly the fgets() function and more on how it works and how to deal with two-dimensional arrays. This one was actually quite fun despite the issue I encountered!
Thankfully my headache did not persist to today and I had more energy so let’s get right into it!
D4 Part 1
The challenge for this part of day 4 is to take a grid of paper rolls and find all the forklift accessible rolls such that each accessible roll has fewer than 4 other rolls in adjacent positions3 where rolls are marked as @. In the example below, given by the website, there are 13 rolls accessible.
..@@.@@@@.
@@@.@.@.@@
@@@@@.@.@@
@.@@@@..@.
@@.@@@@.@@
.@@@@@@@.@
.@.@.@.@@@
@.@@@.@@@@
.@@@@@@@@.
@.@.@@@.@.
And here are what the adjacent positions are in comparison to a single roll of paper, marked by xs.
.xxx.
.x@x.
.xxx.
Since you need to compare each row with other rows, I decided that a two-dimensional array was the best way to store the input. The magical input reading from day 3 wouldn’t work for this one as that only works for reading and working on a single line at a time so it was back to the drawing board. After watching this video to get a refresher on how 2D arrays work (my main hiccup was getting rows and columns mixed up… rookie mistake), and after reading the man page for fgets(), I saw the following:
- fgets man page
- fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline.
This is actually perfect, as that means when I read in the file I only have to deal with a single layer of looping as I can just read in whole lines at a time and I don’t have to deal with EOF manually. Here’s the code I came up to deal with that.
char papers[GRID_HEIGHT][GRID_LENGTH];
...
for(int row = 0; row < GRID_HEIGHT; row++){
if(!fgets(papers[row],sizeof(papers[row]), file)){break;}
} The next step was to actually do work on the array.
The neighbour checking logic I came up with works fine (using the print statements and another function I made that prints out the whole grid I was able to manually verify that it works when whole rows are present and seen by the loop, it also works as expected on the test input given by the site) but for some reason the loop it’s inside, shown below, just skips elements and sometimes even whole rows seemingly at random. Because of this, it massively overcounts instead of undercounting like days 1 and 2… fancy.
for(int i = 0; i < GRID_HEIGHT; i++){
for(int j = 0; j < GRID_LENGTH; j++){
if(papers[i][j] != '@'){continue;}
// printf("checking roll[%d][%d]\n",i,j);
num_adjacent = 0;
if(i - 1 >= 0 && papers[i-1][j] == '@'){num_adjacent++;}
if(i - 1 >= 0 && j - 1 >= 0 && papers[i-1][j-1] == '@'){num_adjacent++;}
if(i - 1 >= 0 && j + 1 < GRID_LENGTH && papers[i-1][j+1] == '@'){num_adjacent++;}
if(j - 1 >= 0 && papers[i][j-1] == '@'){num_adjacent++;}
if(j + 1 < GRID_LENGTH && papers[i][j+1] == '@'){num_adjacent++;}
if(i + 1 < GRID_HEIGHT && papers[i+1][j] == '@'){num_adjacent++;}
if(i + 1 < GRID_HEIGHT && j - 1 >= 0 && papers[i+1][j-1] == '@'){num_adjacent++;}
if(i + 1 < GRID_HEIGHT && j + 1 < GRID_LENGTH && papers[i+1][j+1] == '@'){num_adjacent++;}
// printf("roll[%d][%d] has %d adjacent rolls\n",i,j,num_adjacent);
if(num_adjacent < 4){accessible++;}
}
}I know it’s supposed to skip over anything that isn’t an @ but it shouldn’t be skipping over any @ or whole lines and I just could not figure out why it was doing that. In my headcannon I will count this one as a success since I did solve the actual challenge part of checking neighbours, but add 1 to the unsolved logic bug counter.
Day 5(Dec 22)
Full disclosure: the get_fresh() function in part 1 has the following vibe coded line.
unsigned long long value = strtoull(line,NULL,10);As well as the structure used to complete part 1 as shown below.
typedef struct {
unsigned long long low;
unsigned long long high;
} Range;Yet again I have fallen victim to the A.I slop machine but it did actually help this time, I had no idea that the strtoull() function existed4 so I probably never would have gotten anywhere without that. I also forgot that structs existed so this was a great help in storing the ranges at single indexes in an array, since I now have that in my brain I will not have to use A.I for something like that again.
D5 Part 1
The challenge for this part of day 5 is to find the amount of fresh ingredients based on given ranges and then a separate list of ingredients to check if they exist within any of the ranges. Kind of a poor explanation but I’m tired and I’ll give the example from the site so hopefully it makes sense.
The given example from the site is as follows:
3-5
10-14
16-20
12-18
1
5
8
11
17
32
The ranges are the first set of numbers before the new line and the IDs to check are the numbers after the newline. The ranges are inclusive and can overlap so in the above example, there are 3 fresh ingredients. 5, 8, and 17 which is in ranges 16-20 AND 12-18 but since the ranges overlap the 17 is only counted once.
While I did yet again get A.I assistance to complete this part (a troubling theme I wish to obliterate), I probably never would have thought to use structs to store the start and end of the ranges since I haven’t used structs a lot in my personal projects. The logic for solving the problem is all from me since I was thinking about it all day while I was busy, I just had no idea how to parse the file to actually implement that logic. The main core of the actual problem solving part of the code is the following code block, which is really simple. It just reads each line of IDs to check and then goes through each range and checks if that ID is A: in the range and B: not already encountered since the ranges can overlap so we don’t want to overcount.
...
unsigned long long value = strtoull(line,NULL,10);
for (int i = 0; i < range_count; i++) {
if (value >= ranges[i].low && value <= ranges[i].high) {
if (!already_seen(seen, seen_count, value)) {
seen[seen_count++] = value;
printf("New valid value: %llu\n", value);
}
break;
}
}
}D5 Part 2
The challenge for this part of day 5 is mostly the same as part 1 except now instead of checking if the values are in the ranges, we are given only the ranges and must count how many values are in each range. The ranges can still overlap and are still inclusive.
3-5
10-14
16-20
12-18
Using the example from the site above, the ranges have 14 valid IDs of 3,4,5,10,11,12,13,14,15,16,17,18,19,20.
The only real problem I had was having something big enough to store the answer, I ended up using malloc() for that even though I like to avoid using the heap when possible but it was unavoidable here… at least in C and the way I was solving the problem. Higher-level languages like python don’t have this issue as they can just assign arbitrarily large values to variables which I think takes away some of the fun for certain problems like this one.
- #define MAX_RANGES 1500
+ #define MAX_RANGES 3000000
- #define LINE_LEN 64
...
- Range ranges[MAX_RANGES];
+ Range *ranges = malloc(MAX_RANGES * sizeof(Range));
...
- unsigned long long seen[1500];
+ unsigned long long *seen = malloc(MAX_RANGES * sizeof(unsigned long long));This was extremely slow, much slower than I expected it to be and after seeing that it wasn’t done after a whole night I realized that I had definitely missed something about the problem. It was already into the next day so I didn’t have time to figure out what the intended solution was. Given enough time, I’m pretty sure my solution would work but I definitely dropped the ball on this one… oops.
Day 6(Dec 23)
As the 6th day falls upon us, I am officially at the halfway mark! For those not keeping track, I’m at 4 starts (1 sans A.I) and that really bothers me so the plan for what little time I have today was to setup DNS blocking for the A.I slop generators but UBlock has once again saved my bacon. I modified my filter to include all subdomains of the sites and that just completely broke the sites which is perfect. If this is in-fact intended behaviour and reproducable, here are the filters I added to UBlock if you want to do something similar:
||chatgpt.com^
||claude.ai^
Like most people I am travelling to see family for the holidays so I may not have time to do the next couple days but I’m hoping that’s not the case.
Day 7(Dec 24)
My luck has been running dry lately it seems. After arriving at my familys’ place I was hoping to spend the nights click clacking away at the event… I was surprised in the worst way possible when a massive snow storm hit and the power went out for around 12 hours. Hooray rural power grids :sigh:
Day 8(Dec 25)
Today is the titular day! I hope you have a wonderful christmas if you celebrate it (and even if you don’t, I hope the day is well).
I won’t have any time to do anything today unfortunately but the challenge for this one seems super interesting and I’m definitely coming back to it after the event is over.
P.S. It involves euclidean distance and who doesn’t like some math :)
Day 9(Dec 26)
As seems to be the pattern for the last couple days, I was too busy to complete the day :(
D9 Part 1
The challenge for this part of day 9 is to find the largest rectangle that uses red tiles for exactly two of its opposite corners. The example input from the website shown below, would have a largest rectangle area of 50 using coordinates 2,5 and 11,1.
7,1
11,1
11,7
9,7
9,5
2,5
2,3
7,3
Below is a visual representation of the coordinates above which represent the locations of red tiles on a grid.
..............
.......#...#..
..............
..#....#......
..............
..#......#....
..............
.........#.#..
..............
I had enough time to start the challenge today and I have a general idea of how to solve it, however I feel like this is a deceptively simple problem for being this far into the event so maybe it’s a lot harder than it seems.
Day 10 to 12
I looked ahead at the problems for days 10-12 and they were problems I’m very specifically bad at and have always been bad at so I decided it would be better to just skip them and focus on solving the ones from the rest of the event and then practice some easier versions of those puzzles after the event.
Redemption?(Dec 27 to 31)
Alright it is officially day 10 of the event and as mentioned above I have chickened out of days 10-12 so let’s see about finishing as much of the earlier parts as we can before the month is over, starting with fixing the ones I did that failed.
D1P2
As mentioned in the accompanying section, I’m not sure how annoying this will be to navigate but I’m hoping this isn’t too bad as I want to keep the chronological order of things relatively consistent and accurate. Anyways you can go back to the problem statement if you want.
The troubleshooting for this started with making a little function to print what the program was getting from the input file to make sure that it matched. Doing a diff confirmed that there was no problems with the information going into the program.
./day1p2.out input.txt > output.txt
diff input.txt output.txt
# no output here which means they are the sameOk… so there’s no issues with the input which is good. Using the tried and true method of printf() debugging I was able to notice a pattern that I believe is the issue. Take a look at the following two sections of the output and see if you can notice something off.
|dial position: 000|previous position: 021|
|moving L by 624|
pos: -624
pos: -524
pos: -424
pos: -324
pos: -224
pos: -124
pos: -24
...
|dial position: 000|previous position: 019|
|moving R by 458|
pos: 458
*crossed 0*
pos: 358
*crossed 0*
pos: 258
*crossed 0*
pos: 158
*crossed 0*
Here are a few of the other inputs I found that produce the same behaviour L846,L420,L564,L547,L265,L301,L624.
The problem appears to be that when the dial is at position 0, if it moves left by more than 100 then it doesn’t count any of the times it crosses 0.
I feel quite silly having made the classic off-by-one error but I was able to look at the issue and figure out what it was so I count that as a win. Below are the main changes I had to make to fix it.
while(pos < 0){
printf("pos: %d\n",pos);
- pos +- 100;
+ pos += 99;
- if(prev > 0 && pos != 0){
+ if((prev > 0 || pos < 0) && pos != 0){
pass++;
printf("*crossed 0*\n");
}
}
- while(pos >= 100){
+ while(pos > 100){
printf("pos: %d\n",pos);
- pos -= 100;
+ pos -= 99;
if(prev < 100 && pos != 0){
pass++;
printf("*crossed 0*\n");
}
}Date fixed: Dec 27
Time to fix: ~30-45 minutes
D2P1
This one was another silly little problem, all I had to do was change the data types from unsigned int/long to unsigned long long and it worked… not sure how I didn’t think of that during the moment but oh-well. Also I thought this one looked pretty neat while it was running so here’s a little gif of the output.
Date fixed: Dec 27
Time to fix: < 2 hours (I forgot to see what time I started but I had to look at the output for a good while before I figured it out so I’m guessing over an hour)
D4P1
As with the other two fixes, let’s start with a function to print what we get and do a diff on that. Doing so results in the following snippet which I’ve reduced for readability:
...
> ...@..@@@@@@.@@@..@@@@.@@.@@@...@@@@@.@@@@...@@@@@@@@@@@.@..@@@@@.@@@@@@@@@@@@.@@.@@@..@@.@@@@@.@..@@.@.@@@@@@.@.@@@@@@@@.@@@@.@..@..@..@..
> .@.@.@..@.@.@@@@@@@@@@@@.@@.@@@@...@@@.@.@@@..@@@.@@@@...@@@@@.@....@@@@..@@@.@.@@..@@...@@@@@.@@.@@.@@@@.@.@@@@.@@.@@...@@@.@@@@.@.@@@@.@@
> @.@..@.@.@..@..@@@..@.@@@@.@@@.@@@.@@.@@.@@@.@.@@@@@..@@@@.@@@@.@@@@@@@.@@@@@@.@@@..@@.@..@.@@@.@@...@.@@@.@.@..@....@@@.@@@@.@@@@.@@@@.@@@
71,139c198,268
< @@@.@....@@@@....@@.@..@.@.@.@@@....@@@.@@@.@@@@@@@@.@@@.@@.@.@@@.@@@@.@@@.@.@.@.@.@@.@.@..@.@.@@@@@@...@.@.@..@.@.@@@@@@@.@.@.@@@@@....@.@
< @@@@...@.@..@..@..@.@@..@.@.@@@.@.@.@@@@.@.@..@...@@..@@@@.@@@.@...@@@@.@@@@.@.@.@.@@@@.@@@@@.@@.@@@@@@.@...@@.@@.@@@@.@.@@@@@@.@.@@@@..@.@
< @.@.@...@..@@.@@..@@.@@@@@.@@@@@@@@@@@.@...@.@@@@.@@@.@...@@@@.@@@@@..@@.@.@@@@@...@.@.@@@@@@@@@@@@@@@@.@@@@..@.@....@.@..@@@@@.@@@.@@.@.@@
...
< means that it’s a line from the first file that’s different and > means that it’s a line from the second file that’s different so clearly something is getting messed up in the reading of the file.
Turns out when I initially attempted this challenge, I didn’t read the fgets man page well enough because I missed this crucial detail.
- fgets man page
- … A terminating null byte (‘\0’) is stored after the last character in the buffer.
Off-by-one strikes again! After reading the man page and spotting my mistake, I made the following changes and it just works.
- #define GRID_HEIGHT 140
+ #define GRID_HEIGHT 141
- #define GRID_LENGTH 140
+ #define GRID_LENGTH 141Date fixed: Dec 29
Time to fix: ~1 hour
D5P2
Straight of the bat I know this one is not an off-by-one error or a data-type error or anything silly like that, and is instead a fundamental problem with how I chose to solve the problem… luckily I was thinking about it when I was trying to fall asleep that night and I remember what I was thinking so hopefully my new idea for how to solve it is right.
There’s 3 main steps to my new approach (only the last 2 really matter or are intersting) and they are as follows:
Step 1: The malloc() stuff isn’t really helpful here for the solution I have in mind so let’s start by getting rid of what we have and just copying part 1 as a “clean slate” to work off of.
As with the other fixes, I made a function to print what the program was getting just to make sure there wasn’t anything weird going on with the input and there wasn’t so onto the next step!
Step 2: Go through the ranges and remove any overlapping
Full disclosure: I did end up using A.I for help with the merge_ranges() function and the sort_ranges() function. Apparently I didn’t understand the problem quite as well as I thought so that’s another failure on my end, but all the other stuff was me.
This step is split into 2 steps itself which are:
- sort the ranges
This is simple conceptually, basically you just want to sort them in ascending order so that any ranges that would be within each other are close together to make the merging easier.
for (unsigned int i = 1; i < range_count; i++) {
Range prev = ranges[i];
int j = i - 1;
while (j >= 0 && ranges[j].low > prev.low) {
ranges[j + 1] = ranges[j];
j--;
}
ranges[j + 1] = prev;
}This is the less interesting of the two functions in my opinion, it’s a very simple compare one at a time and swap algorithm. I was planning on reimplementing that as quicksort but I couldn’t figure out how to do that while using the Range struct so I’ll work on that in the future at some point.
- merge the ranges
After the ranges are sorted, you want to merge the ranges so that there is no more overlap between any of them.
unsigned int new_count = 0;
if (range_count == 0){return 0;}
for (unsigned int i = 1; i < range_count; i++) {
if (ranges[new_count].high + 1 >= ranges[i].low) {
if (ranges[i].high > ranges[new_count].high) {ranges[new_count].high = ranges[i].high;}
}
else {
new_count++;
ranges[new_count] = ranges[i];
}
}
return new_count + 1;
}I’m not really sure what to say here, it’s a simple compare and swap as well. Since we are getting rid of the overlapping ranges, we have a new_count variable here to set the range_count after the merge so that we work on the right amount of ranges when counting IDs later.
I also just feel stupid because I couldn’t figure out how to fix the one actual problem of the challenges I was fixing. I guess that’s what learning is but man does it feel bad sometimes.
Step 3: Find all the invalid IDs
Finding all the invalid IDs is pretty simple once the overlapping ranges are removed. Since the ranges are inclusive and this part just wants the total number of IDs in each range (added to a total), you can do \[(end + 1) - start = total\_in\_range\]
Note the “+ 1” here, that’s required for this to work with how I’ve done it. I’m sure anyone reading this knows why but if you’ve somehow ended up here and don’t have an idea of how stuff like this works, it’s not too bad. Since the ranges are inclusive you need to add 1 to get the final number in the range i.e. there are 8 numbers in the range 3-10 but \(10 - 3 = 7\). so you would need to do \((10 + 1) - 3\) to get the right answer of 8.
I’m sure there are better ways to solve this, but this was the first thing that came to mind.
Also sorry that this part is a bit tutorial-y… I’m not really sure how else I could write it while still making some sense and covering how I did the thing. Maybe that just comes with practice.
Date fixed: Dec 31
Time to fix: ~2.5 hours
Takeaways
There are a few takeaways from this that I think are important.. and slightly obvious in hindsight:
programming and problem solving are similar to muscles, and just like muscles, the less you use them to the worse you get at using them over time
being able to search for things and keep an open mind about how problems should be looked at is a massive help
not taking things too seriously makes stuff like this way more fun
making programs from tutorials or programs that only take small amounts of user input (most of my experience) does not really prepare you for “real” problems. I wouldn’t call the problems in this event real per se but they are certainly more reflective of problems you would encounter in the real world
knowing how to make algorithms/what algorithms are available for use is essential
time management is a lot harder to predict than you usually expect
learning and practicing how to debug, whether that be printf-ing everywhere or with something like gdb, can be very helpful
taking breaks is very important (I’m a bit embarrased that the first 3 fixes were solved so easy when I could have finished them on the day if I had taken proper breaks)
you should ALWAYS initialize variables when you make them. At least in a lower level language like C, not doing so poses a huge issue with trying to work on something and then there’s a bunch of junk data (that was actually part of the problem with day 4 as well).
Conclusion
As is tradition, thank you for reading! I’m a bit disappointed with how much I was able to complete but it was my first time doing an event like this so I’m not too bummed about it (I also had much less time than I was expecting, maybe I shouldn’t start stuff like this during the busy times of the holidays. Hindsight is 20/20 and all that)… that being said, I definitely need to work on my problem solving and critical thinking skills since those don’t get much exercise in my real life and I think that shows with my performance here. I did end up having fun though and look forward to doing better next year :D
For those who haven’t been keeping track, I got 08/24 stars (04/24 sans A.I). Also here’s my artwork.
I highly recommend you give it a shot yourself if you haven’t already. Happy holidays and I hope we all have a great start to the new year!
Footnotes
During the writing of this I learned that diff syntax is supported in plain markdown which is pretty cool! I thought that was only in one of the many extended markdowns like commonmark.↩︎
I was re-reading this post on day 4 just to make I haven’t missed anything so far and I’m not sure if it was exactly this one that I read, but here’s a stackoverlow page that explains the XOR swap pretty well if you were curious about that.↩︎
Apparently this is a very common type of thing called a Moore neighbourhood which comes from cellular automata and is a really cool subject.↩︎
I feel like I am breaking my legs just to use crutches in using these tools but I also feel like it’s unrealistic to read the entire spec of a language just to find one specific function. If you are in The Space TM and are willing to share some advice on how to manage this, I would love to hear it!↩︎