A Monte Carlo look at how to pick a restaurant
Exploration · Monte Carlo simulation · Summer 2023
Two people pick a restaurant by taking turns crossing options off a list. I was bored one weekend and wondered whether the way you take those turns actually changes who ends up happy, so I ran ten thousand of them in a Monte Carlo simulation. The order you make the cuts does matter a bit, mostly for the pickier of the two diners.
The setup
I blew the ritual up a bit to make any pattern easier to see: thirty candidate restaurants instead of a shortlist, and up to eight passes instead of the usual one or two. One diner knocks out the spots they’d hate and hands the survivors over, the other trims further, back and forth until a single restaurant is left.
In real life you get two or three passes before everyone’s too hungry to care, so the question isn’t which restaurant is best. It’s how to spend a scarce handful of rounds, and whether that changes as the diners get more room to haggle.
The model
I gave each of thirty restaurants two independent ratings, one per diner, drawn from a bell curve centered at 5. A joint pick can be judged two ways, and they pull in different directions:
- Average — the mean of the two diners’ ratings. Forgiving: a place one person loves and the other merely tolerates can still win.
- Min — the rating of the unhappier diner. Egalitarian: a pick only counts as good if it’s good for both.
For each trial I also computed the single best restaurant under each measure (what a perfectly informed referee would choose) and scored every strategy by its regret: how far below that ideal the actual pick landed. Lower is better; zero would mean the turn-taking found the optimum.
Two ways to narrow down
Every strategy uses the same machinery: on your turn you keep your top-k favorites and pass the trimmed list along. The only thing that changes is the schedule: how many candidates survive each successive round. I compared two:
- Geometric — remove a constant fraction each round, so the count decays 30 → 19 → 12 → 8 → … Big cuts early, gentle ones near the end.
- Linear — remove a constant number each round, so the count steps down evenly, 30 → 25 → 21 → … on toward one.
Same starting list, same final pick of one, same number of rounds. Only the spacing of the cuts is different.
What the simulation says
Across 10,000 trials, here is the average regret for each schedule, broken out by how many rounds the diners take, and by which measure they’re optimizing:
| Rounds | Geometric · avg | Linear · avg | Geometric · min | Linear · min |
|---|---|---|---|---|
| 2 | 0.14 | 0.19 | 0.11 | 0.34 |
| 3 | 0.16 | 0.19 | 0.19 | 0.36 |
| 4 | 0.14 | 0.16 | 0.09 | 0.21 |
| 8 | 0.14 | 0.14 | 0.11 | 0.10 |
Average regret below the best-possible restaurant (lower is better); bold marks the better schedule in each pair. “avg” scores a pick by the two diners’ mean rating, “min” by the unhappier diner.
It comes down to how many rounds you get. With only a handful, geometric narrowing wins. On the egalitarian min measure at two rounds it isn’t close: regret of 0.11 versus 0.34, roughly three times better. The edge fades with more rounds, though. By eight passes the two schedules are neck and neck on both measures.
When the schedule matters
The gap is almost entirely in the min measure, and I think the reason is that a good min pick is a conjunction: you need a restaurant that both people rate highly, which is rarer and easier to wreck than a place that merely scores well on average. Geometric narrowing keeps the shortlist wide through the early turns, so both diners get to meaningfully shape it before it collapses to one. With only a couple of linear rounds the trimming is lopsided: whoever moves last effectively dominates, and the other person gets stuck with something they only tolerate. The average measure forgives a pick like that; the min doesn’t.
Give the process enough rounds and the alternation rebalances on its own, which is why everything converges by round eight. So the schedule only matters while rounds are scarce, which at dinner they always are.
Run it yourself
The whole experiment is a handful of lines: generate ratings, alternate top-k culls down a chosen schedule, and compare the survivor to the best-possible pick.
import numpy as np
# Each restaurant gets two independent ratings (one per diner), ~N(5, 1).
def generate(n):
return np.random.normal(5, 1, (2, n))
# One turn: the active diner keeps their top `keep`; the rest are cut.
def cull(r, diner, keep):
order = np.flip(np.argsort(r[diner])) # that diner's ranking, best first
return r[:, order][:, :keep]
def run(r, counts): # counts[i] = how many survive round i
for i, keep in enumerate(counts):
r = cull(r, i % 2, keep) # the two diners alternate turns
return r[:, 0] # the surviving pick (its two ratings)
# Same start (30), end (1), and rounds — only the cut SPACING differs:
n, rounds = 30, 8
geometric = np.flip([int(n**p) for p in np.linspace(0, 1, rounds, endpoint=False)])
# -> [19, 12, 8, 5, 3, 2, 1, 1] constant FRACTION removed each round
linear = np.flip(np.linspace(1, n, rounds).astype(int))
# -> [30, 25, 21, 17, 13, 9, 5, 1] constant COUNT removed each round
# regret = (best restaurant for that measure) - (run's pick), over 10k trials.In practice
Honestly, none of this helps you much. Restaurant ratings aren’t a bell curve, there’s a cutoff below which nobody bothers going and a long tail of a few great spots, so the tidy ~N(5,1) assumption is wrong from the start. And real people don’t communicate by silently alternating vetoes; you talk, you say what you actually want, you overrule the model in one sentence. The one thing I’d carry to an actual dinner is mild: when you only get a couple of passes, cut by fractions rather than fixed numbers, so the list stays wide while both of you still have a say. Otherwise it was a fun way to spend a bored afternoon.
Kept simple on purpose: independent normal ratings, greedy top-k turns, no bluffing or strategy between the diners. I wouldn’t read the exact numbers as gospel, but the shape of the result, geometric beating linear when rounds are scarce and most of all for the unhappier diner, held up across every setting I tried.