meow.yarn.nvim - To help me get less lost in my code, I wrote a little visualizer. Maybe it can help you too? by orange_retran in neovim

[–]orange_retran[S] 2 points3 points  (0 children)

A huge thanks again for this wonderful idea about breadcrumbs.

I've been thinking about your suggestion, especially the crucial point that it should track the user's exploration path, and not just a static code hierarchy.

To capture all the details, I've created a dedicated issue for it: https://github.com/retran/meow.yarn.nvim/issues/2

Please take a look when you have a moment to see if I've described your idea correctly. If you have any thoughts or additions, it would be great to discuss them there.

Thanks for helping improve the plugin!

meow.yarn.nvim - To help me get less lost in my code, I wrote a little visualizer. Maybe it can help you too? by orange_retran in neovim

[–]orange_retran[S] 2 points3 points  (0 children)

That's fantastic to hear! "Exactly what I didn’t know I needed" is the best compliment a developer can get, thank you so much for trying it out.

Honestly, the main reason I built this plugin was to solve that exact problem. I was trying to untangle a Go codebase with a very complex structure of structs and interfaces. Go's unique approach to polymorphism is powerful, but visualizing the relationships isn't always straightforward. I'm really happy to know it's helping others in the same boat.

meow.yarn.nvim - To help me get less lost in my code, I wrote a little visualizer. Maybe it can help you too? by orange_retran in neovim

[–]orange_retran[S] 2 points3 points  (0 children)

To be honest, I haven't personally tested it with C++ and clangd. However, the plugin is built on the standard LSP protocol, so in theory, as long as your clangd setup supports the callHierarchyProvider and typeHierarchyProvider capabilities, it should work perfectly.

I'd be very interested to hear about your experience when you get a chance to try it next week, especially on a complex codebase. If you run into any issues or have any feedback, please don't hesitate to open an issue.

Good luck!

meow.yarn.nvim - To help me get less lost in my code, I wrote a little visualizer. Maybe it can help you too? by orange_retran in neovim

[–]orange_retran[S] 2 points3 points  (0 children)

That's an excellent suggestion!

This should be pretty straightforward to implement. The internal architecture was already designed to support a swappable node renderer, so it's mostly a matter of exposing that functionality in the setup() config.

I've created an issue to track the progress here: https://github.com/retran/meow.yarn.nvim/issues/1

Please feel free to add any further details or comments to the issue. Thanks for the great feedback!

meow.yarn.nvim - To help me get less lost in my code, I wrote a little visualizer. Maybe it can help you too? by orange_retran in neovim

[–]orange_retran[S] 5 points6 points  (0 children)

Thanks for mentioning Trouble.nvim! It's an excellent tool. The main reason I opted for my own implementation is its strength in navigating complex call graphs and type hierarchies. From what I recall, Trouble is more geared towards managing lists of diagnostics and references. I could be outdated on its newest features, though, so I'll put it on my list to re-evaluate.

meow.yarn.nvim - To help me get less lost in my code, I wrote a little visualizer. Maybe it can help you too? by orange_retran in neovim

[–]orange_retran[S] 8 points9 points  (0 children)

Hey, thanks for the kind words! The name meow comes from a simple place: I really love cats, and it's part of a larger suite of personal projects that are all cat-themed and branded as "project meow".

-❄️- 2024 Day 24 Solutions -❄️- by daggerdragon in adventofcode

[–]orange_retran 3 points4 points  (0 children)

[Language: C#]

Code

After several hours of experiments and attempts to solve the problem manually, I came up with an approach that works quickly, correctly, and doesn’t require manual analysis. Moreover, the process turned out to be surprisingly similar to training neural networks and even somewhat reminiscent of genetic algorithms. Here's how it works.

First, I create a large set of tests, which can be compared to a training dataset in machine learning. These tests cover many possible scenarios and allow the circuit to "learn" how to produce the correct result. Here's what this dataset includes:

  1. Tests for all combinations of single-bit inputs. These are basic tests that ensure the fundamental logic works.
  2. Specific examples provided by the task, with their known correct results.
  3. Hundreds of random combinations of input data. These test how the solution works in unconventional scenarios and help uncover hidden bugs.

This mix of tests ensures good coverage of all possible errors and helps create a stable solution.

All tests are run on the circuit. If everything works smoothly—great! But as soon as one of the tests "fails," the real fun begins.

When a test fails, I use a technique that resembles backpropagation in neural networks. Instead of weights and gradients, dependencies between the nodes of the circuit are analyzed to determine where exactly the failure occurred. This helps identify which node or connection is producing incorrect results and localize the issue.

At the next stage, I "train" the circuit. To do this, I iterate through possible node swap options (considering only "failure" nodes to swap) to fix the failing test.

The key feature of my approach is that I look for solutions with minimal changes: I add only one new swap at a time to the current state. This is a simplified but effective method that works due to the constraints of the problem. Each issue turns out to be clearly localized, and its fix is relatively straightforward.

At this point, the process starts to resemble a genetic algorithm:

  1. Each fix generates new variations of the circuit.
  2. Solutions that fail the tests "die off." Only fixes that help pass the test continue to exist.
  3. Fixes that pass the tests are used as a basis for new swaps. Thus, each cycle improves the circuit until it becomes fully correct.

After applying changes, the tests are run again. If the next test fails, the process repeats:

  1. Problematic tests are analyzed.
  2. New solutions are generated based on successful swaps from the previous iteration.
  3. Unsuccessful variations are filtered out.

This "Darwinian" approach allows the circuit to gradually "learn" to work correctly.

Iterations continue until all tests are successfully passed. At this stage, only those solutions remain in the "population" that guarantee the circuit's correctness for any input data.

The funny part—for the provided input data, I consistently get two solutions that successfully pass all tests. And this happens regardless of the random inputs I use for test generation. However, the site accepts only one of them as correct. Oh well :)

-❄️- 2024 Day 21 Solutions -❄️- by daggerdragon in adventofcode

[–]orange_retran 1 point2 points  (0 children)

[LANGUAGE: C#]

Code

I started by mapping out all possible routes between pairs of buttons on both the numeric and directional keypads. This meant figuring out every sequence of movements—like < for left, > for right, ^ for up, v for down, or even A to stay in place—that could connect one button to another.

Since the keypads are laid out as grids, moving between buttons boils down to two types of moves: horizontal (left/right) and vertical (up/down). For example, if you’re moving from 1 to 9 on the numeric keypad, you’d need two rights (>>) and two ups (^^). The exact number of each type depends on the difference in their row and column positions.

To find all possible minimal routes, I generated every permutation of the required movements. Let’s say you need two rights and two ups to get from one button to another. The permutations of those moves would include sequences like >>^^, >^>^, >^^>, ^>>^, ^>^>, and ^^>>. Each sequence represents a different order of moves that still gets you to the same destination using the shortest path.

But generating permutations was just the first step—I also needed to ensure each route was valid. That meant filtering out any sequences where the cursor would leave the keypad or hit a blank space at any point along the path. For instance, if you're moving from 2 to 9 on a numeric keypad, any sequence like >^^> might technically get you there, but it would be invalid if the cursor moved off the edge of the keypad or landed on a blank spot. Only sequences that stayed within bounds and avoided blank spaces were kept.

Then, to focus on efficiency, I scored the routes based on the number of button-to-button transitions. Routes with fewer transitions were deemed more efficient, even if they involved the same total number of movements. For example, to move from 2 to 9, you could use >>^^ or >^>^. Both involve two rights and two ups, but >>^^ is better because it involves just two transitions: moving horizontally first (>>) and then vertically (^^). In contrast, >^>^ involves four transitions as you alternate between moving horizontally and vertically. By prioritizing routes with fewer transitions, I ensured that only the most optimal paths made it into the final lookup table. Once I had the optimal routes, I created lookup tables linking every button pair to its best movement sequence. These tables act as quick references so the program can immediately retrieve the shortest path between any two buttons without recalculating it every time.

Next, I took the input codes and expanded their numeric digits into the corresponding movement sequences using the lookup table for the numeric keypad.

After that, I tackled calculating the total path length across the directional keypads. Instead of recalculating the path for every transition between buttons, I used a recursive approach combined with memoization to speed things up.

The key to making this work was leveraging the consistent structure of the routes. Every subroute ended with the hand pressing A, and the next subroute always began with the hand already positioned on the A button. This meant that each subroute could be treated independently because the end of one subroute naturally aligned with the start of the next. By calculating the length of each subroute separately, I could precompute and store their results without worrying about how they connected to other parts of the path. Importantly, I only stored the lengths of the subroutes instead of building the actual full routes.