Suppose you had a bag with $n$ tiles, each with a letter on it. There are $n_A$ tiles with letter 'A', $n_B$ with 'B', and so on, and $n_*$ 'wildcard' tiles (we have $n = n_A + n_B + \ldots + n_Z + n_*$). Suppose you had a dictionary with a finite number of words.

You pick $k$ tiles from the bag without replacement.

How would you compute (or estimate) the probability that you can form a given word, of length $l$ (with 1 < $l$ =< $k$) from the dictionary given the $k$ tiles selected?

For those not familiar with Scrabble (TM), the wildcard character can be used to match any letter. Thus the word 'BOOT' could be 'spelled' with the tiles 'B', '*', 'O', 'T'. The order in which the letters are drawn does not matter.

Suggestion: in order to simplify the writing of answers, it might be better to just answer the question: what is the probability of having the word 'BOOT' among your possible moves after drawing 7 letters from a fresh bag.

(the problem's introduction has been copied from this similar question)

  • $\begingroup$ I'd advise tackling a simpler case first, such as one without wildcards. $\endgroup$
    – Glen_b
    Nov 3, 2013 at 23:52
  • $\begingroup$ @Glen_b I agree. As my final purpose is to order the words by probability, I think ignoring the wildcards is an acceptable approximation. However I still don't have the skills to build a formula to solve this simpler problem $\endgroup$
    – Sébastien
    Nov 4, 2013 at 9:16
  • 1
    $\begingroup$ If you want to start yet simpler, calculate the probability of picking out 'B', then 'O', then 'O', then 'T'. After that, calculate the probability of picking the letters in any order. After that, factor in the fact that you have seven tries. Then factor int he wildcards. $\endgroup$ Nov 5, 2013 at 19:42
  • 1
    $\begingroup$ An easy way of getting at this problem would be to use a Monte Carlo approximation. Would this suffice? $\endgroup$ Nov 5, 2013 at 19:45
  • 1
    $\begingroup$ Are you talking about forming words with just the letters that you pick, or taking into consideration the letters already chosen, and words already placed on the board? $\endgroup$ Nov 8, 2013 at 21:42

5 Answers 5


A formula is requested. Unfortunately, the situation is so complicated it appears that any formula will merely be a roundabout way of enumerating all the possibilities. Instead, this answer offers an algorithm which is (a) tantamount to a formula involving sums of products of binomial coefficients and (b) can be ported to many platforms.

To obtain such a formula, break down the possibilities into mutually disjoint groups in two ways: according to how many letters not in the word are selected in the rack (let this be $m$) and according to how many wildcards (blanks) are selected (let this be $w$). When there are $r=7$ tiles in the rack, $N$ available tiles, $M$ available tiles with letters not in the word, and $W=2$ blanks available, the number of possible choices given by $(m,w)$ is


because the choices of non-word letters, blanks, and word letters are independent conditional on $(m,w,r).$

This reduces the problem to finding the number of ways to spell a word when selecting only from the tiles representing the word's letters, given that $w$ blanks are available and $r-m-w$ tiles will be selected. The situation is messy and no closed formula seems available. For instance, with $w=0$ blanks and $m=3$ out-of-word letters are drawn there will be precisely four letters left to spell "boot" that were drawn from the "b", "o", and "t" tiles. Given there are $2$ "b"'s, $8$ "o"'s, and $6$ "t"'s in the Scrabble tile set, there are positive probabilities of drawing (multisets) "bboo", "bbot", "bbtt", "booo", "boot", "bott", "bttt", "oooo", "ooot", "oott", "ottt", and "tttt", but only one of these spells "boot". And that was the easy case! For example, supposing the rack contains five tiles chosen randomly from the "o", "b", and "t" tiles, together with both blanks, there are many more ways to spell "boot"--and not to spell it. For instance, "boot" can be spelled from "__boott" and "__bbttt", but not from "__ttttt".

This counting--the heart of the problem--can be handled recursively. I will describe it with an example. Suppose we wish to count the ways of spelling "boot" with one blank and four more tiles from the collection of "b", "o", and "t" tiles (whence the remaining two tiles show non-blank letters not in {"b", "o", "t"}). Consider the first letter, "b":

  1. A "b" can be drawn in $\binom{2}{1}$ ways from the two "b" tiles available. This reduces the problem to counting the number of ways of spelling the suffix "oot" using both blanks and just three more tiles from the collection of "o" and "t" tiles.

  2. One blank can be designated as a "b". This reduces the problem to counting the number of ways of spelling "oot" using the remaining blank and just three more tiles from the collection of "o" and "t" tiles.

In general, steps (1) and (2)--which are disjoint and therefore contribute additively to the probability calculations--can be implemented as a loop over the possible number of blanks that might be used for the first letter. The reduced problem is solved recursively. The base case occurs when there's one letter left, there is a certain number of tiles with that letter available, and there may be some blanks in the rack, too. We only have to make sure that the number of blanks in the rack plus the number of available tiles will be enough to obtain the desired quantity of that last letter.

Here is R code for the recursive step. rack usually equals $7$, word is an array of counts of the letters (such as c(b=1, o=2, t=1)), alphabet is a similar structure giving the numbers of available tiles with those letters, and wild is the number of blanks assumed to occur in the rack.

f <- function(rack, word, alphabet, wild) {
  if (length(word) == 1) {
    return(ifelse(word > rack+wild, 0, choose(alphabet, rack)))
  n <- word[1]
  if (n <= 0) return(0)
  m <- alphabet[1]
  x <- sapply(max(0, n-wild):min(m, rack), 
              function(i) {
                choose(m, i) * f(rack-i, word[-1], alphabet[-1], wild-max(0, n-i))

An interface to this function specifies the standard Scrabble tiles, converts a given word into its multiset data structure, and performs the double sum over $m$ and $w$. Here is where the binomial coefficients $\binom{M}{m}$ and $\binom{W}{w}$ are computed and multiplied.

scrabble <- function(sword, n.wild=2, rack=7, 
              N=sum(alphabet)+n.wild) {
  word = sort(table(strsplit(sword, NULL))) # Sorting speeds things a little
  a <- sapply(names(word), function(s) alphabet[s])
  names(a) <- names(word)
  x <- sapply(0:n.wild, function(w) {
           function(i) {
             f(i, word, a, wild=w) *
               choose(n.wild, w) * choose(N-n.wild-sum(a), rack-w-i)
  return(list(numerator = sum(x), denominator = choose(N, rack),
              value=sum(x) / choose(N, rack)))

Let's try out this solution and time it as we go. The following test uses the same inputs employed in the simulations by @Rasmus Bååth:

system.time(x <- sapply(c("boot", "red", "axe", "zoology"), scrabble))

This machine reports $0.05$ seconds total elapsed time: reasonably quick. The results?

> x
            boot        red         axe         zoology     
numerator   114327888   1249373480  823897928   11840       
denominator 16007560800 16007560800 16007560800 16007560800 
value       0.007142118 0.07804896  0.0514693   7.396505e-07

The probability for "boot" of $114327888/16007560800$ exactly equals the value $2381831/333490850$ obtained in my other answer (which uses a similar method but couches it in a more powerful framework requiring a symbolic algebra computing platform). The probabilities for all four words are reasonably close to Bååth's simulations (which could not be expected to give an accurate value for "zoology" due to its low probability of $11840/16007560800,$ which is less than one in a million).

  • $\begingroup$ Cool and elegant solution! And much faster than mine... :) $\endgroup$ Nov 12, 2013 at 13:08
  • 1
    $\begingroup$ This is a great answer, thanks. I would have had a hard time coding your algorithm, so the ready to use code is very welcome. I didn't know R but still managed to use your functions in less than an hour's work, so that the script takes input from a 20k words dictionary file and write results to a .csv. (this took less than 10 minutes on a mid-range core i5) $\endgroup$
    – Sébastien
    Nov 12, 2013 at 19:23

Answers to the referenced question apply here directly: create a dictionary consisting only of the target word (and its possible wildcard spellings), compute the chance that a random rack cannot form the target, and subtract that from $1$. This computation is fast.

Simulations (shown at the end) support the computed answers.


As in the previous answer, Mathematica is used to perform the calculations.

  1. Specify the problem: the word (or words, if you like), the letters, their counts, and the rack size. Because all letters not in the word act the same, it greatly speeds the computation to replace them all by a single symbol $\chi$ representing "any letter not in the word."

    word = {b, o, o, t};
    letters = {b, o, t, \[Chi], \[Psi]};
    tileCounts = {2, 8, 6, 82, 2};
    rack = 7;
  2. Create a dictionary of this word (or words) and augment it to include all possible wildcard spellings.

    dict[words_, nWild_Integer] := Module[{wildcard, w},
       wildcard = {xx___, _, yy___} -> {xx, \[Psi], yy};
       w = Nest[Flatten[ReplaceList[#, wildcard] & /@ #, 1] &, words, nWild];
       Union[Times @@@ Join[w, Times @@@ words]]];
    dictionary = dict[{word}, 2]

    $\left\{b o^2 t, b o^2 \psi ,b o t \psi ,o^2 t \psi ,b o \psi ^2,o^2 \psi ^2,b t \psi ^2,o t \psi ^2\right\}$

  3. Compute the nonwords:

    alphabet = Plus @@ letters;
    nonwords = Nest[PolynomialMod[# alphabet, dictionary] &, 1, rack]

    $b^7 + 7 b^6 o + 21 b^5 o^2 + \cdots +7 \chi \psi ^6+\psi ^7$

    (There are $185$ non-words in this case.)

  4. Compute the chances. For sampling with replacement, just substitute the tile counts for the variables:

    chances = (Transpose[{letters, tileCounts/(Plus @@ tileCounts)}] /. {a_, b_} -> a -> b);
    q = nonwords /. chances;
    1 - q


    This value is approximately $0.00756036.$

    For sampling without replacement, use factorial powers instead of powers:

    multiplicities = MapThread[Rule, {letters, tileCounts}];
    chance[m_] :=  (ReplaceRepeated[m , Power[xx_, n_] -> FactorialPower[xx, n]] 
                   /. multiplicities);
    histor = chance /@ MonomialList[nonwords];
    q0 = Plus @@ histor  / FactorialPower[Total[tiles], nn];
    1 - q0


    This value is approximately $0.00714212.$ The calculations were practically instantaneous.

Simulation results

Results of $10^6$ iterations with replacement:

simulation = RandomChoice[tiles -> letters, {10^6, 7}];
u = Tally[Times @@@ simulation];
(p = Total[Cases[Join[{PolynomialMod[u[[All, 1]], dictionary]}\[Transpose], 
       u, 2], {0, _, a_} :> a]] / Length[simulation] ) // N


Compare it to the computed value relative to its standard error:

(p - (1 - q)) / Sqrt[q (1 - q) / Length[simulation]] // N


The agreement is fine, strongly supporting the computed result.

Results of $10^6$ iterations without replacement:

tilesAll = Flatten[MapThread[ConstantArray[#1, #2] &, {letters, tiles}] ]
    (p - (1 - q)) / Sqrt[q (1 - q) / Length[simulation]] // N;
simulation = Table[RandomSample[tilesAll, 7], {i, 1, 10^6}];
u = Tally[Times @@@ simulation];
(p0 = Total[Cases[Join[{PolynomialMod[u[[All, 1]], dictionary]}\[Transpose], 
       u, 2], {0, _, a_} :> a]] / Length[simulation] ) // N


Make the comparison:

(p0 - (1 - q0)) / Sqrt[q0 (1 - q0) / Length[simulation]] // N


The agreement in this simulation was excellent.

The total time for simulation was $12$ seconds.


So this is a Monte Carlo solution, that is, we are going to simulate drawing the tiles a zillion of times and then we are going to calculate how many of these simulated draws resulted in us being able to form the given word. I've written the solution in R, but you could use any other programming language, say Python or Ruby.

I'm first going to describe how to simulate one draw. First let's define the tile frequencies.

# The tile frequency used in English Scrabble, using "_" for blank.
tile_freq <- c(2, 9 ,2 ,2 ,4 ,12,2 ,3 ,2 ,9 ,1 ,1 ,4 ,2 ,6 ,8 ,2 ,1 ,6 ,4 ,6 ,4 ,2 ,2 ,1 ,2 ,1)
tile_names <- as.factor(c("_", letters))
tiles <- rep(tile_names, tile_freq)
## [1] _ _ a a a a a a a a a b b c c d d d d e e e e e e
## [26] e e e e e e f f g g g h h i i i i i i i i i j k l
## [51] l l l m m n n n n n n o o o o o o o o p p q r r r
## [76] r r r s s s s t t t t t t u u u u v v w w x y y z
## 27 Levels: _ a b c d e f g h i j k l m n o p q r ... z

Then encode the word as a vector of letter counts.

word <- "boot"
# A vector of the counts of the letters in the word
word_vector <- table( factor(strsplit(word, "")[[1]], levels=tile_names))
## _ a b c d e f g h i j k l m n o p q r s t u v w x y z 
## 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0 0 0 0 

Now draw a sample of seven tiles and encode them in the same way as the word.

tile_sample <- table(sample(tiles, size=7))
## _ a b c d e f g h i j k l m n o p q r s t u v w x y z 
## 1 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 1 0 1 0 0 0 

At last, calculate what letters are missing...

missing <- word_vector - tile_sample
missing <- ifelse(missing < 0, 0, missing)
## _ a b c d e f g h i j k l m n o p q r s t u v w x y z 
## 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 

... and sum the number of missing letters and subtract the number of available blanks. If the result is zero or less we succeeded in spelling the word.

sum(missing) - tile_sample["blank"] <= 0

In this particular case we didn't though... Now we just need to repeat this many times and calculate the percentage of successful draws. All this is done by the following R function:

word_prob <- function(word, reps = 50000) {
  tile_freq <- c(2, 9 ,2 ,2 ,4 ,12,2 ,3 ,2 ,9 ,1 ,1 ,4 ,2 ,6 ,8 ,2 ,1 ,6 ,4 ,6 ,4 ,2 ,2 ,1 ,2 ,1)
  tile_names <- as.factor(c("_", letters))
  tiles <- rep(tile_names, tile_freq)
  word_vector <- table( factor(strsplit(word, "")[[1]], levels=tile_names))
  successful_draws <- replicate(reps, {
    tile_sample <- table(sample(tiles, size=7))
    missing <- word_vector - tile_sample
    missing <- ifelse(missing < 0, 0, missing)
    sum(missing) - tile_sample["_"] <= 0

Here reps is the number of simulated draws. Now we can try it out on a number of different words.

> word_prob("boot")
[1] 0.0072
> word_prob("red")
[1] 0.07716
> word_prob("axe")
[1] 0.05088
> word_prob("zoology")
[1] 2e-05
  • $\begingroup$ I get different answers. It's hard to tell why they disagree, given the complexity of your simulation code, but I would start searching for the cause at our handling of wildcards. $\endgroup$
    – whuber
    Nov 5, 2013 at 22:44
  • 2
    $\begingroup$ I believe that sample does not act as you seem to expect. For instance, what happens to your code if the game is modified to allow a rack of 28 tiles? Change size=7 to size=28 to find out. $\endgroup$
    – whuber
    Nov 5, 2013 at 23:00
  • 2
    $\begingroup$ @whuber You're right, thanks for pointing out! Now it's working and results in the same answer as your code! $\endgroup$ Nov 6, 2013 at 8:45
  • $\begingroup$ Thanks for this nice work. Indeed a Monte Carlo approach is perfectly suitable. However, mainly for performance reasons, I have chosen to use the exact calculation algorithm provided by whuber. $\endgroup$
    – Sébastien
    Nov 13, 2013 at 9:03

For the word "BOOT" with no wildcards: $$ p_0=\frac{\binom{n_b}{1}\binom{n_o}{2}\binom{n_t}{1}\binom{n-4}{3}}{\binom{n}{7}} $$ With wildcards, it becomes more tedious. Let $p_k$ indicate the probability of being able to play "BOOT" with $k$ wildcards: $$ \begin{eqnarray*} p_0&=&\frac{\binom{n_b}{1}\binom{n_o}{2}\binom{n_t}{1}\binom{n-4}{3}}{\binom{n}{7}} \\ p_1&=&p_0 +\frac{\binom{n_*}{1}\binom{n_o}{2}\binom{n_t}{1}\binom{n-4}{3}}{\binom{n}{7}} + \frac{\binom{n_b}{1}\binom{n_o}{1}\binom{n_*}{1}\binom{n_t}{1}\binom{n-4}{3}}{\binom{n}{7}} + \frac{\binom{n_b}{1}\binom{n_o}{2}\binom{n_*}{1}\binom{n-4}{3}}{\binom{n}{7}}\\ &=&p_0 +\frac{\binom{n_*}{1}\binom{n-4}{3}}{\binom{n}{7}}(\binom{n_o}{2}\binom{n_t}{1} + \binom{n_b}{1}\binom{n_o}{1}\binom{n_t}{1} + \binom{n_b}{1}\binom{n_o}{2})\\ p_2&=&p_1 + \frac{\binom{n_*}{2}\binom{n-4}{3}}{\binom{n}{7}}(\binom{n_b}{1}\binom{n_o}{1} + \binom{n_b}{1}\binom{n_t}{1} + \binom{n_o}{2} + \binom{n_o}{1}\binom{n_t}{1})\\ p_3&=&p_2 + \frac{\binom{n_*}{3}\binom{n-4}{3}}{\binom{n}{7}}(\binom{n_b}{1} + \binom{n_o}{1} + \binom{n_t}{1})\\ p_4&=&p_3 + \frac{\binom{n_*}{4}\binom{n-4}{3}}{\binom{n}{7}}\\ p_i&=&p_4, i\ge4 \end{eqnarray*} $$

  • 1
    $\begingroup$ The idea is correct (although it would help to explain why and to explain the notation, especially concerning exactly what "$n$" means: whether it counts all other letters or all other letters and the wildcards), but the treatment of wildcards is incomplete. Without any explanation and without any worked examples, it is difficult to determine whether your formulas are correct so we must consider them unreliable. Generally, it is possible to write down a formula for the probability in terms of sums of products of binomial coefficients. $\endgroup$
    – whuber
    Nov 6, 2013 at 14:14
  • 1
    $\begingroup$ There are mistakes in the calculation of $p_0$: it assumes exactly 1 "b", 2 "o"s, and 1 "t" will be chosen; and then it assumes the choice of the other three letters will be independent of those choices, which it is not. Assuming $n=100$ is the total number of tiles, the resulting value is larger than it should be (it equals $8/2585\approx 0.0031$). The same mistake is propagated into the calculations of the wildcard probabilities. $\endgroup$
    – whuber
    Nov 8, 2013 at 22:28


$$\frac{\partial \gamma}{\partial c} = b_0x^c ln(x) \sum_{r=0}^{\infty}\frac{(c+y-1)(c+\alpha)_r(c+\beta)_r}{(c+1)_r(c+\gamma)_r}x^r+$$



$$=b_0x^c\sum_{r=0}^{\infty}\frac{(c+\gamma-1)(c+\alpha)_r(c+\beta)_r}{(c+1)_r(c+\gamma)_r}(ln \ x+\frac{1}{c+\gamma-1}+$$


It's been a while since I looked at how I built my project. And my math may be entirely incorrect below, or correct. I may have it backwards. Honestly, I forget. BUT! Using only binomial combination, without taking into account blank tiles which throws the entire thing out of whack. The simple combination solution without wild.

I asked these questions myself, and built my own scrabble words probability dictionary because of it. You don't need a dictionary of possible words pulled out, only the math behind it and available letters based on letters in tile bag. The array of English rules is below. I spent weeks developing the math just to answer this question for all English words that can be used in a game, including words that can not be used in a game. It may all be incorrect.

The probability of drawing a given word from a bag of letters in Scrabble, requires how many letters are available in the bag, for each letter ( A-Z ) and, whether we're using the wild card as an addition to the math. The blank tiles are included in this math - assuming 100 tiles, 2 of which are blank. Also, how many tiles are available differs based on language of the game, and game rules from around the world. English scrabble differs from Arabic scrabble, obviously. Just alter the available letters, and the math should do the work.

If anyone finds errors, I will be sure to update and resolve them.

Boot: The probability of Boot in a game of scrabble is 0.000386% which is a chance of 67 out of 173,758 hands as shown on the word page for boot.

English Tiles

all is the array of letters in the bag. count is the array of available tiles for that letter, and point is the point value of the letter.

// All arranged by letter, number of letters in scrabble game, and point for the letter.
$all = array("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z");
    $count = array("9", "2", "2", "4", "12", "2", "3", "2", "9", "1", "1", "4", "2", "6", "8", "2", "1", "6", "4", "6", "4", "2", "2", "1", "2", "1");
$point = array("1", "3", "3", "2", "1", "4", "2", "4", "1", "8", "5", "1", "3", "1", "1", "3", "10", "1", "1", "1", "1", "4", "4", "8", "4", "10");

There are 100 tiles in an English scrabble game (i.e., the sum of $count). It does not matter how the tiles are pulled, so it's not a permutation.

The Math I Used Determine how many letters are in the word and what letters are in the word, how many of those letters are available in the tile bag ( count for each letter, unique and allchars ). Binomial coefficient of each, divided by binomial coefficient of length word.

Determine the binomial combinations available

let C(n,r) be binomial coefficient: n!/[n!(n-r)!], or 0 if r > n

Foreach letter, what is the binomial coefficient.

There is 1 "B". There are 2 available, a 2% chance of pulling the b.
There is 2 "O". There are 8 available, a 8% chance of pulling the o.
There is 1 "T". There are 6 available, a 6% chance of pulling the t.
BOOT is a 4 letter word, being taken from a 100 tile set with blanks, 98 without.

n = 98. The number of tiles without blank in the English set

$B = {2 \choose 1} = \frac{2!}{2!(2-1)!}$
$O = {8 \choose 2} = \frac{8!}{8!(8-2)!}$
$T = {6 \choose 1} = \frac{6!}{6!(6-1)!}$

${B \times O \times T}$ divided by the binomial coefficient of tilecount $\frac{98!}{98!(98-{\rm length})!}$

  • $\begingroup$ It's hard to evaluate your solution without knowing what $n$ and $r$ refer to in the final formula. How do you handle the effect of the blank tiles? That's what makes this a difficult problem. Regardless, it would be interesting to see a demonstration that the value of $\frac{38248840}{16007560800}\approx 0.00239$ is incorrect: this was obtained using the R solution I posted. Try this one-second R simulation: let <- c(rep("b", 2), rep("o", 8), rep("t", 6), rep("_", 84)); boot <- function(x) sum(x=="b")>=1 && sum(x=="o")>=2 && sum(x=="t")>=1; mean(replicate(1e5, boot(sample(let, 7)))) $\endgroup$
    – whuber
    Nov 17, 2014 at 19:50
  • $\begingroup$ Re the edit: one obvious error is that your calculation does not account for the number of blanks at all. As far as I can tell from your formulas, if that number were to change (from 2 to 50, say) then your answer would not change. That's obviously wrong. Another problem you face is to explain how your answer can conflict with three other answers already posted, which use three completely different techniques yet agree with one another (and disagree with yours). $\endgroup$
    – whuber
    Nov 17, 2014 at 22:55
  • $\begingroup$ If combinations - the math is binomial coefficients. So, let x be the count of blank tiles. The only math that changes, is n! - is there blanks used, or not. If so, add the count of blank to n! since blank allows 2 more options of every letter possible (n+x)! - if not, leave n! as is. Yes? No? If blanks are not used depending on language rule set in this case English, n! = 98 or 100 with. Each letter without blank is C(n,r), else with blank C((n+x),r). In the array, blank is there - but I forgot to put blank in the math. So just change n to work with blanks. Yes? $\endgroup$ Nov 18, 2014 at 17:45
  • $\begingroup$ No, your reasoning is invalid. I invite you to try out your formulas with smaller numbers so you can see where they go wrong. $\endgroup$
    – whuber
    Nov 18, 2014 at 18:20
  • $\begingroup$ What do you mean by smaller numbers - whuber? Give me an example. Are you saying pulling boot from a set of 10 letters instead, 1 b, 2 o, 1 t's with a 1 blank in the set and 5 other letters. Or something completely different. I'm no math major, but it seems we've become poker players. We're now calculating poker odds with scrabble tiles that don't have suits. $\endgroup$ Nov 18, 2014 at 19:01

Not the answer you're looking for? Browse other questions tagged or ask your own question.