HNHacker News
TopNewBestAskShowJobs

slaymaker1907

2,540 karma · joined November 22, 2016

submissionscomments
slaymaker1907··on The Math of Card Shuffling
The other thing I don't like about it is that many cards will be flipped upside down which is very annoying for games like MTG.
slaymaker1907··on The Math of Card Shuffling
Yes, you’ll get the alternating pile phenomenon more and more often. In reality, big “clumps” of cards from one pile or the other actually improve the randomization. In the extreme, this becomes the Faro shuffle https://en.m.wikipedia.org/wiki/Faro_shuffle

From a probabilistic standpoint, even if it isn’t a perfect Faro shuffle, almost-Faro shuffling clearly introduces far fewer bits of entropy which is less than ideal.

slaymaker1907··on The Math of Card Shuffling
I wish the 7 shuffle thing would stop getting repeated everywhere. It’s based off a faulty model, particularly for sleeved cards, since if we consider the deck as two piles left (L) and right (R), Pr[L|R] (the probability of taking from the left pile given the last draw was from the right), should be about 0.5 but is nearly 1 in many cases.

The riffle shuffle also has to be one of the only things you actually get worse at the more you practice it.

slaymaker1907··on Federal judge partially blocks U.S. ban on noncompetes
Can we just dissolve the U.S. District Court for the Northern District of Texas? They continually harm the entire country with their nonsense.

Almost every “crazy” decision you’ve heard about in recent years comes from this one district.

slaymaker1907··on Reflection for C++26
You can sort of do it so long as the return type is a template parameter.

    template<typename T>
    T my_construct() { T result; return result; }
slaymaker1907··on Writing GUI apps for Windows is painful
40MB seems like a weird requirement. If it’s under 1GB, I don’t think most people really care any more about executable size. Memory usage is still relevant, but 1GB is going to be less than 1% of disk usage for almost everyone.
slaymaker1907··on A write-ahead log is not a universal part of durability
I’ve come around to the idea that checksumming isn’t some universal panacea. Once you have checksums, you need to start thinking about error *recovery* and not just detection. What happens to linked data? Do you just declare the whole SQLite file corrupted and just throw up your hands?

If you have backups, that’s one obvious solution, but people might not have uncorrupted backups.

I still think you should do it and emit a warning about it at the very least, but it’s not trivial to handle.

slaymaker1907··on B-Trees Require Fewer Comparisons Than Balanced Binary Search Trees
B-trees are definitely more useful, but I don’t think they’re really a good idea to start out with as your first balanced tree.
slaymaker1907··on AI-powered conversion from Enzyme to React Testing Library
I don't think so since you need to leave edit mode to terminate the macro.
slaymaker1907··on Serialization for C# Games
You can surprisingly sort of do this in Java. Just create a lambda which will start the game at the current state when you call it.
slaymaker1907··on Serialization for C# Games
Depending on how large your save state is, it could be as simple as a function mapping from a list of game objects to the saveable object. That approach works really well with Redux on the web since you really don't want to save most things. Where things really get tricky is when you want to get fancy and support things like saving only the changed portion of the state.
slaymaker1907··on Zero Tolerance for Bias
Yes, and the trouble I've seen is that MTG players assume they aren't shuffling like a pro card dealer when their shuffles are actually even more uniform. IIRC Diaconis' original study even mentioned that the number of required shuffles balloons out of control with these very uniform shuffles.
slaymaker1907··on Zero Tolerance for Bias
I think we really need to consider the efficiency of the shuffle as well when evaluating a shuffling technique. If it takes hundreds (much less tens of thousands) of lengthy steps to shuffle the deck, then no one is going to do it.

Additionally, your analysis only considers when the permutation is reachable. You would also want to look at how likely each permutation is.

slaymaker1907··on Zero Tolerance for Bias
The bias I saw would likely be difficult to exploit without studying the mathematics a lot more. It seems to pass several statistical tests, but the problem I found was more about independence.

Let's call the two splits L for left and R for right and consider the resulting deck to be defined as a sequence of these letters indicating whether that card was taken from the left or right pile so in theory you can specify a shuffle uniquely like "LRRLLLLLLRRR...". This method of labeling shuffles has the advantage of being extremely easy to record and also makes the bias I found apparent where there are way too many pairs of "LR" and "RL" compared to "LL" and "RR" like the "7 shuffles is enough" model suggests there should be.

For some reason, when I did all this analysis last year, I was mostly thinking about how to ensure my MTG decks are sufficiently shuffled. I didn't really think about the implications for card counting. However, normal riffle shuffling seems to have less bias (but still present) than the mash shuffling I looked at and I think most casinos use machines for shuffling these days.

slaymaker1907··on Zero Tolerance for Bias
It kind of makes me mad that the very simple RS algorithm (divide and conquer) isn't more widely known given that it's so easy to implement and that it's actually parallelizable unlike Fisher-Yates. I think it's also better pedagogically since you can easily do it with a deck of cards and a coin or some dice while Fisher-Yates is pretty unwieldy for anything beyond very small lists.
slaymaker1907··on Zero Tolerance for Bias
You need at least nlog(n) bits for the same reason as regular shuffling. There are n! permutations and it therefore takes log(n!) bits to uniquely describe a shuffle. nlog(n) is the same as log(n^n) which is obviously greater than log(n!) (this is Stirling’s approximation).
slaymaker1907··on Zero Tolerance for Bias
I implemented this for GPUs back in college and you’re right, it’s really good for parallelism. This shuffle is also great if you want to do a completely unbiased shuffle with real cards. Fischer-Yates is impractical to do with a real deck of cards.
slaymaker1907··on Zero Tolerance for Bias
It’s almost certainly still good enough since it’s unlikely to be biased in ways that matter. Most hand shuffling methods have nasty biases as well.

For standard riffle shuffling, there is often a bias in pulling from the pile opposite from the last pulled card (so alternating pairs of left and right). The model saying “7 shuffles is sufficient” as people like to quote presumes you pull from a pile only proportional to the size of the pile (so you get many fewer alternating runs).

slaymaker1907··on NASA Software Safety Guidebook [pdf]
I love that they used a clipart wizard hat as the *official* symbol of software development on page 14.
slaymaker1907··on AI headphones let wearer listen to a single person in a crowd by looking at them
Oh my god, these would be absolutely amazing as someone with auditory processing issues.
slaymaker1907··on Low-latency scripting for game engines
I think wasm would work pretty well given that sandboxing is essential for browser security. However, the hard part is having a functional permissions system that isn’t so strict that actually malicious plugins can slip through due to every plugin needing a ton of permissions for basic functionality.
slaymaker1907··on Low-latency scripting for game engines
There was an interesting paper I read the other day about a scheme for guaranteed constant time dynamic allocation and deallocation. The idea was you make all objects identical in size (they used 32 bytes). Then, on deallocation of a 32 byte node, you just put the node on a free list. Then, when a new allocation request comes in decrement the ref count of any *direct* reference(s) and move those objects to the free list if their ref count goes to 0. Therefore, even if you have some huge list that goes out of scope, only the 1st node goes on the freelist, but the rest of the list will get freed eventually assuming you continue to allocate new objects.

I thought it was a really cool idea and it seems totally viable for things like a game engine. All the pointer chasing would be expensive, but being able to freely allocate memory without much lag would be a really nice property, particularly for games with plugins like Roblox, Factorio, etc. where code quality is often out of your control.

https://lptk.github.io/files/ctrc-2024-05-09.pdf

slaymaker1907··on WinDirStat – Windows Directory Statistics
There are pretty good reasons to do that. We've been really lax in what is allowed to run as root/admin when in reality, those permissions should only be used when doing things like reading the MFT or snooping on all the network traffic with Wireshark. It should not be required to run as root/admin in order to install most software because installing software is a very common thing to do.

Even if you want more control over your system, I still think technically capable people would be better served by having a separate administrator account from your normal day-to-day account which you have to explicitly log into (so no UAC prompts, you need to go onto that other account and then you get the UAC prompt). Unfortunately, I think most Desktop OSes are still too unusable with this sort of workflow due to how much software insists on admin for installation.

slaymaker1907··on Running PHP fast at the edge with WebAssembly
You're assuming that network latencies follow the triangle inequality, i.e., that A->C is smaller than A->B + B->C. However, that breaks down because of money. It's possible that the user's ISP is a cheapskate without good peering agreements such that while A->B is fast, they haven't setup the necessary agreements to make A->C fast.

I've personally seen this with a game recently and my own ISP. I can ping their West Coast servers in 20-40ms while pinging their Chicago servers takes 200ms+.

This is actually one huge flaw with the current way IP is done. Because your ISP is closely tied with the last-mile of routing, you have very little control over optimizing those backend layers of routing.

This doesn't explain why you wouldn't just run a thin proxy at the edge and instead want to run a full PHP app. For that, my guess is this makes sense when you don't want to run a full server all the time or if you want it to be rapidly scalable.

slaymaker1907··on How to compare two packed bitfields without having to unpack each field (2019)
C++ also supports this. However, you still end up needing to do a bunch of operations, the compiler just hides it from you which is why I think Chen opted not to use it.

  struct my_bitfield
  {
    uint16_t b:5;
    uint16_t g:6;
    uint16_t r:5;
  };

  bool IsEveryComponentGreaterThanOrEqual4(my_bitfield x, my_bitfield y)
  {
    return x.b > y.b && x.g > y.b && x.r > y.r;
  }
slaymaker1907··on How to compare two packed bitfields without having to unpack each field (2019)
You can reduce the branches by just eliminating the early return returns. And short circuits, but you can use bitwise and instead to encourage the compiler not to generate extra branches (the compiler is generally free to do this anyway as there isn't any side effect in the example code which would prohibit optimization). Therefore, what we should really compare the improved version against is:

bool IsEveryComponentGreaterThanOrEqual(uint16_t x, uint16_t y) { int rv; auto xr = x & 0xF100; auto yr = y & 0xF100; rv = xr >= yr;

auto xg = x & 0x07E0; auto yg = y & 0x07E0; rv &= xg >= yg;

auto xb = x & 0x001F; auto yb = y & 0x001F; rv &= xb >= yb;

return rv != 0; }

According to the Compiler Explorer, the one presented in the article still has far fewer instructions on x86_64. Interestingly, the optimization of eliminating the bitshifts doesn't change how it is compiled which says something about trusting your compiler for some of this stuff. https://godbolt.org/z/zWf5GnPPb

However, one more interesting thing is that the modified version I made is nearly identical in size on ARMv8 for the one in the article vs my version (12 vs 11 instructions). https://godbolt.org/z/d4TPqGhKe

slaymaker1907··on Why not just do simple C++ RAII in C?
I'd argue it barely works in C++ as well. I've seen so many poorly implemented classes that violate the very complicated 3/5/0 rule. It's much easier to do RAII correctly in Rust since people aren't constantly working with raw pointers and since objects which are moved somewhere else are not dropped like they are in C++.

One variant that I think might work even better than RAII or defer in a lot of languages is having a thread local "context" which you attach all cleanup actions to. It even works in C, you just define cleanup as a list of

    typedef void(cleanup_function*)(void* context);

 which is saved as into a thread local. Unlike RAII, you don't need to create a custom type for every cleanup action and unlike the call-with pattern from functional programming, lifetimes of these lists can be non-hierarchical.
However, I'm still glad to see defer being considered for C. It's a lot better than using goto for cleanup.
slaymaker1907··on ICC prosecutor seeks arrest warrants against Sinwar and Netanyahu for war crimes
Biden technically has authority to invade the Netherlands if they arrest any member of the military or government of Israel under the American Service-Members' Protection Act since Israel is a major non-NATO ally.
slaymaker1907··on The problem with new URL(), and how URL.parse() fixes that
I think I agree on that, but returning null seems like a bad idea in this specific instance. Instead, I think I'd prefer they return an object like a promise so people are forced to check if an error occurred.
slaymaker1907··on The problem with new URL(), and how URL.parse() fixes that
You're assuming that error handling logic should be local, but I don't think that's ideal. Most of the time, I really do just want things to bail out if something goes really wrong and log what happened. This is because what often happens is that the real error occurred a while back and so the code expected to handle the error has no idea on how to do that (like passing in a mangled URL).
← PreviousPage 4 of 34Next →