Many years ago, I stumbled upon a children’s board game called Spot it (a.k.a Dobble).
The game is simple and fun, designed for children ages 6 and up.
There’s a deck of cards with 8 symbols on each card. Every deck has one symbol in common with every other card.
There are a few variants of the game, my go-to is:
- Put one card face-down in the middle of all the players.
- Deal the remaining deck evenly to all players as face-down stacks
- Everyone flips their stack face-up and someone flips the center card face-up.
- Everyone looks at their face-up card and the center card.
- The moment anybody sees a matching symbol with the center card, they should say it out loud and place their card onto the center.
- That placed card is now the new center card.
- Repeat.
- The person who empties their deck first gets 1st, next gets 2nd, and so on.
This project is my version of the game, with a practice mode, timed mode, and a visualizer to explain the math.
The math
To me, the most interesting aspect of this game is the math behind it.
Given a deck of n=8 symbols that meets the constraints:
- Each card has n symbols on them
- Each card has one symbol in common with every other card
- Each symbol must be used an equal number of times.
How many S total symbols and C total cards are there?
Or, in tweet form:
If you’re interested in the solutions, here’s three:
Solution 1: Incremental Deck Construction
The idea: build the deck one card at a time, and see how far we can get before we run into trouble.
Step 0: Swap pictures for numbers
Symbols are hard to write down, so let’s give each one a number:
⚓ -> 1 🍎 -> 2 🍼 -> 3 💣 -> 4 🌵 -> 5 ... and so on
Now a card is just a list of numbers, like
[1,2,3], and we can name each card #1, #2, and so on.Let’s set aside rule 3 (every symbol appears equally often) for now, and just worry about the first two rules:
- Each card has 8 symbols on it
- Any two cards share exactly one symbol
Step 1: Start with two cards
Card #1 can be anything, so let’s say it’s
[1,2,3,4,5,6,7,8].Card #2 needs to share exactly one symbol with card #1 — let’s have it share the
1: [1,9,10,11,12,13,14,15].That’s already a valid (if tiny) deck:
15 symbols + 2 cards.But of course, we can do better!
Every new card has to match both existing cards. The easiest way: reuse the
1 again, and fill the rest with numbers nobody has used yet. That makes card #3 [1,16,17,18,19,20,21,22]. And we can keep repeating this trick: take the
1, then add the next 7 unused numbers!Step 2: Why we can’t do this forever
A cheeky solver might now say: just repeat that trick forever, for
infinite symbols + infinite cards! #1: [1,2,3,4,5,6,7,8] #2: [1,9,10,11,12,13,14,15] #3: [1,16,17,18,19,20,21,22] ... #N+1: [1,2+7N,3+7N,4+7N,5+7N,6+7N,8+7N] ... ad infinitum
But this breaks rule 3: every symbol has to appear the same number of times. Here, the
1 shows up on every card while every other symbol appears exactly once — and adding more cards never evens that out.So the trick has to stop somewhere. The question is: where?
Step 3: The trick stops at 8 cards
It turns out we can only reuse the
1 this way 8 times before we get stuck:#1: [1,2,3,4,5,6,7,8] #2: [1,9,10,11,12,13,14,15] #3: [1,16,17,18,19,20,21,22] #4: [1,23,24,25,26,27,28,29] #5: [1,30,31,32,33,34,35,36] #6: [1,37,38,39,40,41,42,43] #7: [1,44,45,46,47,48,49,50] #8: [1,51,52,53,54,55,56,57]
Why is it finished after 8 times?
- Imagine we tried a 9th card with a
1on it. It would need 7 brand-new symbols:[1,58,59,60,61,62,63,64].
- Now think about any future card without a
1. It has to share a symbol with each of these 9 cards — and besides the1, those 9 cards have nothing in common with each other. - So that future card would need 9 different symbols, one borrowed from each card. But a card only holds 8 — impossible! Every card would be forced to contain a
1, and that breaks rule 3 again.
So 8 cards is the limit for the
1 trick — which also caps our symbols at 57 (the largest number we used) and gives us our first 8 cards.Step 4: Cards without a 1
So far, every card has a
1 on it. Time to build the rest: cards that skip the 1 entirely.Let’s start with
2. A 2-card still needs to match cards #2 through #8, so it must borrow one symbol from each of them. Taking the first available number from each card gives us: [2,9,16,23,30,37,44,51].#9: [2,9,16,23,30,37,44,51]
The next
2-card can’t reuse any symbol from card #9 (the two would then share more than just the 2), so we shift every slot over by one: [10,17,24,31,38,45,52].This gets us to
#10: [2,10,17,24,31,38,45,52]
Keep shifting, and the rest of the
2-cards fall right out:#11: [2,11,18,25,32,39,46,53] #12: [2,12,19,26,33,40,47,54] #13: [2,13,20,27,34,41,48,55] #14: [2,14,21,28,35,42,49,56] #15: [2,15,22,29,36,43,50,57]
Each card is just the one before it with every number (after the
2) bumped up by one.That’s 15 cards done:
1 and 2 each appear on 8 cards, and every other number appears on 2 so far.Step 5: Continuing the pattern
Next up, the
3-cards. Same idea: at each slot, add the smallest number that doesn’t clash with an existing card.- Start with
3. The smallest number we can add is9, because 4 through 8 all sit on card #1, which already shares the3with us.
- With
[3,9], the next number is17: 10–15 are blocked by card #2 (we already share its9), and 16 is blocked by card #9.
- With
[3,9,17], the next is25: 18–22 are blocked by card #3, 23 by card #9, and 24 by card #10.
- Following this through, we end up with
[3,9,17,25,33,41,49,57]— and just like the2s, the rest come from shifting. Only now the numbers also wrap around in a loop.
#16: [3,9,17,25,33,41,49,57] #17: [3,10,18,26,34,42,50,51] #18: [3,11,19,27,35,43,44,52] #19: [3,12,20,28,36,37,45,53] #20: [3,13,21,29,30,38,46,54] #21: [3,14,22,23,31,39,47,55] #22: [3,15,16,24,32,40,48,56]
The
4s work the same way — a little tedious by hand, until the looping pattern jumps out at you:#23: [4,9,18,27,36,38,47,56] #24: [4,10,19,28,30,39,48,57] #25: [4,11,20,29,31,40,49,51] #26: [4,12,21,23,32,41,50,52] #27: [4,13,22,24,33,42,44,53] #28: [4,14,16,25,34,43,45,54] #29: [4,15,17,26,35,37,46,55]
Zooming out, here’s the pattern:
- The 1st slot cycles through
[9,10,11,12,13,14,15], shifted by+0from the previous group (if the3s start with9, the4s start with9too)
- The 2nd slot cycles through
[16,17,18,19,20,21,22], shifted by+1(if the3s start with17, the4s start with18)
- The 3rd slot cycles through
[23,24,25,26,27,28,29], shifted by+2
- The 4th slot cycles through
[30,31,32,33,34,35,36], shifted by+3
- The 5th slot cycles through
[37,38,39,40,41,42,43], shifted by+4
- The 6th slot cycles through
[44,45,46,47,48,49,50], shifted by+5
- The 7th slot cycles through
[51,52,53,54,55,56,57], shifted by+6
Follow the pattern all the way out, and the entire 57-card deck appears:
#1: [1,2,3,4,5,6,7,8] #2: [1,9,10,11,12,13,14,15] #3: [1,16,17,18,19,20,21,22] #4: [1,23,24,25,26,27,28,29] #5: [1,30,31,32,33,34,35,36] #6: [1,37,38,39,40,41,42,43] #7: [1,44,45,46,47,48,49,50] #8: [1,51,52,53,54,55,56,57] #9: [2,9,16,23,30,37,44,51] #10: [2,10,17,24,31,38,45,52] #11: [2,11,18,25,32,39,46,53] #12: [2,12,19,26,33,40,47,54] #13: [2,13,20,27,34,41,48,55] #14: [2,14,21,28,35,42,49,56] #15: [2,15,22,29,36,43,50,57] #16: [3,9,17,25,33,41,49,57] #17: [3,10,18,26,34,42,50,51] #18: [3,11,19,27,35,43,44,52] #19: [3,12,20,28,36,37,45,53] #20: [3,13,21,29,30,38,46,54] #21: [3,14,22,23,31,39,47,55] #22: [3,15,16,24,32,40,48,56] #23: [4,9,18,27,36,38,47,56] #24: [4,10,19,28,30,39,48,57] #25: [4,11,20,29,31,40,49,51] #26: [4,12,21,23,32,41,50,52] #27: [4,13,22,24,33,42,44,53] #28: [4,14,16,25,34,43,45,54] #29: [4,15,17,26,35,37,46,55] #30: [5,9,19,29,32,42,45,55] #31: [5,10,20,23,33,43,46,56] #32: [5,11,21,24,34,37,47,57] #33: [5,12,22,25,35,38,48,51] #34: [5,13,16,26,36,39,49,52] #35: [5,14,17,27,30,40,50,53] #36: [5,15,18,28,31,41,44,54] #37: [6,9,20,24,35,39,50,54] #38: [6,10,21,25,36,40,44,55] #39: [6,11,22,26,30,41,45,56] #40: [6,12,16,27,31,42,46,57] #41: [6,13,17,28,32,43,47,51] #42: [6,14,18,29,33,37,48,52] #43: [6,15,19,23,34,38,49,53] #44: [7,9,21,26,31,43,48,53] #45: [7,10,22,27,32,37,49,54] #46: [7,11,16,28,33,38,50,55] #47: [7,12,17,29,34,39,44,56] #48: [7,13,18,23,35,40,45,57] #49: [7,14,19,24,36,41,46,51] #50: [7,15,20,25,30,42,47,52] #51: [8,9,22,28,34,40,46,52] #52: [8,10,16,29,35,41,47,53] #53: [8,11,17,23,36,42,48,54] #54: [8,12,18,24,30,43,49,55] #55: [8,13,19,25,31,37,50,56] #56: [8,14,20,26,32,38,44,57] #57: [8,15,21,27,33,39,45,51]
You can even have ChatGPT write a quick checker to confirm every rule holds:
✅ All sets have 8 numbers. ✅ All sets share exactly 1 number in common with every other card. ✅ All numbers are represented exactly 8 times.
Solution 2: Projective plane
It turns out mathematicians studied this exact structure long before the game existed — it’s called a finite projective plane.
A projective plane is just a diagram of points and lines with two rules:
- Any two points have exactly one line through them
- Any two lines cross at exactly one point
That second rule should sound familiar: it’s exactly our “any two cards share exactly one symbol” constraint, with lines playing the role of cards and points playing the role of symbols.
In the picture above, each point is a symbol, and each colored line is a card holding the symbols it passes through.
These planes come in sizes, measured by a number
n called the order. A plane of order n always has:n² + n + 1points (symbols)
n² + n + 1lines (cards)
n + 1points on each line (symbols per card)
n + 1lines through each point (cards per symbol)
Spot It has 8 symbols per card, so
n + 1 = 8, which means n = 7: a full Spot It deck is exactly a projective plane of order 7.Plugging in
n = 7:- Symbols:
n² + n + 1 = 49 + 7 + 1 = 57
- Cards:
n² + n + 1 = 57
- Symbols per card:
n + 1 = 8
- Cards per symbol:
n + 1 = 8
The same formula works for any deck size:
Symbols per card | Total symbols | Total cards |
3 (n=2) | 7 | 7 |
4 (n=3) | 13 | 13 |
5 (n=4) | 21 | 21 |
6 (n=5) | 31 | 31 |
8 (n=7) | 57 | 57 |
9 (n=8) | 73 | 73 |
You’ll note here that the number of symbols always equals the number of cards.
Brendan Conley describes this solution more clearly in his article The Math of Spot it.
Solution 3: Proof by algebra
Let = symbols per card (here: ).
Let = the number of cards each symbol appears on (the same for every symbol, by rule 3).
Let = total number of cards.
Let = total number of symbols.
Step 1: Count the deck from one card’s point of view
Pick any card. Every other card in the deck shares exactly one symbol with it, so we can sort all the other cards into groups by which symbol they share:
- Our card has symbols, so there are groups.
- Each symbol sits on other cards, so each group holds cards.
- No card lands in two groups — that would mean sharing 2 symbols with our card, which isn’t allowed.
So the number of other cards is exactly:
Therefore:
With :
Step 2: Count symbol appearances two ways
Now count every symbol printed on every card, in two different ways:
- Card by card: cards with symbols each → appearances
- Symbol by symbol: symbols on cards each → appearances
It’s the same count either way, so:
With :
Step 3: You can’t have more cards than symbols
Here’s the key fact (a cousin of Fisher’s inequality, for the curious):
Why? Suppose the opposite were true — that there are more cards than symbols:
- Suppose .
- Step 2 told us , so this would force — some symbol would have to appear on more than 8 cards.
- Now pick any card and a symbol on it. Since , appears on at least other cards.
- Each of those cards carries extra symbols that aren’t on , since it can only share with .
- No two of them can share any of those extras, either — otherwise they’d share both and the extra symbol, breaking the one-match rule.
- So the cards containing need at least different symbols beyond ’s, which means
- But Step 1 gave us and Step 2 gave us , so
- Combining gives
so . But we needed — contradiction!
- Therefore : there are always at least as many symbols as cards.
- (This is the same wall we ran into in Solution 1, Step 3.)
Step 4: Put it all together
Combining Steps 2 and 3:
So : no symbol can appear on more than 8 cards.
To make the deck as big as possible, take the biggest allowed and plug it into Step 1’s formula:
Then Step 2’s gives us the symbol count:
Final answer:
The app
Some details about the app:
- React + Vite, hosted on Vercel (free)
- Custom themed shadcn/ui
- Built primarily with Cursor agent (gpt 5.2 + opus 4.5) including using Cursor’s native browser actions to test the app

