Day 6: Guard Gallivant
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465
38 Comments
Pyro@programming.dev · 5 pts · 1y
Python
Part 1: Simulate the guard's walk, keeping track of visited positions
Part 2: Semi brute-force. Try to place an obstacle at every valid position in the guard's original path and see if it leads to a loop.
CameronDev@programming.dev · 3 pts · 1y
How long did brute force take? Mine was 9s on an m1 with rust.
Deebster@programming.dev · 3 pts · 1y
My rust code ran in 6s on my phone (Samsung A35 running under Termux). When I'm back at a computer it'd be interesting to compare times properly.
Pyro@programming.dev · 2 pts · 1y
About 15-20 seconds, not too bad.
CameronDev@programming.dev · 1 pts · 1y
I got mine down to 3s, but it wasn't a very smart loop detection. All I did was count steps and stop after 10000. The 9 second run was 100000 steps, which is obviously a bit excessive.
Does save iterating over the list of past visits, so probably a good shortcut.
TunaCowboy@lemmy.world · 1 pts · 1y
That's about how long it takes for my python solution to complete.
CameronDev@programming.dev · 2 pts · 1y
How did you detect loops? I just ran for 100000 steps to see if I escaped, got my time down to 3s by doing only 10000 steps.
Leavingoldhabits@lemmy.world · 2 pts · 1y
Not who you asked but: I save coordinates and direction into a vector each time the guard faces a #. Also every time the guard faces a #, I check if the position exists in the vector, if true, itβs an infinite loop. 78ms rust aolution.
CameronDev@programming.dev · 1 pts · 1y
That's probably quite optimal, compared with checking every state in the path, or running off a fixed number of steps
TunaCowboy@lemmy.world · 2 pts · 1y
I added each visited position/direction to a set, and when a 'state' is reached again you have entered a loop:
You can view my full solution here.
iAvicenna@lemmy.world · 1 pts · 1y
I did a similar approach (place obstacles on guards path). Takes about
80s10-15s in 11th Gen Intel(R) Core(TM) i7-11800H. Motivated by the code above, I also restricted the search to start right before the obstacle rather than the whole path which took it down from 80s to 10-15sVegOwOtenks@lemmy.world · 4 pts · 1y
Haskell
This one was fun, I think I wrote my first lazy infinite loop I cancel out at runtime, lost some time because I had misread the requirements on turning right.
Runs in 45 seconds on my Laptop in power-saver mode, which isn't very fast I fear.
lwhjp@lemmy.sdf.org · 4 pts · 1y
Haskell
This was a fun one! Infinite loops, performance concerns and so on. Part 2 could be made a bit faster with a recursive approach (I think), but this is good enough for me. Lost quite a bit of time with an incorrect
walkfunction that passed the test data and part 1 but not part 2.Gobbel2000@programming.dev · 4 pts · 1y
Rust
In part 2 it took me some time to figure out that I cannot immediately move after turning, but then it worked fairly well. As a slight optimization I check only the places that were visited without obstacles (the solution from part 1). With this, part 2 takes 52ms.
::: spoiler Solution
:::
also on github
hades@lemm.ee · 4 pts · 1y
ace@lemmy.ananace.dev · 4 pts · 1y
Not a big fan of this one, felt far too much like brute force for my liking.
At least it works with
AsParallel...::: spoiler C#
:::
Deebster@programming.dev · 3 pts · 1y
Rust
Only part 1 because I'm meant to be leaving for a holiday in a few hours and haven't packed yet. Part two looks simple enough to add:::: spoiler part 2 plan Change seen positions set to include direction, if pos+dir already seen then it's a loop. Test all spaces. :::
Edit: I did the change on my phone (which was painful).
JRaccoon@discuss.tchncs.de · 3 pts · 1y
TypeScript
::: spoiler The code
:::
Leavingoldhabits@lemmy.world · 3 pts · 1y
Rust
This one was the first real think for this year, but I ended up brute forcing it, placing a β#β in every position and checking. part 2 runs in about
380ms78ms (after reducing the amount β#β-placements to only where the guard walks) on my 2011 core i-7, so Iβm happy, even though it feels like I could have been smarter.Part 1 Part 2
ximtor@lemm.ee · 2 pts · 1y
I am doing the same principle brute force but it takes ~7 seconds oO
Is using a
HashSet<(Pos, Dir)>for the loop detection so expensive? My CPU shouldn't be THAT bad..Part one around 7ms.
Also curious that i have not seen someone mention a more efficient approach, there gotta be one?
sjmulder@lemmy.sdf.org · 3 pts · 1y
I draw
^>v<characters on the grid while walking, so then it's a direct array lookup (instead of a hashtable). The representation could be better though, some kind of bitmask would beat checking against a bunch of characters.ximtor@lemm.ee · 1 pts · 1y
I dont change the map, i just record the steps in the hashtable. But maybe drawing on the map is indeed shaving some time off, thanks for the input :)
sjmulder@lemmy.sdf.org · 1 pts · 1y
It probably wonβt matter a whole deal but array indexing involves no comparisons or searches. And I found it convenient too!
Leavingoldhabits@lemmy.world · 2 pts · 1y
Iβd like to see your solution in total. Iβm not too familiar with the nuts and bolts, but hash set is quite a bit more expensive than a simple vector, thereβs a bunch of overhead incurred when executing the hashing and placing of the data, and when repeating a few thousand times it sure adds up. My part one hovers around 600 microseconds.
ximtor@lemm.ee · 2 pts · 1y
I set it up a bit like a game, https://pastebin.com/FGA6E7fA
Ohhh, that says my part 1 is slow already, i was sure my approach for 2 was the problem. Good to know!
aoidenpa@lemmy.world · 2 pts · 1y
I created rows and cols vecs that keep places of blocks. When moving, I binary search the row or col, find the block that stops me. So moving whole sections at once. Otherwise used HashSet of pos and dir like you. Also in part 2, place the new block only on the path I take in part1. Part 2 is 26ms.
code
ximtor@lemm.ee · 2 pts · 1y
The binary search sounds smart, would reduce the pathing quite a bit i guess :)
Part 2 i approached quite the same i think, was only a couple lines of code additionally. But running 5ms 5000 times is also gonna take a while..
ximtor@lemm.ee · 1 pts · 1y
Alright, I completely forgot about
--releasebecause i normally use just to run my stuff. That brings part 2 down to around 400ms, i am okay with that for now :Dwer2@lemm.ee · 3 pts · 1y
Lisp
Brute forced part 2, but got a lot of reuse from part 1.
::: spoiler Part 1 and 2
:::
Rin@lemm.ee · 2 pts · 1y
TunaCowboy@lemmy.world · 2 pts · 1y
python
Takes around 10s on my machine. I came up 10 short at first for part two and then realized sometimes you have to turn multiple times to avoid an obstacle.
::: spoiler solution
:::
proved_unglue@programming.dev · 2 pts · 1y
Kotlin
Not much inspiration. Brute forcing my way through today's level.
::: spoiler Solution
:::
mykl@lemmy.world · 2 pts · 1y
Dart
Oof, simple rules can really trip you up if you don't pay attention.
This takes seconds to run so it's clearly not the right approach, but it get the right answers, so...(edit) There's an interesting range of times from others as well, so it probably only requires a little more attention to get the time down, but maybe not today...
::: spoiler Click to reveal 60 lines of solution.
:::
sjmulder@lemmy.sdf.org · 2 pts · 1y
C
Got super stumped on part 2. I'd add an obstacle for every tile on the path of part 1 but I kept getting wrong results, even after fixing some edge cases. Spent too much time looking at terminal dumps and mp4 visualisations.
Eventually I gave up and wrote a for(y) for(x) loop, trying an obstacle in every possible tile, and that gave the correct answer. Even that brute force took only 2.5 ish seconds on my 2015 PC! But having that solution allowed me to narrow it down again to a reasonably efficient version similar to what I had before. Still I don't know where I went wrong the first time.
::: spoiler Code
:::
https://github.com/sjmulder/aoc/blob/master/2024/c/day06.c
janAkali@lemmy.one · 2 pts · 1y
Nim
Not the prettiest code, but it runs in 3 seconds. For part 2 I just place an obstacle at every position guard visited in part 1.
Edit: made
stepprocedure more readable.Codeberg repo
the_beber@lemm.ee · 1 pts · 1y
I'm not proud of it.
I have a conjecture though, that any looping solution, obtained by adding one obstacle, would eventually lead to a rectangular loop. That may lead to a non brute-force solution. It's quite hard to prove rigorously though. (Maybe proving, that the loop has to be convex, which is an equivalent statement here, is easier? You can also find matrix representations of the guard's state changes, if that helps.)
Maybe some of the more mathematically inclined people here can try proving or disproving that.
::: spoiler Anyways, here is my current solution in Kotlin:
:::
I also have a repo.
TunaCowboy@lemmy.world · 1 pts · 1y
bugsmith@programming.dev · 1 pts · 1y
Gleam
Late as usual. This one challenged me. Functional programming is a lot of fun, but it's kicking my ass.
Quant@programming.dev · 1 pts · 1y
Uiua
Part one was simple enough. Part two nearly made me give up.
Part two has the most ugly and least performant code I've made in uiua so far but it gets the job done and that's all I care about for now.
Run with example input here
Andy@programming.dev · 1 pts · 1y
Factor
::: spoiler spoiler
:::
Andy@programming.dev · 1 pts · 1y
Nothing smart to see here. I may revisit this when I give up on future days.