https://github.com/clockworklabs/scrabblebot
Scrabble-style auction game for AI bots, built on SpacetimeDB
https://github.com/clockworklabs/scrabblebot
Last synced: 9 days ago
JSON representation
Scrabble-style auction game for AI bots, built on SpacetimeDB
- Host: GitHub
- URL: https://github.com/clockworklabs/scrabblebot
- Owner: clockworklabs
- License: mit
- Created: 2026-06-06T00:12:11.000Z (19 days ago)
- Default Branch: main
- Last Pushed: 2026-06-06T00:35:21.000Z (19 days ago)
- Last Synced: 2026-06-06T02:17:41.128Z (19 days ago)
- Language: TypeScript
- Size: 582 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# ScrabbleBot
A Scrabble-style auction game where AI bots compete for letters.
Each round the module reveals one letter from a shared Scrabble bag and runs a
1-second sealed-bid auction. The highest bidder wins the letter, adds it to
their rack, and pays (Vickrey or first-price). Bots play words from their
collected letters at any time to earn currency, which funds future bids. Long
words pay a superlinear bonus, so hoarding is rewarded.
Built on [SpacetimeDB](https://spacetimedb.com): rules, timing, lobby
formation, dictionary — all inside a Rust module. Bots are external
SpacetimeDB clients (any language); the spectator UI is a Vite + React app.
Live at **[scrabblebot.vercel.app](https://scrabblebot.vercel.app)** ·
Bot-writing docs: **[/docs](https://scrabblebot.vercel.app/docs)**
## Repo layout
The web client lives at the repo root (standard SpacetimeDB project shape);
the module is nested inside it.
| Path | What it is |
|---|---|
| `src/`, `index.html`, `vite.config.ts` | Vite + React spectator UI |
| `spacetimedb/` | Rust module — schema, reducers, scheduled lobby + auction ticks, dictionary |
| `bot-starter/` | TypeScript starter bot — fork & edit `src/strategy.ts` |
## How a match comes together
There's a single rolling **lobby** that's always open for 60 seconds at a
time:
- Real bots `join_lobby()` at any time.
- If 6 real bots join → match starts immediately.
- If the timer expires → match starts with whoever's there, padded out to 6
with idle simulated bots.
- A fresh lobby opens the moment the previous one resolves.
This means matches run continuously without anyone having to manually
schedule them. Bots that finish a match just call `join_lobby()` again.
## The rules
- **Auction:** 1-second sealed-bid window per letter. Highest bid wins; on
ties, the earlier submission wins.
- **Payment:** Vickrey by default (winner pays the runner-up's bid; reserve
1). First-price is configurable per lobby.
- **Currency:** start at 100 per match. Reward for a word = base score ×
length multiplier (1.0× ≤3 letters → 3.0× ≥7 letters). Reward goes into
both `balance` (spendable) and `score` (ranking).
- **Letters:** standard 98-tile Scrabble bag (no blanks). Match ends when the
bag empties. Tiles nobody bids on go back to the bag.
- **Visibility:** `Holding` and `BagLetter` are private. Bots see only their
own rack via the `my_rack` view; nobody can subscribe to the full bag
composition. The spectator reconstructs opponents' racks from public
`AuctionResult` + `WordPlay` events.
- **Dictionary:** the public-domain
[ENABLE](https://en.wikipedia.org/wiki/Moby_Project#ENABLE) wordlist
(~173k words), embedded from `spacetimedb/wordlist.txt`. Swap in TWL or
SOWPODS if you have a license.
- **Rating:** per-bot ELO updates pairwise at every match end (K=32).
## Writing a bot (5-minute version)
Three steps end-to-end:
1. **Get a token** — on the live site, link your spacetimedb.com identity at
`/account`, then create a team at `/team/new`, then click *Generate token*
on `/team`. You'll get a SpacetimeDB JWT bound to a credential for your
team's bot persona (shown once).
2. **Fork the starter** and plug the token in:
```bash
git clone https://github.com/clockworklabs/scrabblebot
cd scrabblebot/bot-starter
npm install
npm run generate
BOT_NAME=alice BOT_TOKEN= npm start
```
3. **Edit `bot-starter/src/strategy.ts`** — two functions:
- `decideBid(ctx)` — return how much to bid for the current letter.
- `chooseWord(ctx)` — pick a word to play from your rack.
That's it. Your bot will auto-join the lobby, play in matches as they form,
and re-join after each one ends. Token is persisted to
`.token-` after the first run.
For a deeper writeup — what's visible to your bot, the reducer API, the
SpacetimeDB connection snippet end-to-end — see **[/docs](https://scrabblebot.vercel.app/docs)**.
Bots can use any language SpacetimeDB has an SDK for (Rust, C#, TypeScript).
The starter is just convenience; the reducer interface is language-agnostic.
## Running the project locally
For development work on the module or UI:
```bash
npm install
npm run dev
```
This launches `spacetime dev` against maincloud — auto-builds the module,
publishes it, regenerates client bindings, and starts the Vite client on
http://localhost:5173. Edit `spacetimedb/src/lib.rs` and changes flow
straight through to the browser.
The maincloud database name is set in `spacetime.local.json` (defaults to
`scrabblebot`). The `init` reducer seeds a default admin and the simulated
bot pool on every fresh database init.
### Other npm scripts
- `npm run dev:local` — same flow against a local `spacetime start` server.
- `npm run publish` — one-shot publish to the configured server.
- `npm run generate` — regenerate client bindings without the watcher.
- `npm run build` / `npm run preview` — production build of the spectator.
## Tournament mode
`/admin` (admin-only) has a tournament launcher: Swiss rounds → top-N cut →
single-elimination bracket → best-of-3 finals. Match size, Swiss round
count, and top cut are configurable. ELO ratings are updated independently
of tournament standings.
## Known limitations
- `auction_tick` and `lobby_timeout_tick` are callable by any client today.
Fine for a hackathon, but a hardened deploy should gate them.
- No human play — bots only.
- Token-recovery for bots is via the *rotate* model: mint a new credential
on `/team` and the old token keeps working in parallel. The bot persona
itself survives.
## License
MIT.