Balatro and Probability
2025-02-07 11:56 - Programming
I've been thoroughly enjoying Balatro lately. I've proceeded through the challenge mode, and completed 19 of the 20 challenges. The last one, though, seems very difficult. Enough that I went looking online for suggestions of how to beat it. I found a post claiming that the four of a kind hand is the winning strategy. I immediately scoffed. Drawing a four of a kind is just too hard! Right? Right??
I felt the need to validate my intuition, that it's too hard to draw a four of a kind. I tried to look up the chances online, but I have a problem. I want the chances for this game. It's a little like poker, but barely. Specifically: you draw a hand of eight cards. Then you get some number (three, normally) of discards, of up to five cards. Then you get some number of hands to play (four usually, so three can be "throw away" fake discards). Or: what I really want to know is how likely it is to: A) draw eight cards, then B) as necessary discard up to five of them, up to six times, and end up with a four of a kind in hand. Nothing I could search up quickly gave me the answer, but the "real answer" was to simply simulate it. I got nerd sniped, and as a result I did. Simulate it.
#!/usr/bin/env python import collections import random DECK = list('23456789JQKA' * 4) N = 10000 def draw_from(deck): i = random.randint(0, len(deck) - 1) return deck.pop(i) results = [] for _ in range(N): deck = list(DECK) random.shuffle(deck) hand = [] for _ in range(8): hand.append(draw_from(deck)) for i in range(7): #print('hand', hand) cnt = collections.Counter(hand) com = cnt.most_common() if com[0][1] >= 4: #print('Found 4 of %s!' % com[0][0]) results.append(i) break elif i == 6: results.append(None) break else: for _ in range(5): d = com[-1][0] cnt[d] -= 1 com = [x for x in cnt.most_common() if x[1] > 0] #print('discard', d) hand.remove(d) for _ in range(5): hand.append(draw_from(deck)) for result, freq in collections.Counter(results).most_common(): if result is None: print('Failed %.2f%%' % (freq / N * 100)) else: print('Success with %d discards %.2f%%' % (result, (freq / N * 100)))
This is some quick and dirty code. I wrote it in almost exactly half an hour. (As of reading this post, I realize I shuffled the deck, so I didn't need the extra step of randomly choosing a card to draw. I could have "drawn from the top". Probably other minor mistakes of that nature. But I think it's a valid simulation.) And it tells me:
$ python four_of_a_kind.py Failed 42.50% Success with 6 discards 15.02% Success with 5 discards 13.09% Success with 4 discards 11.59% Success with 3 discards 8.99% Success with 2 discards 5.69% Success with 1 discards 2.72% Success with 0 discards 0.40%
Indeed: using "all six" discards results in only a slightly-under-60% chance of finding a four of a kind. In a standard 52 card deck. (Changing slightly each run, as this is a random simulation, not exact probability.) So this might be a workable strategy, but it requires some luck in manipulating your deck, to be able to make the four of a kind hand regularly.
2025-02-07 15:39 - arantius
Above, I failed to include the rank ten card, skipping from 9 to Jack. Including it:
Because there's more different cards to draw, finding a four of a kind is even worse. Roughly a 50/50 shot in a standard 52 card deck.