Skip to content

z-korp/zordle

Repository files navigation

Zordle

A fully on-chain Wordle clone built on Dojo and deployed with Cartridge. Practice mode runs on a Cartridge Katana slot with loginless burner play; NFT mode runs on Sepolia and Mainnet through Cartridge Controller.

Play: zordle-azure.vercel.app

How it works

The contract uses a "lazy boss" model — there is no preselected answer. Each guess partitions the surviving candidate set by Wordle feedback pattern, then picks one bucket weighted by count^0.8, narrows the candidate set to that bucket, and shows the player the corresponding 3-color feedback. The boss commits to whichever word the player ends up naming, as long as it's still in the candidate set.

Randomness comes from Cartridge VRF on Sepolia/mainnet, and from a deterministic poseidon salt on practice slots.

See bucket-selection-analysis.md for the full design rationale.

Project layout

contracts/        Cairo / Dojo contracts (actions, setup, models)
client/           React + Vite frontend
scripts/          Deploy + dictionary loading + offline analysis tools
docs/             Operational runbooks

Key contract entry points (contracts/src/systems/actions.cairo):

  • start_practice() / start_game(token_id) — begin a game
  • guess(game_id, word_id) — submit a 5-letter word
  • get_game, get_guess, get_dictionary, active_game_id — views

Running locally

Prerequisites pinned in .tool-versions:

  • scarb 2.15.1 (via asdf)
  • sozo 1.8.6
  • starknet-foundry 0.55.0
  • Node 20+ with pnpm

Boot a local Katana + Torii + dev client:

scripts/dev_up.sh

The script migrates the contracts, loads the 2,315-word answer pool + 12,540 guess-only words, finalizes the dictionary, and starts the Vite dev server.

Deploying

  • Practice slot (Cartridge Katana): scripts/deploy_slot.sh
  • Sepolia NFT mode: scripts/deploy_sepolia.sh
  • Mainnet NFT mode: scripts/deploy_mainnet.sh

See docs/deploy.md for the full runbook including mainnet guardrails, practice-slot carryover, when to bump dojo_*.toml seeds, when to force a dictionary reload, and how to verify the deploy via sozo call.

Testing

cd contracts && scarb test

CI runs this on every PR and push to main (workflow).

For offline distribution analysis (different openers, different pools):

node scripts/pattern_distribution.mjs trace
node scripts/pattern_distribution.mjs slate --pool=merged --full

Dictionaries

The on-chain dictionary holds 14,855 words split into two ranges:

  • [0, 2315) — answer pool (NYT real wordles, in shuffled order)
  • [2315, 14855) — guess-only (extra valid 5-letter words)

Source files in scripts/:

  • shuffled_real_wordles.txt — 2,315 NYT answers (input to loader)
  • merged_valid_wordles.txt — 14,855 valid Wordle words (full guess vocab)

scripts/load_dictionary.mjs packs words 10-per-u256, calls load_word_packs in batches, and finalizes with finalize_dictionary. The frontend reads the same ordering from client/public/words.txt.

Credits

Built by zKorp. Dictionary derived from the public NYT Wordle word lists.

License

MIT — see LICENSE.

About

Fully on-chain Wordle on Dojo + Cartridge — daily loginless practice, NFT mode on Sepolia.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors