Western States 100 Lottery

Author

Peter Ehmann

Published

December 3, 2025

Introduction

The Western States 100 mile endurance event is held every June in California since 1974. In a field of 369 runners, 260 can earn a spot on the starting line through a lottery process. Each year, entrants must complete a 100k or 100mi qualifying race. The number of tickets you have in the lottery is 2n-1, where n is the number of years you have entered to lottery (n resets once you are selected).

More details are described on the race website.

This year I have 8 tickets because it is my 4th year entering the lottery.

Year Race Distance Time
2022 Massanutten Mountain Trails (VA) 100mi 26:32:42
2023 Twisted Branch (NY) 100k 19:09:25
2024 Twisted Branch (NY) 100k 18:24:59
2025 Massanutten Mountain Trails (VA) 100mi 22:38:46

Lottery Entrants

Code
# number of people with the respective number of tickets

one            <- 4471
two            <- 2563
four           <- 1754
eight          <- 1102
sixteen        <- 672
thirtytwo      <- 354
sixtyfour      <- 240
onetwentyeight <- 129
twofiftysix    <- 45
fivetwelve     <- 5

# assign each person a unique ID

tix001 <- (1:one)
tix002 <- (1:two)            + max(tix001)
tix004 <- (1:four)           + max(tix002)
tix008 <- (1:eight)          + max(tix004)
tix016 <- (1:sixteen)        + max(tix008)
tix032 <- (1:thirtytwo)      + max(tix016)
tix064 <- (1:sixtyfour)      + max(tix032)
tix128 <- (1:onetwentyeight) + max(tix064)
tix256 <- (1:twofiftysix)    + max(tix128)
tix512 <- (1:fivetwelve)     + max(tix256)

# create the complete lottery pool

tickets <- c(rep(tix001,1),
             rep(tix002,2),
             rep(tix004,4),
             rep(tix008,8),
             rep(tix016,16),
             rep(tix032,32),
             rep(tix064,64),
             rep(tix128,128),
             rep(tix256,256),
             rep(tix512,512))

Number of entrants: 11335

Number of tickets: 93461

Simulation Results

I performed 1,000,000 simulations to approximate the probability of being selected for each ticket count. An exact probability cannot be calculated because once a ticket is selected, every other ticket from that individual is removed from the pool.

Code
# counters for the number of simulations in which
# a person with that number of tickets is selected

counter001 <- 0
counter002 <- 0
counter004 <- 0
counter008 <- 0
counter016 <- 0
counter032 <- 0
counter064 <- 0
counter128 <- 0
counter256 <- 0
counter512 <- 0

# number of simulations

n_sim <- 1000000

# simulation for-loop

for (i in 1:n_sim) {
  winners <- c()
  while (length(winners)<260) {
    selection <- sample(tickets, size = 1, replace = F)
    winners   <- unique(c(winners,selection))
  }
  if (tix001[1] %in% winners) { counter001 <- counter001 + 1 }
  if (tix002[1] %in% winners) { counter002 <- counter002 + 1 }
  if (tix004[1] %in% winners) { counter004 <- counter004 + 1 }
  if (tix008[1] %in% winners) { counter008 <- counter008 + 1 }
  if (tix016[1] %in% winners) { counter016 <- counter016 + 1 }
  if (tix032[1] %in% winners) { counter032 <- counter032 + 1 }
  if (tix064[1] %in% winners) { counter064 <- counter064 + 1 }
  if (tix128[1] %in% winners) { counter128 <- counter128 + 1 }
  if (tix256[1] %in% winners) { counter256 <- counter256 + 1 }
  if (tix512[1] %in% winners) { counter512 <- counter512 + 1 }
}
# calculate percentages for each ticket count

percent001 <- counter001*100/n_sim
percent002 <- counter002*100/n_sim
percent004 <- counter004*100/n_sim
percent008 <- counter008*100/n_sim
percent016 <- counter016*100/n_sim
percent032 <- counter032*100/n_sim
percent064 <- counter064*100/n_sim
percent128 <- counter128*100/n_sim
percent256 <- counter256*100/n_sim
percent512 <- counter512*100/n_sim

# output table of results

kable(
  data.frame(
    `Number of tickets` = c(
      "1 ticket",   "2 tickets",   "4 tickets",   "8 tickets",   "16 tickets",
      "32 tickets", "64 tickets",  "128 tickets", "256 tickets", "512 tickets"
    ),
    `Probability` = c(
      paste0(format(round(percent001,2),nsmall=2),"%"),
      paste0(format(round(percent002,2),nsmall=2),"%"),
      paste0(format(round(percent004,2),nsmall=2),"%"),
      paste0(format(round(percent008,2),nsmall=2),"%"),
      paste0(format(round(percent016,2),nsmall=2),"%"),
      paste0(format(round(percent032,2),nsmall=2),"%"),
      paste0(format(round(percent064,2),nsmall=2),"%"),
      paste0(format(round(percent128,2),nsmall=2),"%"),
      paste0(format(round(percent256,2),nsmall=2),"%"),
      paste0(format(round(percent512,2),nsmall=2),"%")
    ),
    `Number of applicants` = c(
      one,two,four,eight,sixteen,thirtytwo,sixtyfour,
      onetwentyeight,twofiftysix,fivetwelve
    ),
    `Number selected` = c(
      format(round(one*percent001/100,1),nsmall=1),
      format(round(two*percent002/100,1),nsmall=1),
      format(round(four*percent004/100,1),nsmall=1),
      format(round(eight*percent008/100,1),nsmall=1),
      format(round(sixteen*percent016/100,1),nsmall=1),
      format(round(thirtytwo*percent032/100,1),nsmall=1),
      format(round(sixtyfour*percent064/100,1),nsmall=1),
      format(round(onetwentyeight*percent128/100,1),nsmall=1),
      format(round(twofiftysix*percent256/100,1),nsmall=1),
      format(round(fivetwelve*percent512/100,1),nsmall=1)
    )
  )
)
Number.of.tickets Probability Number.of.applicants Number.selected
1 ticket 0.31% 4471 14.0
2 tickets 0.62% 2563 16.0
4 tickets 1.25% 1754 21.9
8 tickets 2.48% 1102 27.3
16 tickets 4.82% 672 32.4
32 tickets 9.50% 354 33.6
64 tickets 18.11% 240 43.5
128 tickets 32.97% 129 42.5
256 tickets 55.00% 45 24.8
512 tickets 79.77% 5 4.0