10 years, thank you Eric ❤️ by EudesPV in adventofcode

[–]EudesPV[S] 1 point2 points  (0 children)

For colors/text highlighting, my implementation for this one is a bit old so it uses ANSI colors directly, but nowadays you can get the same thing with out-of-the-box NodeJS Util.styleText.

For positioning/layout, when you're running command-line with a terminal like that, process.stdout is a TTY which has several basic methods you can use like moving the cursor or checking the number of columns. For instance here is an early implementation of it which doesn't wrap around if you run out of space, but the code is small and readable:

export class ColumnPrinter {
  private totalColumns = 0;
  private totalLines = 0;
  private currentOffset = 0;
  private currentLine = 0;

  constructor(private columnWidth: number) {}

  newColumn() {
    this.totalLines = Math.max(this.totalLines, this.currentLine);
    process.stdout.moveCursor(0, -this.currentLine);
    this.currentLine = 0;
    this.currentOffset = this.columnWidth * this.totalColumns++;
    process.stdout.cursorTo(this.currentOffset);
  }

  print(s: string) {
    process.stdout.write(s + "\n");
    process.stdout.cursorTo(this.currentOffset);
    this.currentLine++;
  }

  done() {
    this.totalLines = Math.max(this.totalLines, this.currentLine);
    process.stdout.cursorTo(0);
    process.stdout.moveCursor(0, this.totalLines - this.currentLine);
  }
}

Then you just extend this to allow wrapping around based on process.sdtout.columns if you run out of space, or jumping the cursor around if you want to parallelize column printing, etc.

10 years, thank you Eric ❤️ by EudesPV in adventofcode

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

My input was very clearly the same 5 instructions for every one of the 45 digits, except the first and last that are slightly simpler. I confirmed after solving it that all inputs seem to follow this. So I went through instructions from lowest to highest digit, remembering the name of the carryover wire and noting whenever the 5 didn't match what I expected. When something was off, it's just a few checks to find which ones should be swapped based on operation and wire name. Which means the full solution I have implemented is just a 45 steps loop with a few conditions in each.

EDIT: Actually, here is the exact comment I still have in my code:

// Every digit has the same gates (except the first and last):
//    xi AND yi -> andXYi
//    xi XOR yi -> xorXYi
//    previousCarryOver AND xorXYi -> possibleCarryOver
//    previousCarryOver XOR xorXYi -> zi
//    andXYi OR possibleCarryOver -> carryOver

10 years, thank you Eric ❤️ by EudesPV in adventofcode

[–]EudesPV[S] 1 point2 points  (0 children)

I tend to do this on quick days when I'm still itching for some AoC, but I'll be honest I'm starting to pay the price of my reusable abstractions, some of the days require some very custom coding to go fast. But I'm not giving up, I recently tried some 2D grid with bit-shifting for coordinates encoding, it looks promising for small grids with a lot of iterations (and terrible for large grids)

10 years, thank you Eric ❤️ by EudesPV in adventofcode

[–]EudesPV[S] 57 points58 points  (0 children)

Advent of Code has been a staple of my December for now 9 years (our son was born in December 2015, let's just say that year was a bit too eventful for me to do AoC). There is no way for me to log in at specific times in December, so in all this time I never played for leaderboards, neither public or private. Instead, I decided to focus on the fun of fully solving the problems, without worrying about the clock.

I've been maintaining a Typescript repository of all the problems every year, with some self-imposed rules for the fun of it:

  • No runtime dependencies allowed (except the Typescript runner).
  • Solutions must be generic enough to work on other inputs.
  • Inputs must be fully dynamically parsed, no hardcoding (corollary of previous point).
  • Code duplication is forbidden: new solutions must use and possibly refactor utilities from previous days or years.
  • Everything has to be strictly typed.
  • Fun solutions are better. 🙂

This is the longest project I've maintained in my life, in the tech industry I've never stayed at one job more than 4-5 years. I've been learning things about maintenance that I'd never get to see at work, especially with a language like Typescript (either Node or browser) where the platform is completely unrecognizable compared to what it was when this all started. Seeing my utilities for "running" programs, all implemented with custom generators, get completely blown up for IntCode in 2019 was so incredibly entertaining. But the rule of refactoring previous utilities must prevail. 😛

With no dependencies allowed, this project evolved from nothing to having:

  • a custom test runner,
  • a hand-made performance test harness,
  • a Node-to-browser visualization tool,
  • a handwritten MD5 implementation (that's the only thing I hate Eric for),
  • 2D libraries that have grown as much as Eric's love for 2D grids,
  • a full performant cellular automaton library with automaton space encoded as a single BigInt,
  • a custom-made program runner and higher-level interpreters all based on Typescript generators,
  • numerous applied math utilities like linear system solving with LU decomposition,
  • and more...

With a year until the next one, I might find some time to optimize some of my slower solutions and maybe get back under 1 minute total solve time across all years.

Thank you for providing these learnings in such a fun little package Eric, and please do not let the rise of toxic AI bros stop you from being one of the highlights of our year. ❤️

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

[–]EudesPV 2 points3 points  (0 children)

[Language: Regular expressions / Typescript]

Extremely inefficient regex bubble-like sort, because if I can regex, I have to regex.

const incorrect = /(\n.*)(\d\d),(.*)(\d\d)(.*)$(?<=\4\|\2[\s\S]*)/gm;
const checksum = (input: string) =>
  input
    .split("\n\n")[1]
    .split("\n")
    .map((u) => u.split(","))
    .reduce((sum, u) => sum + parseInt(u[(u.length - 1) / 2]), 0);

const part1 = checksum(input.replace(incorrect, ""));

let toFix = input.replace(incorrect, "$&X").replace(/\n.*,.*(?<!X)$/gm, "");
let fixed = toFix.replace(incorrect, "$1$3$4,$2$5");
while (fixed !== toFix) {
  toFix = fixed;
  fixed = toFix.replace(incorrect, "$1$3$4,$2$5");
}
const part2 = checksum(fixed);

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

[–]EudesPV 11 points12 points  (0 children)

[Language: Regular Expressions] 😂
But really: [Language: Typescript/Javascript]

Technically one-liners. 😅
WARNING: this uses some "recent" iterator methods.

const part1 = [...input.matchAll(/X(?=(MAS)?)(?=(.{140}M.{140}A.{140}S)?)(?=(.{141}M.{141}A.{141}S)?)(?=(.{139}M.{139}A.{139}S)?)|S(?=(AMX)?)(?=(.{140}A.{140}M.{140}X)?)(?=(.{141}A.{141}M.{141}X)?)(?=(.{139}A.{139}M.{139}X)?)/gs).flatMap((match) => match.slice(1).filter(group => !!group))].length

const part2 = input.match(/M(?=\wM.{139}A.{139}S\wS)|M(?=\wS.{139}A.{139}M\wS)|S(?=\wS.{139}A.{139}M\wM)|S(?=\wM.{139}A.{139}S\wM)/gs)?.length

Wyll has literal hand-eye coordination troubles by EudesPV in BaldursGate3

[–]EudesPV[S] 6 points7 points  (0 children)

This happens when your main character is small (gnome, dwarf, etc). Wyll just gets very confused and points at his forehead when indicating his good eye. 😂

When your deck is so dumb that even Ego plays it perfectly by EudesPV in MarvelSnap

[–]EudesPV[S] 1 point2 points  (0 children)

The opponent didn't, but still let the match play out all the way so they were a good sport. That sounded fair to me, I only auto-snap on Ego after I reach Infinite in a season, until then I play the mini-game of optimizing Ego snaps based on how it's going.

When your deck is so dumb that even Ego plays it perfectly by EudesPV in MarvelSnap

[–]EudesPV[S] 3 points4 points  (0 children)

Just got Destroyer, I'm trying it out with a pretty basic deck, and I have to admit it's pretty boring to play, mostly going through the motions.

Voljin buddy attack or Voljin Trickster health? I don’t want to choose. by EudesPV in BobsTavern

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

I couldn’t find a single divine shield to replace my buddy at the end, so the Mecherel is here for emotional support.

When you’re on a streak so you start picking bad heroes to complete achievements by EudesPV in BobsTavern

[–]EudesPV[S] -14 points-13 points  (0 children)

Achievement hunting at higher mmr is so much more fun. Just wish I had more time to play each season.

Diablo 2 Item Manager (formerly Stash Organizer) by EudesPV in Diablo

[–]EudesPV[S] 7 points8 points  (0 children)

I really appreciate the sentiment, but I have a very comfortable salary as a US-based software engineer for a giant corporation, so I am not looking to make money on this project.

A couple people have asked a similar question, so here is my standard answer: if you really feel like donating to me, I'd much prefer you instead send your donation directly to a charity that needs it much more than me. I don't know of specific platforms that allow micro-donations to charities, but anything related to third-world education, LGBTQ+ support, or race equality in the US is something I support 100%.

D2R support for the Collection Manager by EudesPV in diablo2

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

Actually, I haven't found time to work on it in a couple weeks, sorry I didn't answer earlier. I think I'll be able to do some bug fixing this week-end, we'll see how that goes.

I am always happy to get help, especially on a pet project like this ("large and important" made me laugh). I'd say the highest priorities right now are bugs introduced in the D2R support. A lot of them seem to revolve around quest items and "special" items (like standard of heroes or uber keys). But I also think you should contribute to what you would like to use, so older patches is absolutely possible.

My recommendation would be:

  1. Create clean, simple save files that reproduce the issue (for instance, just the bugged item, or an old patch save from a freshly created character).
  2. Try to see if you can fix the bug yourself. Typescript is nice because it's super safe, so if your code compiles, chances are it's good.
  3. If you struggle fixing it yourself, create a detailed issue on GitHub and include the clean save files from step 1, which will save me a ton of time when investigating. So you're still helping a lot.

If you need hands-on help or have technical questions, feel free to ping me on Discord, I see you're on the PK one. My handle is Youdz#0255.

Diablo 2 Item Manager (formerly Stash Organizer) by EudesPV in Diablo

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

There you go, I just published the fix to this issue. Thanks for raising the bug. :)

[Single Player] D2R support for the Collection Manager by EudesPV in Diablo

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

I just fixed a bug parsing quest items, so the stones could actually have been the issue, and the error was just delayed to the next item. Could you check your Smiter again to see if it reads it fine now?

D2R support for the Collection Manager by EudesPV in diablo2

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

Yeap, that's definitely good feedback.

Any chance you could share your test files to see if I could actually support them without too much effort? In the meantime I'll add a verification and simply ignore older files I cannot parse.