cacheson

joined 2 years ago
[–] cacheson@kbin.social 2 points 1 year ago

Nim

Part 1 was pretty straightforward. For part 2 I made an ItemRange type that's just one integer range for each attribute. I also made a split function that returns two ItemRange objects, one for the values that match the specified rule, and the others for the unmatched values. When iterating through the workflows, I start a new recursion branch to process any matching values, and continue stepping through with the unmatched values until none remain or they're accepted/rejected.

[–] cacheson@kbin.social 1 points 1 year ago

Yeah, I read up on ear clipping for a small game dev project a while back, though I don't remember if I actually ended up using it. So my solution is inspired by what I remember of that.

[–] cacheson@kbin.social 2 points 1 year ago

Yep, I figure it's good exercise to make me think through the problems thoroughly.

[–] cacheson@kbin.social 3 points 1 year ago (2 children)

Shoelace formula

This would have been really useful to know about. I've committed to a certain level of wheel-reinvention for this event unless I get really stuck, but I'm sure it'll come up again in the future.

[–] cacheson@kbin.social 2 points 1 year ago* (last edited 1 year ago) (3 children)

Nim

I am not making good time on these anymore.

For part 1, I walked through the dig plan instructions, keeping track of the highest and lowest x and y values reached, and used those to create a character grid, with an extra 1 tile border around it. Walked the instructions again to plot out the trench with #, flood-filled the exterior with O, and then counted the non-O tiles. Sort of similar to the pipe maze problem.

This approach wouldn't have been viable for part 2, due to the scale of the numbers involved. Instead I counted the number of left and right turns in the trench to determine whether it was being dug in a clockwise or counterclockwise direction, and assumed that there were no intersections. I then made a polygon that followed the outer edge of the trench. Wherever there was a run of 3 inward turns in a row, that meant there was a rectangular protrusion that could be chopped off of the main polygon. Repeatedly chopping these off eventually turns the polygon into a rectangle, so it's just a matter of adding up the area of each. This worked great for the example input.

Unfortunately when I ran it on the actual input, I ran out of sets of inward turns early, leaving an "inside out" polygon. I thought this meant that the input must have intersections in it that I would have to untwist somehow. To keep this short, after a long debugging process I figured out that I was introducing intersections during the chopping process. The chopped regions can have additional trench inside of them, which results in those parts ending up outside of the reduced polygon. I solved this by chopping off the narrowest protrusions first.

[–] cacheson@kbin.social 1 points 1 year ago* (last edited 1 year ago) (1 children)

Nim

Another tough one. Judging by the relative lack of comments here, I wasn't the only one that had trouble. For me this one was less frustrating and more interesting than day 12, though.

I solved part 1 by doing a recursive depth-first search, biasing towards a zigzag path directly to the goal in order to establish a baseline path cost. Path branches that got more expensive than the current best path terminated early. I also stored direction, speed, and heat loss data for each tile entered. Any path branch that entered a tile in the same direction and at the same (or greater) speed as a previous path was terminated, unless it had a lower temperature loss.

This ran pretty slowly, taking around an hour to finish. I took a break and just let it run. Once it completed, it had gotten pretty late, so I did a quick naive modification for part 2 to account for the new movement restrictions, and let that run overnight. The next day it was still running, so I spent some time trying to think of a way to speed it up. Didn't really get anywhere on my own, so I started reading up on A* to refresh my memory on how it worked.

The solution that I arrived at for the rewrite was to use Dijkstra's algorithm to pre-compute a map of what the minimum possible costs would be from each tile to the goal, if adjacent tiles could be moved to without restriction. I then used that as the heuristic for A*. While I was writing this, the original part 2 program did finish and gave the correct answer. Since I was already this far in though, I figured I'd finish the rewrite anyway.

The new program got the wrong answer, but did so very quickly. It turned out that I had a bug in my Dijkstra map. I was sorting the node queue by the currently computed cost to move from that node to the goal, when it instead should have been sorted by that plus the cost to enter that node from a neighbor. Since the node at the head of the queue is removed and marked as finalized on each iteration, some nodes were being finalized before their actual minimum costs were found.

When using the A* algorithm, you usually want your heuristic cost estimate to underestimate the actual cost to reach the goal from a given node. If it overestimates instead, the algorithm will overlook routes that are potentially more optimal than the computed route. This can be useful if you want to find a "good enough" route quickly, but in this case we need the actual best path.

[–] cacheson@kbin.social 3 points 1 year ago* (last edited 1 year ago) (1 children)

Nim

I'm caught up!

This one was pretty straighforward. Iterate through the beam path, recursively creating new beams when you hit splitters. The only gotcha is that you need a way to detect infinite loops that can be created by splitters. I opted to record energized non-special tiles as - or |, depending on which way the beam was traveling, and then abort any path that retreads those tiles in the same way. I meant to also use + for where the beams cross, but I forgot and it turned out not to be necessary.

Part 2 was pretty trivial once the code for part 1 was written.

[–] cacheson@kbin.social 2 points 1 year ago

Nim

Almost caught up. Not much to say about this one. Part 1 was a freebie. Part 2 had a convoluted description, but was still pretty easy.

[–] cacheson@kbin.social 2 points 1 year ago (1 children)

Nim

Getting caught up slowly after spending way too long on day 12. I'll be busy this weekend though, so I'll probably fall further behind.

Part 2 looked daunting at first, as I knew brute-forcing 1 billion iterations wouldn't be practical. I did some premature optimization anyway, pre-calculating north/south and east/west runs in which the round rocks would be able to travel.

At first I figured maybe the rocks would eventually reach a stable configuration, so I added a check to detect if the current iteration matches the previous one. It never triggered, so I dumped some of the grid states and it became obvious that there was a cycle occurring. I probably should have guessed this in advance. The spin cycle is effectively a pseudorandom number generator, and all PRNGs eventually cycle. Good PRNGs have a very long cycle length, but this one isn't very good.

I added a hash table, mapping the state of each iteration to the next one. Once a value is added that already exists in the table as a key, there's a complete cycle. At that point it's just a matter of walking the cycle to determine it's length, and calculating from there.

[–] cacheson@kbin.social 1 points 1 year ago (1 children)

Nim

This one was a nice change of pace after the disaster of day 12. For part 1 I kept a list of valid column indexes, and checked those columns in each row for reflections, eliminating columns from the list as I went. To find vertical reflections, I just transposed the grid first.

Part 2 looked daunting at first, but I just needed to add a smudges counter to each column candidate, eliminating them when their counter reaches 2. For scoring, just count the 1-smudge columns.

 

Just found a place to post my more risque anime memes. It has a "no genitals" rule, so not for outright porn:

 

I just made a very large update to the list of specialized instances. It's now about 3 times the size! I normally won't be making new posts here for updates, but this was a really big one:

 

Two communities that don't seem to have been posted here yet:

Animemes - A community for anime memes!

And:

anime_irl - me_irl, but anime

1
submitted 2 years ago* (last edited 2 years ago) by cacheson@kbin.social to c/nim@programming.dev
 

I've finally managed to join this community from kbin, seems we were having federation problems with programming.dev.

So anyway, what sorts of projects are you all using Nim for?

Edit: Post isn't propagating. Maybe this edit will help?

 

I'm changing my stance on the whole Meta/project92 thing after reading this article. I think the entire* fediverse should block project92 by default. Later, some instances can re-evaluate whether to maintain those blocks, once we have a better idea of what the benefits and consequences of federating will be:

Of course, it's possible to work with companies you don't trust. Still, a strategy of trusting the company you don't trust until you actually catch them trying to screw you over is ... risky. There's a lot to be said for the approach scicomm.xyz describes as "prudently defensive" in Meta on the Fediverse: to block or not to block?: "block proactively and, if none of the anticipated problems materialise within time, consider removing the block." Georg of lediver.se frames it similarly:

We will do the watch-and-see strategy on our instance in regards to #meta: block them, watch them, and if they behave (hahahahaha) we will see if we unblock them or not. No promise though

Previously, I'd thought "some block, some federate" would be the best approach, as described in this post by @atomicpoet:

My stance towards Meta is that the Fediverse needs two types of servers:

  1. Lobby servers that explicitly federate with Meta for the purposes of moving people from Meta to the rest of the Fediverse

  2. Exit servers that explicitly defederate with Meta for the purposes of keeping portions of the Fediverse out of reach from Meta

Both approaches not only can co-exist with each other, they might just be complementary.

People who use Meta need a way to migrate towards a space that is friendly, easy-to-use, and allows them to port their social graph.

But People also need a space that’s free from Meta, and allows them to exist beyond the eye of Zuckerberg.

Guess what? People who use Meta now might want to be invisible to Meta later. And people who dislike Meta might need a bridge to contact friends and family through some mechanism that still allows them to communicate beyond Meta’s control.

And thankfully, the Fediverse allows for this.

32
L O A F (media.kbin.social)
 
 

/m/politics is basically unmoderated, and the trolls and other ne'er-do-wells are starting to find it. I'm not even particularly interested in following it, but that's one topic that you don't want to leave unmoderated. It's a troll magnet for obvious reasons, and that starts to affect the rest of the instance (and the fediverse) if there isn't anyone enforcing some sort of decorum.

@ernest I know you're ridiculously busy right now, but could you find a moment to appoint someone to recruit a mod team for /m/politics? I'd be willing to do the recruiting if you don't have any better candidates, but I wouldn't want to remain on as a moderator after that's done.

Alternatively does anyone here actively want the job?

view more: ‹ prev next ›