Im a highschool student and I have finally finished the first 8 days of aoc and I know it’s not anything crazy but I thought that I could still post this as an achievement as I had only gotten the 5th star last year.
My code isn’t anything grand and i know it’s ugly and unoptimized so if anyone would like to give me some feedback and code advice here’s my GitHub where I put all my solving code.
github.com/likepotatoman/AOC-2024
Because these two junction boxes were already in the same circuit, nothing happens!
connect together the 1000 pairs of junction boxes which are closest together.
I didn't expect that I would need to count the "nothing happens" as part of the 1000 connections to make for part 1. It kind of makes sense that with 1000 boxes, 1000 connections would lead to a fully connected circuit, but I think it could've been worded better
I'll first say Happy Holidays =) and thank you so much to Eric Wastl and the sponsors.
This is my first year doing AoC and I had a blast, but I've had to cheat for part 2 for the last 4 days and I'm curious about a few things.
My background is a Data Engineer/Data Architect and I'm very proficient in my field. I work mostly in pyspark and spark sql or tsql and I'm really good with object oriented coding, but all we do is ETL data in data driven pipelines. The most complicated thing I might do is join 2 large tables or need to hash PI data or assess data quality. I don't have a computer science degree, just an app dev diploma and 15 years data experience.
Because of how I've been conditioned I always land on 'brute force' first and it doesn't work for most of these problems lol. I've learned a ton doing AoC, from dijkstra to Cramer's rule. Here are my questions about this stuff.
1) Where would some of these AoC logic solutions have practical application in computer science
2) Any recommendations on gameified self learning websites/games/courses (like Advent of Code) where I can learn more about this stuff so I'm less likely to cheat next year haha.
I'm stuck on part 1 for day 6 (https://adventofcode.com/2025/day/6). The code I wrote gives the correct answer for the example input and also if I take a small portion of the puzzle input and do the calculations myself. But for some reason the total for the puzzle input is incorrect. Below is the small C# code I wrote for this. Can someone give me a hint into the right direction?
Hi! I heard about Advent of Code thanks to a ThePrimeagen video like a month ago, and today I did the first puzzle and had a lot of fun actually :)
I'm not good at coding by any means: i tinkered with arduinos some years ago and this school year (i'm 17, next year i'll go to university, and i'll study CS wohooo) we've started learning python in class. That means that my solutions are horrible tbh, since i don't know well the tools that are at my disposal (in class we have a very low level, so i'm actually the best at coding and problem solving from them, by far).
So to solve today's puzzle i saw that i needed to read strings from a file or smth. I dont know how to do that, so i just pasted the puzzle input in neovim and run a simple macro 4080 times to format it as a tuple for python.
I mean, it works... but isn't this considered a bad approach or smth?
And then, since i also needed to use the number (excluding R or L) as an int, and I didn't want to waste time learning how to remove the first character from a string or smth, i just copied the puzzle input again, and ran another simple macro 4080 times so it would format it as a tuple full of strings (removing the first character).
I think that that sucks because now the first 8167 lines of my code is just this huge list of numbers and strings. I did that very fast thanks to vim motions, yeah, but I feel like that's a bad idea in general.
Also is the nesting too bad?
So what do I do? Should I try to solve the problems "the proper way". Tbh is much easier like i just did (in part i did that because tomorrow i have two exams so i didn't want to waste a loooot of time). Still, I spent a bit more than an hour and a half on this two puzzles lmao
Sorry for the long text and thanks in advance!
Btw this is my code for the second puzzle (with the example that's 10 movements long instead of the actual puzzle input):
document =('L68', 'L30', 'R48', 'L5', 'R60', 'L55', 'L1', 'L99', 'R14', 'L82')
documentNumber =(68, 30, 48, 5, 60, 55, 1, 99, 14, 82)
password = 0
dial = 50
for i in range(len(document)):
if dial == 0: password += 1 # Removing everything but this password+=1 gives you the solution to puzzle 1 (that's why i spent much more time on the first one)
if document[i].find('R'): # Runs for L
num = documentNumber[i]
while num > 100:
num -= 100
password += 1
if dial-num < 0:
if dial != 0 and dial-num+100 !=0:
password += 1
dial = dial-num+100
continue
dial = dial-num
elif document[i].find('L'): # Runs for R
num = documentNumber[i]
while num > 100:
num -= 100
password += 1
if dial+num >= 100:
if dial != 0 and dial+num-100 !=0:
password += 1
dial = dial+num-100
continue
dial = dial+num
if dial == 0:password += 1
print(password)
It’s my first year doing AoC (and my first year as a programmer), and I’ve found the previous days to be quite manageable, even if they required a fair bit of Googling. It’s been fun stumbling across algorithms and data structures I’ve never encountered before.
But Part 2 of today’s problem really takes the prize for being too complex for a newbie like me. Even after “being dirty” and resorting to AI for an explanation, I’m still having a hard time wrapping my head around the solution.
Is there anyone here who enjoys breaking things down pedagogically and wouldn’t mind explaining it in a way that could help me start understanding the path to the solution?
class Turn {
public:
int clicks;
Direction dir;
Turn(char d, int c) {
switch (d) {
case 'L':
dir = Direction::Left;
break;
case 'R':
dir = Direction::Right;
break;
}
clicks = c;
}
};
My solution for Part1 worked so I am reasonably confident the input is parsed correctly, and my part2 solution (pasted above) works on the example provided. Where have I gone wrong?
Edit: I needed an abs() call. Thanks for the help!! Updated code:
Part2 Corrected
I'm solving this year in Agda. I'm currently trying to get the solution for day 11 part 2.
For part 2 I'm using the same code I used in part 1, but finding the paths from svr to fft/dac from fft/dac to dac/fft and then to out. Then, getting the product should be enough.
For part 1 the code runs <1s (I haven't timed it but it's pretty fast). For part 2, I can't even get the number of paths from svr to fft/dac (I know I only need to find the paths to one of the two, but I won't post which one to not give away the result). It's still running after an hour.
I'm using the {-# TERMINATING #-} flag in Agda to avoid having to deal with termination proofs, but now I'm doubting that this is correct. I'm using memoization to avoid recomputing the number of paths.
This is my code:
{-# TERMINATING #-}
countPaths : Map.Map (List String) → String → String → Map.Map ℕ → ℕ × Map.Map ℕ
countPaths adjacencies from to cache with to ≟ from
... | yes _ = 1 , Map.insert from 1 cache
... | no _ with Map.lookup cache from
... | just x = x , cache
... | nothing =
let (result , cache′) = foldl goCount (0 , cache) (fromMaybe [] (Map.lookup adjacencies from))
in result , Map.insert from result cache′
where
goCount : (ℕ × Map.Map ℕ) → String → (ℕ × Map.Map ℕ)
goCount (acc , cache) neighbor =
let (count , cache′) = countPaths adjacencies neighbor to cache
in (acc + count , cache′)
The adjacencies parameter holds a map of [String] that tells you which devices are attached to each device. from and to are the origin and final node: the from node changes as we traverse the graph, but to always stays the same.
cache is a map that tells you for each node, its distance to to. Initially, it's just an empty map.
Can you help me figure out whether my program is hanging because of a problem in my code or due to an inefficiency in the agda evaluation strategy?
Thank you.
Update: After experimenting a bit with the equivalent code in Haskell, I found out my issue has something to do with Maps being lazy in Agda. I'll have to figure out an alternative to avoid this edge case.
For part 1 of 2024's day 6 problem, I was able to get some Python code that works for the small example map they gave but not my puzzle input. As it stands I have about 100 extra locations the guard visited than I should have. I was wondering if anyone here could take a look at my code and give me a hint as to where my error is, as I am really struggling to find it. I know it has to be where my movement is programmed, I just can't figure out what part needs some tinkering. Thank you in advance!
with open('Day 6/mapinp.txt', 'r') as file:
samp_inp = file.read()
format = samp_inp.splitlines()
matrix = []
for item in format:
matrix.append(list(item))
#locate the guard, return the matrix coords and then the way the guard is pointing
def find_guard(map):
coords = []
for item in map:
if "^" in item:
coords.append(map.index(item))
coords.append(item.index("^"))
coords.append("^")
return coords
elif ">" in item:
coords.append(map.index(item))
coords.append(item.index(">"))
coords.append(">")
return coords
elif "<" in item:
coords.append(map.index(item))
coords.append(item.index("<"))
coords.append("<")
return coords
elif "v" in item:
coords.append(map.index(item))
coords.append(item.index("v"))
coords.append("v")
return coords
#nice function to track movements
def move(map):
on_map = True
step_count = 0
step_loc = []
#index error means the guard has left the map
while on_map == True:
try:
coords = find_guard(map)
if coords[2] == "^":
if map[coords[0]-1][coords[1]] == "." or map[coords[0]-1][coords[1]] == "X":
map[coords[0]][coords[1]] = "X"
map[coords[0]-1][coords[1]] = "^"
step_count += 1
loc = f"{coords[0]}, {coords[1]}"
step_loc.append(loc)
else:
map[coords[0]][coords[1]] = ">"
elif coords[2] == ">":
if map[coords[0]][coords[1]+1] == "." or map[coords[0]][coords[1]+1] == "X":
map[coords[0]][coords[1]] = "X"
map[coords[0]][coords[1] +1] = ">"
step_count += 1
loc = f"{coords[0]}, {coords[1]}"
step_loc.append(loc)
else:
map[coords[0]][coords[1]] = "v"
elif coords[2] == "v":
if map[coords[0]+1][coords[1]] == "." or map[coords[0]+1][coords[1]] == "X":
map[coords[0]][coords[1]] = "X"
map[coords[0]+1][coords[1]] = "v"
step_count += 1
loc = f"{coords[0]}, {coords[1]}"
step_loc.append(loc)
else:
map[coords[0]][coords[1]] = "<"
elif coords[2] == "<":
if map[coords[0]][coords[1]-1] == "." or map[coords[0]][coords[1]-1] == "X":
map[coords[0]][coords[1]] = "X"
map[coords[0]][coords[1] -1] = "<"
step_count += 1
loc = f"{coords[0]}, {coords[1]}"
step_loc.append(loc)
else:
map[coords[0]][coords[1]] = "^"
except IndexError:
print(f"Guard has left the premises after {step_count} steps!")
on_map = "False"
return map, step_loc
comp_map,coordinates = move(matrix)
move_counter = 0
for item in comp_map:
for pos in item:
if pos == "X" or pos == "^" or pos == "<" or pos == ">" or pos == "v":
move_counter += 1
else:
continue
print(f"The guard has visited {move_counter} distinct locations.")
I wanted to yap about my approach for this one because I think I stumbled into something kind of interesting. Initially I implemented this problem in Java. I didn't know what a Union-Find was but in retrospect I think I basically implemented one in a naive way as List<Set<>>. After reading some blogposts I wanted to try using a different approach.
After some research I realized you can call C# from PowerShell by using [System.Reflection.Assembly]. I implemented a union-find in C# and called it from Ps. It was cool initially but got super annoying because every time I want to compile my C# I have to exit the shell and re-open it because Ps has the dll open. Also, you have to use ps 7 to use a priority queue, which doesn't have a separate terminal (I think). This made iteration speed terrible because I had to exit and call pwsh.exe every time I want to compile my code.
Anyways, I wanted to ask if anyone has had any cool experiences combining interpreted langs with compiled langs in this fashion to "get the best of both worlds"
Also, my PS code is so freaking slow, especially considering that I think all the data structures are already compiled to dll (My U-f and dotnet standard lib). These aren't high-quality benchmarks; I just ran the programs 3 times consecutively.
Are there any PowerShell users that have any tips? I didn't implement path compression for the Union-Find but I doubt that's the problem compared to the O(N^2) process to build pairs
I've been going at this problem set for so long now (since it got released) and I just can't find a way to do it on my own. Going over it manually takes over 12+ hours (had to stop running it since it got stuck on the last 4 with the code I had) and I feel like even if it completes, I might not get the correct answer anyway even with the test data being correct.
Is there any way to solve this without Z3? Or is it not really do-able? I'm using GDScript for this so even if I wanted to use libraries, it's not really possible. ^^"
Looking on GitHub to other people who solved it, or even on YouTube, everybody seems to just go for Z3... This year, this really is the hardest challenge imo. A lot of them can be challenging, but I feel like this one is just impossible :/ Any advices or algorithms or something that I could look at?
My initial approach to 9B was going to be to look up a general algorithm for determining if a point lies inside a polygon and implement it, passing 2 vertices for each rectangle constructed from each pair of input vertices. If both points are inside the polygon and the rectangle is larger than the previous largest candidate, keep it else discard and rinse and repeat until I'm done.
I also thought about leveraging a library to do the work for me but I figured I'd take a crack at it myself as I like to do with AOC problems.
As I thought some more, I started to wonder if there's a special case algorithm for this problem given the constraints of the problem - the fact that the polygon is rectilinear (I learned a new word today!) and the points aren't arbitrary, in fact, they are vertices of rectangles created from the vertices of the polygon itself.
Given the nature of AOC, I suspect there might be a simpler way to solve this than the general solution but I haven't been able to work it one out yet.
Could someone please provide a hint to set me off in the right direction?
Lately there have been lots of posts following the same template: ”The AoC website tells me I should not distribute the puzzle texts or the inputs. However, I would like to do so. I came up with imaginary fair use exceptions that let me do what I want.”
And then a long thread of the OP arguing how their AoC github is useless without readme files containing the puzzle text, unit tests containing the puzzle inputs et cetera
I don’t understand how people see a kind ”Please do not redistribute” tag and think ”Surely that does not apply to me”
I didn't participate last year so maybe I missed something. I just don't remember getting locked out of submission so quickly or for so long in previous years. Seems pretty harsh, particularly when I'm fumbling for an answer and I've clearly missed something simple in my code.
EDIT: Chill with the condescension. It's not outside the realm of possibility that someone could make many well-meaning attempts to solve a challenge and simply lack some key bit of knowledge to solve it the way they want to.
All I wanted to bring up is that the lockouts feel pretty punishing - the one thing no one has talked about.
I have seen a lot of memes of people using Z3 for part 2. I tried to solve it myself using BFS and then DFS with some pruning but still couldn't get it. After 3 hours of trying to optimize it, I used Z3 and got my answer in like 20 minutes.
But since I haven't seen any solution that didn't use Z3, I am wondering how to solve it without it, one approach would be to build something similar to Z3, using matrices to solve multiple linear equations but is that really the only solution?
This year I unfortunately got filtered on the last day because I focused too much on solving the problem as described.
I tried all I could during the day, including shapes as bitmasks and a system of linear equations similar to day 10. Ultimately none of what I tried worked; either I made a mistake or something was missing.
Indeed, had I noticed I could do a bit of "pre-filtering" on the input to get rid of the obvious solutions and non-solutions, I would have probably noticed what was going on.
I guess, for my sanity next year, is there a pattern to when these twisted days happen? Or is it something you usually have to pay attention to every day?
P.S.: Not complaining, if I didn't like participating I wouldn't; it was just a bit unexpected.
Since we are a good 10 months away from the new AoC I want to start learning a fun new language to try out for next year. I love languages with interesting and fun concepts.
I am pretty fluent in C, C++, Java, Haskell, Python and Bash and currently in my 4th semester of studying CS. I love learning new programming languages and want to get into compiler design so it never hurts to have a few options. :)
2022 I did the first few days in Bash but had no time to finish because of uni - a similar story in 2023 with Haskell. 2024 I'm gonna have a bit more time on my hands though.
To give you some idea of what I am looking for in particular:
I've dabbled a bit in BQN and was originally thinking if I should give Uiua a shot for next year, but I don't like the fact that the only option for code editors are either online or some VSCode extensions that don't run on VSCodium. That pretty much rules it out for me. But I like the idea of a stack/array language.
I saw someone on our discord doing the AoC in Factor, which looked fun. That is a definite contender, although it wouldn't really be unique.
Elixir is also a contender since I enjoyed Haskell and like functional languages a lot.
Another idea I had was to do it in a sort of command-line challenge: Solving the AoC in a single command in a Linux terminal. That could be a cool challenge.
But basically any semi serious quasi eso lang suggestion is welcome. Be that stack based, array paradigm or functional. I also don't mind a little goofy fun.
Now I can already hear the crabs marching on: I don't wanna do Rust, I don't enjoy the community or politicized nature of the language much.Zig is another one of those modern languages: From my first impressions with it it seems great to use, but it's basically like a more convenient C. I'd like to get crazy though.
I got tired of tabbing to the browser to grab inputs and paste answers, so I built a CLI that does the whole loop. Then I rebuilt it in C# to learn the language. Both work end to end.
cargo run fetch -y 2015 -d 1 # puzzle text + input into cache/
cargo run solve -y 2015 -d 1 # run your solution offline
cargo run solve -y 2015 -d 1 --validate
cargo run solve -y 2015 -d 1 --submit
Output looks like:
year 2015 day 1 in 288µs (959ns parsing)
part one: 138 (correct) [216µs]
part two: 1771 (correct) [71µs]
Then --submit turns those into (new star), and running again shows (starred) since AOC only grades each part once.
The part I haven't seen other AoC tools do: --validate checks your answers against fornwall's independent solver before anything gets submitted. Wrong answers on the site cost an escalating cooldown, but the solver answers the same question as many times as you want, for free. So --submit only sends what the solver agreed with. If the solver doesn't cover the puzzle yet (live event), it submits anyway, since that's exactly when you'd be ahead of it.
Some other things it handles:
Solve fetches whatever is missing, so a fully cached run works offline with no cookie.
When part one earns a star, part two's text gets pulled in the same run.
Inputs are cached with a hash of the session that fetched them. Inputs are account specific, so switching accounts refetches instead of letting you submit an answer computed from the other account's input. That one bit me for real.
Day 25's second star is awarded, not puzzled, so the tool knows not to keep asking for its part two.
No solutions ship on main. There's a compiled template to copy for your first day, and my solutions live on a separate branch if you want examples. Inputs and puzzle text stay out of git, per the site's wishes, and it sends a User-Agent with a reachable contact.
On AI: I used it as a working partner on these repos, for doc wording, test scaffolding, and refactors I'd already designed but didn't want to push through by hand. The line I hold is understanding before generation: I write the code I want to write, which is most of it, and hand off what I could write in my sleep. Design decisions are recorded in each repo's context/ directory, including the ones that got reversed and why. Every line was written or reviewed by me.
Just wondering what size the answers folks got for part 2 mine has calculated
16895725 paths so far and still running and that's just to get paths some svr -> out. I have the following logic for my dfs:
fn depth_first_search(
node: &str,
adjacent_map: &HashMap<String, Vec<String>>,
visited
: &mut HashSet<String>,
end_node: &str,
path_count
: &mut usize,
path
: &mut Vec<String>,
required_nodes: Option<&HashSet<String>>,
unique_paths
: &mut HashSet<String>,
) -> usize {
// Placeholder DFS implementation
//println!("DFS from node: {}", node);
path
.
push
(node.to_string());
let path_string =
path
.join("->");
if
unique_paths
.contains(&path_string) {
println!("duplicate path found {:?}",
path
);
process::exit(1);
}
if node == end_node {
//check if all required nodes are in path
//println!("Reached end node: {}", node);
if let Some(required) = required_nodes {
//println!("Checking required nodes: {:?}", required);
let path_set: HashSet<String> =
path
.iter().cloned().collect();
//println!("Current path set: {:?}", path_set);
if !required.is_subset(&path_set) {
path
.
pop
();
return 0;
}
}
unique_paths
.
insert
(path_string);
*
path_count
+=
1;
//println!("Found path: {:?}", path);
println!("Total paths so far: {}", *
path_count
);
path
.
pop
();
return *
path_count
;
}
if
visited
.contains(node) {
path
.
pop
();
return 0;
}
visited
.
insert
(node.to_string());
if let Some(neighbors) = adjacent_map.get(node) {
for neighbor in neighbors {
if !
visited
.contains(neighbor) {
depth_first_search(
neighbor,
adjacent_map,
visited
,
end_node,
path_count
,
path
,
required_nodes,
unique_paths
,
);
}
}
}
path
.
pop
();
visited
.
remove
(node);
0
}
Can post more of my code if needed for this does the heavy lifting as the fun that's running endlessly. In the time I've been writing this post it now has a value of: 21776839
The number only gets up when the thing goes into 0.
What I'm doing is the next:
I take the first part of the string for each entry, then take the R or L of the string.
At the start, I have a number that starts with 0, right? Then to that number I add if the first character of the string is left, and subtract if the first character is right.
Then I have a variable that saves the last position of the knob and starts at 0.
Then once I add or subtract the knob position, I ask if the modulo of 100 is 0, or if the result is 0, then add one to the password.
Then I take the modulo of the total knob position, and if it's from L, then I just take that one and use the modulo to make it the new knob position.
If it's R, then I do the modulo of the knob position and subtract the modulo of 100 of this one from 100.