The game we'll build
GridBeasts is a territory game: mint creature cards, place them on one shared 8×6 map, and displace weaker enemies. Every rule below maps to a few lines of code you'll paste in Section C.
Cards
- Element: fire, water, or grass. Power: 1–9. Name: generated.
- Stats are rolled by the node when the mint event syncs, using a block-seeded random generator — unknowable before the mint lands, identical on every node after.
- Species: each element has four families. A hash of the NFT's token id picks the species deterministically, and the remaining hash bits vary the individual (eyes, body shape, expression) — so two Drakes are recognizably Drakes, but never twins.
Meet the creatures
All art is generated — the same function that runs in game.html drew these. token id hash → species; more hash bits → the individual. No image files exist anywhere in the project.
Placing & battles
- Your hand = cards you own that aren't on the map. Place any hand card on an empty cell (free, gasless).
- Placing onto an enemy card starts a battle. You can't attack your own cards, and placed cards don't move.
The battle formula
| Total | |
|---|---|
| Attacker | power (+2 if in season) × element multiplier + Σ powers of your cards orthogonally adjacent to the target cell |
| Defender | power (+2 if in season) + Σ powers of their adjacent cards |
- Element triangle: fire beats grass beats water beats fire — advantage ×1.5, disadvantage ×0.5.
- Attacker needs a strictly greater total. Win: the defender's card bounces back to its owner's hand and you take the cell. Lose: nothing changes (your failed attempt is public in the battle log).
- Battle fatigue: after every battle, both fighters permanently lose 1 power (never below 1) — win, lose, or tie. Veterans get tired, and a failed attack still costs you.
Seasons — the multi-chain twist
A counter contract on Midnight selects the season: counter mod 3 → fire / water / grass. The in-season element gets +2 power in every battle, on both sides. Advancing the season is a real Midnight transaction — a private ZK chain shifting the balance of power on an EVM-driven map. That's the bonus step.
Winning
The leaderboard ranks players by cells controlled. In the live session, most cells when the instructor calls time wins.
Which file implements which rule
| Rule | File | Step |
|---|---|---|
| card stats + names | packages/node/game.ts → generateCardStats() | 2 |
| battle formula | packages/node/game.ts → resolveBattle() | 2 |
| move validation | packages/node/state-machine.ts → "place" | 4 |
| battle fatigue (−1 power per battle) | state-machine.ts → decrementCardPower after each battle | 4 |
| seasons | state-machine.ts → "midnightContractState" | 6 |
| grid size, multipliers, buffs | constants at the top of game.ts — tune freely | 2 |