Skip to content
Vamshi Jandhyala

Books · The Riddler

Chapter 132

Scaling a Death Star and Outgunning Stormtroopers

The Riddler for December 23, 2016, two Star Wars problems from Po-Shen Loh. The Express is a scaling argument; the Classic models a blaster duel as a race of rare events.

Riddler Express

A 50-meter Death Star replica needs a 1-meter-wide exhaust port. Power output scales with volume (the cube of the radius), but exhaust capacity scales with surface area (the square). If you keep the same exhaust-area-per-unit-power and scale the design up, at what size does the entire surface have to be exhaust port, the theoretical limit on radius?

The Riddler, FiveThirtyEight, December 23, 2016(original post)

Solution

Find what fraction of the replica’s surface the exhaust port already uses, then see how fast that fraction grows. The 50-meter replica has radius 2525 m and a port of radius 0.50.5 m, so the port area is π(0.5)2=π/4\pi(0.5)^2 = \pi/4 square meters out of a total surface 4π(25)2=2500π4\pi(25)^2 = 2500\pi, a fraction π/42500π=110,000.\frac{\pi/4}{2500\pi} = \frac{1}{10{,}000}. Required exhaust area tracks power, which grows as the cube of the size, while available surface grows as the square; so the fraction of surface needed for exhaust grows linearly with the size. Starting at 1/10,0001/10{,}000, it reaches the whole surface, fraction 11, once the design is scaled up 10,00010{,}000-fold. That takes the diameter from 5050 m to 50 m×10,000=500 km.50 \text{ m} \times 10{,}000 = \boxed{500 \text{ km}}. Beyond that, there is not enough surface to vent the reactor.

The computation

Encode the geometry: the exhaust fraction of the replica, then the linear-in-size growth that hits 11.

import math
port_area = math.pi * 0.5**2            # 1 m wide port -> radius 0.5 m
surface   = 4 * math.pi * 25**2         # 50 m diameter -> radius 25 m
fraction  = port_area / surface
print("exhaust fraction of replica surface:", round(fraction, 8), "= 1 /", round(1/fraction))
print("max diameter:", 50 * (1/fraction) / 1000, "km")
# exhaust fraction of replica surface: 0.0001 = 1 / 10000
# max diameter: 500.0 km

Riddler Classic

Nine stormtroopers fire at you from afar; each shot of theirs hits you with probability 0.0010.001. You fire at the same rate, and with NN of them left your shot takes one out with probability KN/1000K\sqrt{N}/1000 (their tight formation is a bigger target). Every shot is independent. For roughly what KK is this fair, a 50%50\% chance you blast all nine before any of them hits you?

The Riddler, FiveThirtyEight, December 23, 2016(original post)

Solution

Tracking the battle shot by shot is a nightmare, because the troopers fall at random times and the hit chances change as they do. The way through is to notice that every hit is rare, so think of the fight as a continuous race in which each shooter scores hits as independent rare events at a steady rate. When two rare events race, the chance one beats the other is just its share of the combined rate.

With NN troopers up, you land a hit at rate proportional to KNK\sqrt N and the troopers collectively at rate proportional to NN (nine, then eight, …, each at rate 11 in units of 0.0010.001). So the probability your next hit lands before any of theirs is KNKN+N\dfrac{K\sqrt N}{K\sqrt N + N}. You must win this race at every stage, from N=9N=9 down to N=1N=1, and the stages are independent, so your survival probability is the product N=19KNKN+N.\prod_{N=1}^{9} \frac{K\sqrt N}{K\sqrt N + N}. Setting this equal to 12\tfrac12 and solving gives K26.7K \approx 26.7, so a fair fight is right around K27.\boxed{K \approx 27}. You need to be about 2727 times as accurate as a stormtrooper to make even odds of nine-on-one, a back-handed compliment to their marksmanship.

The computation

Encode the product and solve for the KK that makes it 12\tfrac12.

import math
from scipy.optimize import brentq
def survive(K):
    p = 1.0
    for N in range(1, 10):
        p *= K * math.sqrt(N) / (K * math.sqrt(N) + N)
    return p
K = brentq(lambda K: survive(K) - 0.5, 1, 1000)
print("fair K:", round(K, 2), " survival there:", round(survive(K), 4))
for k in (26, 27, 28): print(f"  K={k}: survival = {survive(k):.4f}")
# fair K: 26.71  survival there: 0.5
# K=26: survival = 0.4910
# K=27: survival = 0.5036
# K=28: survival = 0.5156