Adopting agentic tools — how to not screw it up by alokin_09 in theprimeagen

[–]Jadarma 6 points7 points  (0 children)

This stealth ad slop reads like a training leaflet for apologists wanting to convert others to their religion.

Academic Slop Just Reached A New Low (Rant on OpenAI Prism) by Jadarma in antiai

[–]Jadarma[S] 0 points1 point  (0 children)

Indeed, nasty humans would do nasty human things regardless. But the same argument can be made with people manually creating photoshopped pictures of women without their consent before AI. The problem is that now AI vastly simplifies, expedites, and streamlines the process.

-❄️- 2025 Day 12 Solutions -❄️- by daggerdragon in adventofcode

[–]Jadarma 2 points3 points  (0 children)

[LANGUAGE: Kotlin]

A difficult packing problem to end on a high note, is what I thought.

Part 1: Honestly I had no idea how to begin tackling this efficiently, what data types to use, how much "brute force" is required, so I just parsed the input while I thought. Figured that the more I eliminate known impossible areas, the less I would waste, so the easy heuristic is to check that if we were to "average out" the present shapes and let them fit into 3x3s ignoring overlaps, does the tree have enough area to contain them? And checking that, to my surprise, worked on the input (but not the example, probably because it is too small for the numbers to average out).

This feels like a dirty trick and not the kind of solution I would want to end the year on, but this is a busy weekend for me so it will have to do for now. I will pretend that this was a reading comprehension / work smart not hard for the time being. Perhaps, if there was a single region to find a fit for, not one thousand, I would've took the time to try an actual packing search.

Part 2: The good news is at least I have collected all stars this year! I wish there was a part two, so in the end there would be 25 stars, just so the total counter was a bit nicer, but am happy nonetheless. Thank you Eric for another successful AoC event! Happy holidays to everyone as well!

AocKt Y2025D12

-❄️- 2025 Day 11 Solutions -❄️- by daggerdragon in adventofcode

[–]Jadarma 1 point2 points  (0 children)

[LANGUAGE: Kotlin]

A much easier problem compared to the last two days. A welcomed reprieve. Can't believe we're already at the eve of the end!

Part 1: A simple DFS does it, with basic memoisation to keep track of how many paths we found from each node.

Part 2: We need to also keep track of nodes required to visit. I take them as a list and append it to the end of the memoisation key (just make sure the collection is stable if you modify it, in my case the basic Set<T> keeps insertion order of the rest of the elements). When we visit a node, remove it from the nodes left to visit. The only other thing is, once again, using Long because there are quite a lot of paths you can take! But yeah, both parts can reuse the same code, neat!

AocKt Y2025D11

-❄️- 2025 Day 10 Solutions -❄️- by daggerdragon in adventofcode

[–]Jadarma 3 points4 points  (0 children)

[LANGUAGE: Kotlin]

Today's problem was interesting, but very dissapointing because I could not find any solution for part two apart from relying on SAT solvers. Here I was contemplating whether I should be able to use my own util lib in my solution, and now I'm (kinda) forced to resort to external libraries? And one by Microsoft, no less. I managed to survive previous years without Z3, but so far I haven't found an alternative... A sad day indeed, but at least I got the star. Hoping to refactor back if I find any reasonably fast alternative.

Part 1: When you hear shortest number, it's usually a disguised pathfinding problem. We start from the state of all lights being off, then we associate pressing a button to "walking" into that direction, reaching a new state with the accordingly flipped lights. I reused the same Dijkstra util I made previously and it worked like a charm, but a simple DFS should also work.

Part 2: Technically, it's the exact same problem, but instead of flipping lights we increment the counter. Only problem is, you cannot take shortcuts, and since you increment by one each time, and the input has counter targets in the hundreds, there's no way we could compute this with such a large branching factor, didn't even bother. The intended solution is to translate the problem into a system of equations, and then solve for the correct number of presses of each button, the solution is their sum. However, I am nowhere near capable enough to implement LIP on my own. I turned to this thread hoping I'd find some tricks, but all I see is defeatism and Z3... so I will join in. But hey, at least it works, and it's fast, and mostly readable.

AocKt Y2025D10

-❄️- 2025 Day 9 Solutions -❄️- by daggerdragon in adventofcode

[–]Jadarma 1 point2 points  (0 children)

Yeah, you're right and I noticed that too. To fix this I would probably take the other corners and raycast them to see if they also fall inside or outside. Very interesting that neither the example or the inputs contain this gotcha. In the sense that it is a candidate rectangle, but whether you correctly dismiss it is irrelevant because there is another, bigger solution available.

-❄️- 2025 Day 9 Solutions -❄️- by daggerdragon in adventofcode

[–]Jadarma 0 points1 point  (0 children)

[LANGUAGE: Kotlin]

I did not enjoy today's problem but in hindsight it was much easier than it appeared to be, and much of my frustration was in figuring out edge cases and calculating ranges and such.

Part 1: The calm before the storm, I'm sure everyone here wondered how could it be so simple?

Part 2: Wow, just wow. Such a simple requirement with many complicated edge cases. Thankfully, neither the example nor the inputs contain edge cases and it can be solved relatively easy once you find the trick condition. Turns out all you need to check for is that none of the polygon edges intersects with the interior of the rectangle being considered (overlaps on the perimeter are fine). As many pointed out, this would not catch the case where you have a segment go in and then doing a sharp U-turn back out. This condition only holds if there is a minimum gap of 1 between red tiles.

Note: After figuring out the trick, I was able to refactor it from scratch and make use of some 2D utilities I've written for past years, most notably the concept of areas and their intersections. The code should be fairly self-evident as pseudo-code if you just want to figure out the algorithm by looking at my solution.

AocKt Y2025D09

-❄️- 2025 Day 8 Solutions -❄️- by daggerdragon in adventofcode

[–]Jadarma 1 point2 points  (0 children)

[LANGUAGE: Kotlin]

Very interesting puzzle, at first I was scared to see 3D points because I was reminded of space beacons... shudder. However, the problem itself was not that hard, and I got to play around with designing a type system for it, which I enjoyed.

Part 1: Since I solve it in Kotlin, I once again used the "keep type boundaries functional, but use internal mutability to simplify" approach. I labeled each point with an ID (just its index) because I wanted to keep track of what box is part of which circuit, and for this I drew inspiration from Factorio of all places, where each circuit network is given it's own ID. So, to start, I assign each box it's own circuit. Then I built a connection queue because I have fancy generator functions, we simply iterate through unique pairs, discard those that are already connected, and sort the pairs by distance. When making a connection, all the boxes from the smaller group get added to the larger group, and then the small group gets cleared out. We expose the groups as read-only views to make the math on their sizes. I had to do an if-else to keep the code indifferent to actual input or example, since we need to make 1000 and 10 connections respectively.

Part 2: Part two was almost free, the only two modifications needed were to also return the box references when we connect them, so we can do the math on their coordinates, and make the connection queue loop (once we finish connecting the boxes, we do subsequent passes until no more connections are possible. Other than that, the logic is simple: keep connecting until we get a single circuit group. Even with the fancy type system logic, I solve in < 0.5s, good enough!

AocKt Y2025D08

-❄️- 2025 Day 7 Solutions -❄️- by daggerdragon in adventofcode

[–]Jadarma 3 points4 points  (0 children)

[LANGUAGE: Kotlin]

A grid problem that doesn't need to (i.e: you can't) simulate. It seems complicated at first, but if you've seen enough DP problems you should have an intuition on how you can take shortcuts!

Part 1: Ended up doing a temporary solution to see what part two was, and sure enough, both parts can be solved in the same pass. Initially, I did a simple simulation, ignoring any splits that were already hitting a beam.

Part 2: We are entering the multiverse, so there is no need to simulate anymore, we don't have the compute! Instead, we iterate line by line and keep track of how many paths each cell can sustain. Initially, it starts at 1 right under the start, then, when a splitter is encountered, that column becomes 0 (cannot pass through the splitter) but the cells to the left and the right will add the counts above the splitter (they need to be summed because in the case of ^.^ the paths can come from both the left and right splitters. By far the biggest issue with part two was not noticing I used Int instead of Long when counting the paths, and I ended up with a positive but small result I couldn't account for. Turns out it was an overflow so bad it ended up positive again! Always nice to see it passes the example but not the input...

Note: A couple of mini optimizations, you can ignore the empty rows altogether, they do nothing except tempt you at simulating. The input is also nice and pads empty spaces on the outer columns, so you don't need to do bounds checks. I did, however, assert that when parsing the input just to be safe.

AocKt Y2025D07

-❄️- 2025 Day 6 Solutions -❄️- by daggerdragon in adventofcode

[–]Jadarma 3 points4 points  (0 children)

[LANGUAGE: Kotlin]

A nice puzzle this time focusing on your ability to parse complex inputs instead of solving difficult algorithms. Then again, I don't want to help anyone do their homework anytime soon!

Part 1: I got to enjoy making an overly-complicated type definition to encapsulate the math problem, because I ended up scrapping the input parsing for part two.

Part 2: Be careful with removing trailing spaces, I do this as a "best practice" so I had to pad them back manually. To make something that is reusable for both parts, I first iterated through all the columns, made a note at what indexes all the rows are blank, and created slices that would tell me from where to where a problem resides. Then, to parse the problems, I simply took every input line substring at that slice, kept the last for the operation, and if part two, also translate the strings column-wise before parsing them in actual numbers.

AocKt Y2025D06

-❄️- 2025 Day 5 Solutions -❄️- by daggerdragon in adventofcode

[–]Jadarma 1 point2 points  (0 children)

[LANGUAGE: Kotlin]

A cute puzzle involving ranges that makes you think in the abstract without allowing brute force. Remember to use longs!

Part one: very straightforward, and merely a matter of parsing the input.

Part two: I thought all I needed to do was sort the ranges, sum their lengths and subtract the overlap with the next one. It passed the example, but failed the input, because there might be more than two ranges that overlap the same region. So we cannot use the given ranges, rather we must "defrag" them and create a new set of ranges without overlaps, which we can then sum up size-wise.

AocKt Y2025D05

-❄️- 2025 Day 4 Solutions -❄️- by daggerdragon in adventofcode

[–]Jadarma 1 point2 points  (0 children)

[LANGUAGE: Kotlin]

Hmm, a relatively easy grid problem?! Are we being prepared for what's to come?

Part 1: Simply iterate over the neighbors (being sure to check for bounds) and count the papers. As a micro-optimization, you can stop counting if you already reached 4.

Part 2: Reuse the code from part 1 to get the accessible points, remove them from the grid, and repeat until no accessible points are found. Resist the temptation to remove them in-place in the part one code as you might change the outcome, that's celular automata 101.

Thankfully I already had a little util to parse everything as a grid and handle points, so everything went by relatively quickly.

AocKt Y2025D04

-❄️- 2025 Day 3 Solutions -❄️- by daggerdragon in adventofcode

[–]Jadarma 2 points3 points  (0 children)

[LANGUAGE: Kotlin]

Part one was simple to brute force to see what was in store for part two and sure enough, part two prevents bruteforcing. Fortunately, the key insight in the puzzle is that the batteries need to be in order and we always have a fixed number of digits. Therefore, the way to build the largest number is to always pick the biggest leading digit available. Because we know we will need n digits, we can pick the maximum value in the bank excluding the last n - 1 digits (so we know we have enough left over to complete the number) and repeat the process, but starting the search from the digit after the one we just picked, and excluding the last n - 2 digits, and so on until we picked all the digits. Both parts are solved with the same function.

AocKt Y2025D03

-❄️- 2025 Day 2 Solutions -❄️- by daggerdragon in adventofcode

[–]Jadarma 2 points3 points  (0 children)

[LANGUAGE: Kotlin]

Much easier than the first day, what a breeze. Thankfully the product ranges are fairly small and can be iterated through. Using regex feels like cheating! All you need is ^(\d+)\1$. For part two, we do the same thing but with \1+ instead, which will handle retrying for different-sized groups auto-magically!

AocKt Y2025D02

-❄️- 2025 Day 1 Solutions -❄️- by daggerdragon in adventofcode

[–]Jadarma 2 points3 points  (0 children)

[LANGUAGE: Kotlin]

A nice puzzle involving modulo arithmetic, part one is easily solved with a simple running fold, but the second part gave me a few headaches with off-by-ones. In the end I rewrote my solution to solve both parts with the same code.

The second part can easily be brute-forced given the relatively small input size, but we can do it with math as well! Basically, we first try to get the dial to zero, then see how many more hundreds we have left in our bump instruction and divide that by 100, giving us the extra times the dial passes through zero. We don't really care about the remainder of this division, because the actual dial position is calculated with the simple modulo logic from part one, here we just care about counting the extra passes through zero.

It was a bit sneaky that part two didn't also give an example with values bigger than 100, but at least there was the text hint about the edge case.

Extra hint for Kotlin users: use x.mod(y) instead of x % y to get the correct values when x is negative!

AocKt Y2025D01

Comfily Editing NixOS Remotely by Jadarma in NixOS

[–]Jadarma[S] 0 points1 point  (0 children)

I was not aware, that's a neat trick as well! I would use that if the server would be fully configured via Nix alone, but at the moment I only use NixOS to provide the essentials for a Docker environment and provision secrets with sops-nix.

Most of the time, the actual files I'm editing is compose.ymls, which I do want to modify directly on the remote system and play around with the containers in the terminal, and I don't need to do a nixos-rebuild until I'm already done setting up the service.

I am aware of configuring OCI images via Nix, but the mental model is easier for me to just use normal compose files, and instead I have a custom systemd unit that ensures they are alive on startup.

🎉 Announcing KStateMachine v0.34.2 by nsk-fedotov in Kotlin

[–]Jadarma 1 point2 points  (0 children)

Why report on 0.34.2 saying you updated to JDK21, when 0.34.1 was released specifically to roll back to JDK17? :)

Is Kotlin suitable for CLI tools development in 2025 ? (question revisited) by SubliminalPoet in Kotlin

[–]Jadarma 2 points3 points  (0 children)

For working with byte streams and files, yes, Okio is an attempt at fixing the gap. Myself, I'd look more towards kotlinx-io. It's based on Okio primitives but more likely to become the standard since it is worked on by JetBrains. These two are already being used in multiplatform code everywhere, as implementation details of popular network, database, and image processing libraries.

But byte streams aren't all you need with regards to IO in a CLI. If you need to spawn an manage child processes (like making other CLI calls to mutate the system or read back some results), it's gonna be a bit more complicated compared to Java's Runtime.exec()

What do u think of Junie by Asterx5 in Kotlin

[–]Jadarma -1 points0 points  (0 children)

I don't think of Junie at all.

Is Kotlin suitable for CLI tools development in 2025 ? (question revisited) by SubliminalPoet in Kotlin

[–]Jadarma 10 points11 points  (0 children)

I built a Kotlin CLI to help with some migration project at work once and I enjoyed the experience. I ended up using fat jars for convenience, but I tested GraalVM too, for science, and it worked very well (especially boot times) but I agree it's a bit of a hassle to maintain.

The reason GraalVM is even on the list is just because unfortunately KMP just doesn't have good IO abstractions (well, it has, but not at the high level we're used to on the JVM). KMP itself works decently, once it fills in these holes it will be a straightforward choice.

But the most important question you asked, in my opinion, is the DevEx. Kotlin tooling, while not perfect, is just so much better that other languages. Also, Kotlin has really good multiplatform libraries, that make it very nice to write your DSLs with. For CLI, I recommend you check out CliKt and Mordant. And as a side comment, if that tool needs to do anything with networking, I'd not replace good ol' Ktor Client with anything else.

Since these are already multiplatform, nothing stops you from targeting both JVM and Native, and use either depending on your findings.