Balatro

Balatro

Zobrazit statistiky:
Wheel of fortune is definitely bugged (1 in 393,216 occurrence just happened)
I have literally never seen it activate even once, and I've used it over a dozen times. Everyone else I see is complaining about a similar thing.

Edit, new results:

CrabNicholson původně napsal:
I can 100% guarantee that the RNG is busted. Because my random number generator just flipped (for whatever reason, I don't know) from a low roll to a high roll when I booted up the game just now.

These are the results in the past 2 hours:
5 wheels of fortune in a row (1/4)
3 glass cards breaking in a row (1/4)
Gros michel breaking (1/6)

All consecutive to eachother, the run of "good luck" still hasn't ended though I suspect you get a single number every time the game is booted up so it may end now that I've quit out.

The odds of this happening are:
(1/4)^(5+3) * (1/6)

This comes out to a 0.00025% chance, or in other words, 1 in 393,216

Something is definitely wrong with the RNG and it appears to be seeded when the run starts or maybe when the game is booted up.

Also note: Gros Mochel and the Glass cards broke the first time I used them, every time.
Naposledy upravil CrabNicholson; 26. čvc. 2024 v 10.14
< >
Zobrazeno 4660 z 77 komentářů
MysticD'MeeM původně napsal:
For a laugh, I had a nosey.

The code that determines which joker to select is:
if self.ability.name == 'The Wheel of Fortune' then self.eligible_strength_jokers = EMPTY(self.eligible_strength_jokers) for k, v in pairs(G.jokers.cards) do if v.ability.set == 'Joker' and (not v.edition) then table.insert(self.eligible_strength_jokers, v) end end end

That is, for every joker you have (G.jokers.cards), where that is not an "edition" (negative/polychrome/holographic/foil), consider that for WoF. So no, it doesn't "automatically nope" if it picks an already editioned card, because it will never pick one.

Likewise, if you don't have any non-edition jokers, you can't use WoF, as shown:
if self.ability.name == 'The Wheel of Fortune' then if next(self.eligible_strength_jokers) then return true end end

For the actual roll, we're looking at
pseudorandom('wheel_of_fortune') < G.GAME.probabilities.normal/self.ability.extra
with "pseudorandom" being
function pseudorandom(seed, min, max) if type(seed) == 'string' then seed = pseudoseed(seed) end math.randomseed(seed) if min and max then return math.random(min, max) else return math.random() end end

That is, generate a semi-random number between 0 and 1 and, if that is less than some value divided by another, then WoF succeeds.

Probabilities.normal is defined as
probabilities = { normal = 1, },
and self.ability.extra is 4, as taken from:

c_wheel_of_fortune= {order = 11, discovered = false, cost = 3, consumeable = true, name = "The Wheel of Fortune", pos = {x=0,y=1}, set = "Tarot", effect = "Round Bonus", cost_mult = 1.0, config = {extra = 4}},

That is, if you roll a number less than 0.25, from a random chance between 0-1, then WoF succeeds. There's no "hidden" bad luck here.

In addition, All 6s does the following:
if self.ability.name == 'Oops! All 6s' then for k, v in pairs(G.GAME.probabilities) do G.GAME.probabilities[k] = v*2 end end

Meaning you'll end up with a 2/4 chance, which seems pretty obvious from the card description, but might have been worth mentioning.
The problem with the bugged seed probably isn't in the game's code. The game's code is all pretty basic and straightfoward. Unless there is something I missed, it's most likely something in LUA's math.random or math.randomseed code, which is actually just C's math.rand and math.srand. There is something going on at the lower level that is causing the bugged seeds like the one here:

CrabNicholson původně napsal:
Smoking gun:

https://www.youtube.com/watch?v=hmRCC3Q2cns

There is definitely a bug with the RNG, though how it affects the game and what triggers it is not clear.
z33d původně napsal:
Beakstore původně napsal:
Everyone cries about Wheel but nobody cares about Space Joker hitting. Tragic.
What we really should be talking about is the failure of public education system.
We need to be talking about the failure of the optometrist, where I can post a link to a video exploring a confirmed bugged seed and people fail to look at it.
CrabNicholson původně napsal:
z33d původně napsal:
What we really should be talking about is the failure of public education system.
We need to be talking about the failure of the optometrist, where I can post a link to a video exploring a confirmed bugged seed and people fail to look at it.

Notice how you are saying "WoF (and other cards) is definitely bugged because the RNG is bugged".
Notice how the video you have linked is saying: "there exist a few dozen bugged seeds in a total of about 3.8 trillion seeds due to rounding errors where weird things happen".
Who exactly is failing tests here?

Extra bonus information to help you pass: Chance of encountering one of those is less than 0.02%, which according to your own words is impossible as a natural occurence. It is also less than your new baby, the 1 in 393,216 chance.

But hey, I never seen a person arguing a baseless point come around once, and I used logic over a dozen times.
CrabNicholson původně napsal:
The problem with the bugged seed probably isn't in the game's code. The game's code is all pretty basic and straightfoward. Unless there is something I missed, it's most likely something in LUA's math.random or math.randomseed code, which is actually just C's math.rand and math.srand. There is something going on at the lower level that is causing the bugged seeds like the one here:

You legitimately think that you've discovered a bug in the random number functions of LUA and/or C? Something which professional coders have been using for, what, 50 years, and haven't noticed untl now? Seriously?
Nightmyre původně napsal:
CrabNicholson původně napsal:
The problem with the bugged seed probably isn't in the game's code. The game's code is all pretty basic and straightfoward. Unless there is something I missed, it's most likely something in LUA's math.random or math.randomseed code, which is actually just C's math.rand and math.srand. There is something going on at the lower level that is causing the bugged seeds like the one here:

You legitimately think that you've discovered a bug in the random number functions of LUA and/or C? Something which professional coders have been using for, what, 50 years, and haven't noticed untl now? Seriously?
To be fair, C's native random function is generally considered extremely poor quality.
However, despite that, it's still semi-random. It's not going to be "bugged" in the way that's being implied and is still frequently used for "non-critical" (e.g. in a card game) purposes.

CrabNicholson původně napsal:
The problem with the bugged seed probably isn't in the game's code. The game's code is all pretty basic and straightfoward. Unless there is something I missed, it's most likely something in LUA's math.random or math.randomseed code, which is actually just C's math.rand and math.srand. There is something going on at the lower level that is causing the bugged seeds like the one here:

CrabNicholson původně napsal:
Smoking gun:

https://www.youtube.com/watch?v=hmRCC3Q2cns

There is definitely a bug with the RNG, though how it affects the game and what triggers it is not clear.

Except "WoF is broken" is a different matter to "there are bugged seeds". WoF is, in the general sense, working as intended. There exist seeds that cause the entire pseudorandom function to bug out, but unless you're on the specific seeds this isn't something you need to think about.

I'm massively sceptical that it's a C standard library issue, it's much more likely side effects of code like:
G.GAME.pseudorandom[key] = math.abs(tonumber(string.format("%.13f", (2.134453429141+G.GAME.pseudorandom[key]*1.72431234)%1)))

That's the line used to forward random seeds in seeded runs - but again, this isn't something that effects the "average" run, you'd have to get rather (un)lucky to find a seed that does this.
I can explain that broken seed for you too, at least vaguely.
The pseudo-randomness in this game is done by hashing to create new seeds for the C math.rand. You can see it in the pseudorandom function Mystic quoted: seed = pseudoseed(seed)

The pseudoseed function works as follows: the global game state has a list of the last pseudoseed used for each "key", in the case of this WoF call the key is 'wheel_of_fortune'
If a type of roll hasn't been used yet this run, that entry in the list is empty, so in that case it generates one with a hash of the key and the run's seed (the one you pick to do a seeded run, or generated for a random run) concatenated together.
It then iterates that entry in the list using this math: pseudorandom[key] = math.abs(tonumber(string.format("%.13f", (2.134453429141+pseudorandom[key]*1.72431234)%1)))
That's a PRNG formula, which is how any RNG on a computer is done (albeit with various different formulae with their own strengths and weaknesses). Each time it overwrites the gamestate's list entry for that key, so you get a different value each time pseudoseed is called, but each run with a particular seed you get the same order of pseudoseeds and thus the same results from the C rand function. For reference, these pseudoseeds are just a number themselves.

Now on that XEQH7CP9 seed, for WoF this works just fine actually. Calls to the pseudorandom function with argument 'wheel_of_fortune' return results as per usual, so WoF isn't even broken on that run (but since all cards have an edition you wouldn't be able to use it anyway). The same can't be said of certain other keys though. Specifically, a call to pseudorandom with 'erratic' as argument returns... bad argument #1 to 'abs' (number expected, got nil)
That's right, an error. To be specific, the pseudohash returns NaN here. So all subsequent iterations of that key just start doing math on NaN, and thus return NaN. But it works on WoF, what gives? For that let's look at pseudohash's code:
if true then
local num = 1
for i=#str, 1, -1 do
num = ((1.1239285023/num)*string.byte(str, i)*math.pi + math.pi*i)%1
print(num)
end
return num
else
There's more after that in the else statement, but since if true is always true this is the only relevant code. So basically, this iterates backwards over the string it was passed (which is the key string and the global seed appended together, in this case erraticXEQH7CP9). That print(num) statement in there is mine btw, to look at what values it returns. Now one important thing to note here is that since it works backwards, and the global seed is appended to the end, it always works backwards over the global seed first and then the key. You would think this means it always gives the same first 8 results, since that seed is the same for everything, but nope: i is used in the math, and starts off being the length of the string, so each different length of string has a different first 8 results. And there's the problem for this particular seed: with a key length of 7 (such as in 'erratic') the global seed's 7th result is 1.6370904631913e-11. The 8th result will be that magical constant tha'ts roughly 1.12 divided by a value of almost zero, the end result ends up being 0, and thus the 9th one has a divide by zero. That returns INF, the module %1 turns it into NaN, all subsequent math ends up being NaN, so the final thing the function returns is NaN.

Now it's important to remember, Localthunk likely didn't come up with this particular hashing function himself, and they are generally made with numbers where such results are exceedingly rare. In this particular case it breaks down for all keys of length 7 on seed XEQH7CP9, and there's probably a few others seeds that may break down for other string lengths, but this is not a common occurrence - and if it happens for 'wheel_of_fortune' on some seed, it would only break down for other keys with length 16, AKA not glass which has key 'glass'. And thus you didn't encounter this bug at all on your "super lucky" run. And probably you didn't encounter a bug at all. A similar bug could occur in the game where one of the letters in the key cause a particular key (for instance the t in erratic) in a particular seed to return NaN in pseudohash, but then that'd be only for that exact key. And chances of two different key string lengths both causing the bug on one seed are infinitesimal.
senitewolf původně napsal:
CrabNicholson původně napsal:
We need to be talking about the failure of the optometrist, where I can post a link to a video exploring a confirmed bugged seed and people fail to look at it.

Notice how you are saying "WoF (and other cards) is definitely bugged because the RNG is bugged".
Notice how the video you have linked is saying: "there exist a few dozen bugged seeds in a total of about 3.8 trillion seeds due to rounding errors where weird things happen".
Who exactly is failing tests here?

Extra bonus information to help you pass: Chance of encountering one of those is less than 0.02%, which according to your own words is impossible as a natural occurence. It is also less than your new baby, the 1 in 393,216 chance.

But hey, I never seen a person arguing a baseless point come around once, and I used logic over a dozen times.
So what is the cause of the bug in the video I posted then? Explain it to me in detail. It would genuinely help. Nothing you are saying right now is even remotely helpful. I am venturing hypotheses, based on the fact I am not familiar with the game's code and its known bugs. If you are, then go ahead and tell me what the answer is.

Nightmyre původně napsal:
CrabNicholson původně napsal:
The problem with the bugged seed probably isn't in the game's code. The game's code is all pretty basic and straightfoward. Unless there is something I missed, it's most likely something in LUA's math.random or math.randomseed code, which is actually just C's math.rand and math.srand. There is something going on at the lower level that is causing the bugged seeds like the one here:

You legitimately think that you've discovered a bug in the random number functions of LUA and/or C? Something which professional coders have been using for, what, 50 years, and haven't noticed untl now? Seriously?

C's stdlib is full of bugs like the famous buffer overflow, and weird design choices, like this:
https://stackoverflow.com/questions/27544992/does-implementation-of-c-libraries-depend-on-os

If you use google you can find hundreds of threads complaining about c's math.rand function and its various language-specific/system-specific implementations. One interesting thing I learnt was that in Windows (and only windows) you need to set the seed for every thread, or else it will just be seeded with the default value on the new threads and thus return predictable results.

MysticD'MeeM původně napsal:
Nightmyre původně napsal:

You legitimately think that you've discovered a bug in the random number functions of LUA and/or C? Something which professional coders have been using for, what, 50 years, and haven't noticed untl now? Seriously?
To be fair, C's native random function is generally considered extremely poor quality.
However, despite that, it's still semi-random. It's not going to be "bugged" in the way that's being implied and is still frequently used for "non-critical" (e.g. in a card game) purposes.

CrabNicholson původně napsal:
The problem with the bugged seed probably isn't in the game's code. The game's code is all pretty basic and straightfoward. Unless there is something I missed, it's most likely something in LUA's math.random or math.randomseed code, which is actually just C's math.rand and math.srand. There is something going on at the lower level that is causing the bugged seeds like the one here:

Except "WoF is broken" is a different matter to "there are bugged seeds". WoF is, in the general sense, working as intended. There exist seeds that cause the entire pseudorandom function to bug out, but unless you're on the specific seeds this isn't something you need to think about.

I'm massively sceptical that it's a C standard library issue, it's much more likely side effects of code like:
G.GAME.pseudorandom[key] = math.abs(tonumber(string.format("%.13f", (2.134453429141+G.GAME.pseudorandom[key]*1.72431234)%1)))

That's the line used to forward random seeds in seeded runs - but again, this isn't something that effects the "average" run, you'd have to get rather (un)lucky to find a seed that does this.

I encountered a game where literally everything with a 1 in 6 chance or better activated, this was the ~~10th or so game I played. Everything proccing is not normal behavior at all based on probabilities that I tallied up. For me it is not a question if "if" this happens, but "why". It's okay if you don't believe me and think I'm making it up for whatever reason, I didn't have the awareness to grab the seed, because I didn't know about that at the time (I literally just started playing this game). But I know what I saw with my own eyes.

I have literally hundreds of games of chance in my steam library. Not a single one have I ever logged onto the forums and made a post about the RNG. XCom has taught me to be pessimistic. In Xcom, you treat a 25% chance as if it's a 1% chance, nice if it happens, but don't expect it to. I have never cared if wheel of fortune activated, because I would only ever click it if I would otherwise skip. I am not bothered by having 20 nope's in a row, I am only informing that, among the other people who have experienced this, I have too, and in fact, I have experienced another weird occurrence as well (the opposite, where it procced every time).
Goblin původně napsal:
I can explain that broken seed for you too, at least vaguely.
The pseudo-randomness in this game is done by hashing to create new seeds for the C math.rand. You can see it in the pseudorandom function Mystic quoted: seed = pseudoseed(seed)

The pseudoseed function works as follows: the global game state has a list of the last pseudoseed used for each "key", in the case of this WoF call the key is 'wheel_of_fortune'
If a type of roll hasn't been used yet this run, that entry in the list is empty, so in that case it generates one with a hash of the key and the run's seed (the one you pick to do a seeded run, or generated for a random run) concatenated together.
It then iterates that entry in the list using this math: pseudorandom[key] = math.abs(tonumber(string.format("%.13f", (2.134453429141+pseudorandom[key]*1.72431234)%1)))
That's a PRNG formula, which is how any RNG on a computer is done (albeit with various different formulae with their own strengths and weaknesses). Each time it overwrites the gamestate's list entry for that key, so you get a different value each time pseudoseed is called, but each run with a particular seed you get the same order of pseudoseeds and thus the same results from the C rand function. For reference, these pseudoseeds are just a number themselves.

Now on that XEQH7CP9 seed, for WoF this works just fine actually. Calls to the pseudorandom function with argument 'wheel_of_fortune' return results as per usual, so WoF isn't even broken on that run (but since all cards have an edition you wouldn't be able to use it anyway). The same can't be said of certain other keys though. Specifically, a call to pseudorandom with 'erratic' as argument returns... bad argument #1 to 'abs' (number expected, got nil)
That's right, an error. To be specific, the pseudohash returns NaN here. So all subsequent iterations of that key just start doing math on NaN, and thus return NaN. But it works on WoF, what gives? For that let's look at pseudohash's code:
if true then
local num = 1
for i=#str, 1, -1 do
num = ((1.1239285023/num)*string.byte(str, i)*math.pi + math.pi*i)%1
print(num)
end
return num
else
There's more after that in the else statement, but since if true is always true this is the only relevant code. So basically, this iterates backwards over the string it was passed (which is the key string and the global seed appended together, in this case erraticXEQH7CP9). That print(num) statement in there is mine btw, to look at what values it returns. Now one important thing to note here is that since it works backwards, and the global seed is appended to the end, it always works backwards over the global seed first and then the key. You would think this means it always gives the same first 8 results, since that seed is the same for everything, but nope: i is used in the math, and starts off being the length of the string, so each different length of string has a different first 8 results. And there's the problem for this particular seed: with a key length of 7 (such as in 'erratic') the global seed's 7th result is 1.6370904631913e-11. The 8th result will be that magical constant tha'ts roughly 1.12 divided by a value of almost zero, the end result ends up being 0, and thus the 9th one has a divide by zero. That returns INF, the module %1 turns it into NaN, all subsequent math ends up being NaN, so the final thing the function returns is NaN.

Now it's important to remember, Localthunk likely didn't come up with this particular hashing function himself, and they are generally made with numbers where such results are exceedingly rare. In this particular case it breaks down for all keys of length 7 on seed XEQH7CP9, and there's probably a few others seeds that may break down for other string lengths, but this is not a common occurrence - and if it happens for 'wheel_of_fortune' on some seed, it would only break down for other keys with length 16, AKA not glass which has key 'glass'. And thus you didn't encounter this bug at all on your "super lucky" run. And probably you didn't encounter a bug at all. A similar bug could occur in the game where one of the letters in the key cause a particular key (for instance the t in erratic) in a particular seed to return NaN in pseudohash, but then that'd be only for that exact key. And chances of two different key string lengths both causing the bug on one seed are infinitesimal.
Interesting post.

Do you know why the type of joker enhancement changes in the bugged seed once you reach floor 9?
CrabNicholson původně napsal:
Interesting post.

Do you know why the type of joker enhancement changes in the bugged seed once you reach floor 9?
It's not because of reaching ante 9. As the description says, he buys Hone on ante 9. Hone modifies a global variable edition_rate, which is used in the function that picks editions randomly. Effectively it doubles the area of random values that hit each option, which is enough to shift the repeating "random" value from being in the Holo range to the smaller polychrome range above it. Had it been a seed that started off giving polychrome cards only, it would have the potential to shift up to always giving negative jokers (assuming it started off being in the higher half of the polychrome range first).
As a sidenote, after ante 10 it stops giving edition cards. This is because the key for the shop edition generation is 'edi' (for all edition checks) + 'sho' (because it's called from the shop) + ante number. So 'edisho1' for the first ante, 'edisho2' for the second and then 'edisho10' when it hits ante 10. 'edishoX' is length 7 (which we now know is broken on this seed) while 'edishoXX' is length 8.
The problem (and a potential source of bugs) is that it initializes the seed for the rng every time it needs a random number. That's not how you're supposed to use the rng of Lua. As a result it doesn't really rely on the rng library of Lua (or an underlying C library). I think that's a workaround for Lua's lack of support for multiple rng instances. But I'm not a Lua expert.

What you should take a look at is how the game generates the seed it feeds to Lua's random function. That's how Balatro actually generates random numbers.

I have run extensive simulations using Balatro's RNG code. I didn't find any anomality. The Wheel of Fortune was always perfectly 1/4. But I still believe some seeds might give funny results where some of the probabilities break down. I just wasn't able to find one. And I tried millions of seeds.
Naposledy upravil snakeskip; 3. srp. 2024 v 11.07
im up to 5 miss rn
Wheel rarely hits for me.
CrabNicholson původně napsal:
Let me flip this around, has anyone experienced any massive streaks with it? Any runs of 3 or more successes? I haven't heard of anyone where supposed randomness did anything but give them runs of 20 with no successes but never the opposite.
Not to gloate but i had a run where the wheel work 3 times in a row. :lunar2019coolpig:
Samm_y původně napsal:
im up to 5 miss rn
Necroing a 9 month dead topic to complain that you got what is statistically equal to getting one hit, wow.

Ackranome původně napsal:
Wheel rarely hits for me.
1/4 isn't common, it should hit rarely.
CMDR Shven původně napsal:
1/4 isn't common, it should hit rarely.
Semantics. I personally would label a 25% of something happen as uncommon. Rare in my mind is something under 5%. But there is no clear definition so it can vary from person to person.

I don't know if there is or isn't an issue with the RNG in this game. But if there was, it wouldn't be the first game with that problem. Then again, gamers in general seem to overestimate how often they think a 25% (or any other probability) should happen for them.

I also don't know how valid the coding argument that was made is. It seems convincing, but given I don't completely understand it and I can't confirm the code is being accurately represented, I am left with an inability to become convinced.
< >
Zobrazeno 4660 z 77 komentářů
Na stránku: 1530 50

Datum zveřejnění: 25. čvc. 2024 v 7.19
Počet příspěvků: 77