From e22073ca44724ad0e907348f5235d95130af9ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20M=C3=BCllner?= Date: Fri, 13 Nov 2026 18:34:33 +0100 Subject: [PATCH] =?UTF-8?q?docs:=20Devpost-Text=20=E2=80=9EAbout=20the=20p?= =?UTF-8?q?roject=E2=80=9C,=20Tags=20und=20Links?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- docs/submission.md | 93 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/docs/submission.md b/docs/submission.md index bed630a..2dbbb76 100644 --- a/docs/submission.md +++ b/docs/submission.md @@ -45,9 +45,100 @@ Alternativen: - (141) One map. Nine lands. Every day. Build your realm piece by piece, chase three stars and climb today's leaderboard – right inside a Reddit post. +### About the project (Markdown, LaTeX erlaubt) + +> Abschnitt „Inspiration“ bei Bedarf persönlicher machen (eigene Worte des Besitzers). Ob die KI-Unterstützung +> erwähnt wird, entscheidet der Besitzer (die Regeln erlauben technische Hilfe, solange Ideen und Rechte beim +> Teilnehmer liegen). + +```markdown +## Inspiration + +Ninelands started as a strategy board game on a 9×9 board split into nine lands: you place a castle, farmers, +knights and bishops, every piece claims land, and the goal is to rule the nine lands. It runs on the web, desktop, +Android and itch.io – and its most popular mode has always been the **map of the day**, where everyone plays the same +map and compares results. + +Reddit felt like the natural home for that mode. A daily map is a shared puzzle, and a shared puzzle wants a place to +talk about it: _Where did you put your castle? How did you get 9/9 lands?_ So we built **Ninelands for Reddit** – a +focused, bite-sized daily edition that lives inside a post, with the comment thread as the place to compare realms. + +## What it does + +- **One 9×9 map per day, the same for everyone.** A new post appears automatically every day. +- **Easy to start, hard to master.** Tap to preview what a piece would claim and how much gold it brings; tap again to + place it. The line below the board explains why a cell fits or not – no wall of rules. +- **Three stars per map:** reach the gold target, rule the lands target, and both in one game. Targets come from + computer games on that very map, so every day is fair. +- **Leaderboard and streaks.** Only your first game counts. More stars first, then more gold, then the earlier + submission. +- **Your realm.** Unlock board themes with your streak and new banners and peoples (orcs, pirates) with your stars. +- **Reddit-native.** Post your result to the comments with one tap, earn a 🔥 streak flair, and the best player of the + day wears 👑 _Ruler of the day_ the next day. + +## How we built it + +- **Devvit Web** with plain TypeScript, bundled by esbuild; no UI framework. An inline start screen in the feed, the + full board in expanded mode. +- **The original engine, untouched.** The Ninelands engine is pure TypeScript (seeded RNG, `legalMoves`, + `applyMove`, replay). A sync script copies it – plus the SVG board renderer – from a tagged release, so the Reddit + edition plays exactly like the original and fixes flow in one direction only. +- **A server that trusts nothing.** The client sends only its moves. The server replays them with the same engine and + computes gold, lands and stars itself, so results cannot be faked. +- **Redis leaderboards.** Each day is a sorted set. To rank by stars, then gold, then submission time in a single + score, we use + + $$\text{score} = 100\,000 \cdot \text{stars} + \text{gold} + \frac{1}{\text{seq} + 1}$$ + + where $\text{seq}$ is the running number of the submission. The fraction lies in $(0, \tfrac12]$, so it only breaks + ties – and it makes every score unique, which turns a player's rank into a simple + $\text{rank} = \text{count} - \text{zRank}$. +- **First attempt only**, enforced atomically with `hSetNX` – two parallel submissions can never both count. +- **Daily posts** via the Devvit scheduler, **Devvit Journeys** for analytics (journey starts when the castle is + placed, a progress event per star, the end carries the gold as score). +- **Privacy by design:** all user data expires 30 days after a player's last game. + +## Challenges we ran into + +- **Making the daily map unspoilable.** The website has a map of the day too – including a replay of the best game. + The Reddit edition therefore uses its own seed, so its daily map can never be looked up elsewhere. +- **Knowing when to stop.** In the original, a game ends when no move is left. On a phone that can drag on, especially + under the law _One farm per land_, where only costly knights remain. We added an _End game_ button, and the game now + detects when no remaining move earns gold and suggests ending. +- **Fitting a strategy board into a post.** The board, the goals and nine piece costs have to be readable on a phone in + portrait mode. Container queries keep the board as large as possible without pushing the hint line away. +- **Platform details:** a template workflow our CI runner didn't understand, Redis commands that are not enabled for + every app, `localStorage` that is cleared on every app update (so all choices live in Redis), and an analytics router + that expects Express while our server has no framework – we rebuilt its five endpoints by hand. + +## What we learned + +- A daily game lives from **one shared moment**: same map, same day, one first attempt. Every feature we kept serves + that moment; menus and settings did not make the cut. +- Contextual hints beat tutorials. Showing _why_ a move doesn't fit teaches the rules faster than any rules screen. +- Porting is easiest when the game logic is pure: the engine moved to a new platform without a single change. + +## What's next + +- Seasonal events beyond the winter festival, and more unlockable banners and boards. +- A weekly challenge with a twist (fog of war, bandit camps) – both already exist in the original engine. +- An optional duel against the computer after the daily map. +``` + +### Built with (Tags, max. 25) + +typescript, javascript, html5, css3, svg, node.js, devvit, devvit-web, reddit, reddit-api, redis, devvit-scheduler, +devvit-journeys, esbuild, biome, playwright, ffmpeg, pixel-art + +### „Try it out“-Links + +- App: `https://developers.reddit.com/apps/ninelands-game` +- Spielen: `https://www.reddit.com/r/Ninelands/` (sobald angelegt; bis dahin nicht eintragen) +- Original-Spiel: `https://ninelands.stackteam.at` +- Code: Repo ist privat – nur eintragen, wenn es öffentlich wird (optional) + ### Noch zu schreiben -- **Ausführliche Beschreibung** (Funktionen und Ablauf) – Grundlage: `README.md`. - **Portierung angeben** (Kategorie „Best Ported Daily Game“): Ninelands gehört StackTeam; erklären, was seit dem 11. Nov. neu entstanden ist (Pflicht für bestehende Projekte): neue Codebasis auf Devvit Web, neuer Tagesmodus mit eigenem Seed, serverseitig nachgespielte Bestenliste in Redis, Streak, Realm-Freischaltungen, Flair, Ergebnis als