An Optimized “24” Strategy

Introduction and Rules

24 is a card game in which players try to use the basic arithmetic operations and each of four numbers exactly once to get the number 24.

I play the game with my friends as follows: in each round, 4 cards are dealt face-up, and the first person to yell out a solution for how to get 24 wins those cards. J is 11, Q is 12, K is 13, and A is 1. Since it is occasionally impossible to find a solution, the first player to declare the round “impossible” receives the cards after the rest of the players concede. Someone who has already called “impossible” cannot say the answer and win the cards, even if they do find the solution.

The point is this: You want a strategy that allows you to quickly find the correct combination and accurately predict when it’s impossible.

General Strategy

There are four ways to go about making 24, each with its own benefits and weaknesses:

Adding: Use only addition and subtraction operations to get to 24.

This one is the worst for two reasons: 1) very few hands can be solved by it, and 2) in contrast to other strategies, previous calculations don’t build upon each other. Each time you try out a new computation, you’re in effect spinning the “wheel of fortune” and hoping it lands on 24.

Factoring: Make 2 factors of 24 by any operation, then multiply them. (ex. (5 + 1) × (3 + 1) )

This strategy is in my opinion the most useful since 24 only has a few factors, making it easy to identify one factor, then use the remaining cards to create the other.

One thing inherent to factoring is the need to get rid of (i.e. “reduce”) prime numbers that are not factors of 24. For example, if you have a 5 and a 7, then the most logical thing to do is to add or subtract them, giving either 2 or 12, both factors of 24.

Correcting: Make two numbers, then add or subtract them to make 24

This strategy is good if you have a lot of prime numbers that can’t be reduced to pairs of factors. For example, with the numbers 11, 2, 5, and 7, you could make 11 × 2 = 22, then “correct” it to 24 by adding 7 – 5 = 2.

A subcategory of this is distributing, when you have two identical factors and use the distributive property to make 24.

Dividing: Make two numbers and divide them.

This strategy is pretty much useless, but it is a valid way to make 24.


As you can see, 24 doesn’t really involve arithmetic with large numbers — just pattern-matching and good strategy. If you’re making numbers higher than 40 (or, for that matter, non-integers), you’re most likely doing something wrong. I can think of but one exception: Using the numbers 11, 11, 1, and 5, it is only possible to create 24 with these operations: (11 × 11 – 1) / 5. This is probably the only case where large numbers must necessarily be used to make 24, as the expression can’t be simplified in any way.

Programming

First, I wrote a brute-force algorithm to create every possible expression using the 4 cards and 4 operations and seeing which ones evaluate to 24. This was accomplished by putting every combination of the 4 arithmetic operators between the numbers of each possible permutation of the 4 cards. Additionally, I determined that all possible expressions can be evaluated in one of two orders: from left to right (ex. (((1 + 3) * 3) * 2) ), or by doing operations on two sets of two numbers, then an operation on the results (ex. (1 + 5) * (1 + 3) ). Since there are 4! = 24 possible permutations, 4^3 = 64 possible combinations of operators, and 2 ways to order the operations, there are 3072 possible expressions for each number. This algorithm was implemented in Python.

Additionally, the code can tell which of the 4 strategies was used based on the arrangement of operations and the operations themselves; this helps identify which strategies are the most effective overall.

I then analyzed the different strategies using a Monte Carlo approach. This is when you analyze many randomly generated data points to see a pattern, rather than mathematically proving the pattern. By the law of large numbers, as the number of data points increases, so does your accuracy. While this method may be computationally intensive, it is attractive to me because I can leverage my basic programming skills while avoiding the need to do complicated math.

Results

I ran the code on 10000 hands, recording which combinations of strategies could be used to solve each hand. Looking specifically at each strategy and its overlap with other strategies gives us this chart:

There are a few things to note:

  • Adding is the worst strategy. You would do better calling “impossible” immediately on every round than trying to find the solution via adding.
  • Factoring is the best, followed by correcting. Specifically, since around 5500 hands were solved by factoring, 4500 by correcting, and 2700 by both, we can say that around 5500 + 4500 – 2700 = 7300 could be solved by factoring OR correcting. That’s 92% of the roughly 10000 – 2100 = 7900 hands that were solved at all!
  • I stated earlier that dividing is useless, which doesn’t seem to be supported by the graph. However, you can see that most of the hands solved by dividing could also be solved by factoring, likely because they involved dividing by 1.
  • Around 21% of all hands are impossible. This implies that if you’re in a game with 5 or more people, and your skill is at or below average, the optimum strategy is to call “impossible” at the start of every round, which gets you on average 21% of cards.

All Cards Are Equal (But Some Are Less Equal Than Others)

I looked at the numbers most likely to produce an impossible hand. Out of the 2091 impossible hands in 10000 random hands, cards appeared with this frequency (repeated cards in a single hand are counted individually):

Since there are 2091 impossible hands, 4 cards per hand, and 13 possible cards, each card should appear an average of 2091 × 4 ÷ 13 ≈ 643 times. Cards that appear more (“bad cards”) are predictors of impossibility, and cards that appear less (“good cards”) are predictors of non-impossibility (or should I say possibility?).

To get more specific data, I simulated hands that must contain a certain card some number of times, with the rest of the cards in the hand randomly chosen.

As expected, having 2 identical “bad” cards (K–A) significantly increases the probability that a hand is impossible, since a duplicated card decreases the possible expressions that can be used to make 24.

Factoring Strategy

I also looked at the specific case of factoring where you identify a single card as a factor and create the other using the remaining three cards. The computer evaluated the success probability given a certain identified factor:

Surprisingly, factoring with different cards doesn’t produce a meaningful difference, though starting with large factors does give you a slight edge.

Files

Here are my Python files as well as a spreadsheet of the results. The code for each test is contained in its own file, with a library file containing general-use functions. I ran a few tests beyond what was written in this blog post, but their results were uninteresting, so I didn’t include them.