mirror of
https://github.com/tiennm99/vngeoguessr.git
synced 2026-10-11 03:13:56 +00:00
Implement region-scaled scoring: base ladder (0-5 points) adjusts thresholds proportionally to the picked region's bbox diagonal. Leaderboards credited separately using their own region's ladder, preventing country-round guesses from earning inflated district-board points. Score and per-level points returned in gameResult.bands and gameResult.levels.
4.9 KiB
4.9 KiB
Gameplay Flow
Complete Game Flow
1. Username Setup
- Check localStorage for existing username
- Display UsernameModal if not set
- Store username for leaderboard tracking
2. Region Selection
- Choose anywhere on the region tree:
- Vietnam — draws from every covered province
- A province — Ha Noi, Ho Chi Minh, Da Nang, Lam Dong, Long An
- A district or town — 61 of them, expanded from their province
- Regions with no usable panoramas are listed but disabled, with the reason shown. See the Coverage note in project-overview.md
3. Session Creation
- Server generates unique UUID v4 session ID
- Server stores the exact target location and the district the panorama sits in in Redis with 30-minute expiry
- Client receives session ID only — never the coordinates, never the district
4. Location Display Process
- Pick from the index: the server draws a random panorama id from the
prebuilt index in Postgres for the selected region (
pickRandomPanoinsrc/lib/pano-index.js). A country draw picks a province uniformly first, so the round is not dominated by whichever province has the most panoramas - Resolve the image: one Mapillary lookup by id, ~230ms. Up to three candidates are tried in case an image was deleted upstream
- Credit the district that won: the resolving district comes from the attempt that succeeded, not the first candidate — each retry may sit in a different district
- Image Display:
thumb_2048_url, falling back tothumb_original_url - Security: client never receives the coordinates or the district
5. Guessing Phase
- Image Interaction: View street-level thumbnail image
- Map Interaction: Place guess marker on interactive Leaflet map with OpenStreetMap
- Map Search: optional search for a district, street, or place to pan the map before clicking; results never reveal or place the answer
- Submission: Click submit button to finalize guess
6. Server-Side Processing
- Input: Client submits guess coordinates + session ID only
- Retrieval: Server retrieves exact location from Redis session storage
- Validation: Server validates coordinate ranges and session existence
- Calculation: Server calculates distance using Turf.js distance function
- Scoring: Server-side score calculation with distance-based points
- Cleanup: the session is claimed with an atomic
DELbefore any score is written, so a replay or a concurrent submit scores exactly once
7. Scoring System
Distance-based points (0-5 scale). The headline score is graded against a ladder scaled to the size of the region the player picked; base ladder (exact only for regions at or under the 10km reference diagonal):
- 0-50m: 5 points
- 50m-100m: 4 points
- 100m-200m: 3 points
- 200m-500m: 2 points
- 500m-1km: 1 point
- beyond: 0 points
A larger region multiplies every threshold by its bbox diagonal over the 10km
reference (see bandsForBbox in src/lib/game.js). Leaderboards are credited
separately: each board grades the raw distance against its own region's ladder
(submitRoundScore in src/lib/leaderboard.js), so the headline score and a
board's added points can differ.
8. Results Display
- Show calculated distance between guess and actual location
- Display earned points for current round (0-5 scale)
- Reveal the region path the panorama was in, e.g. Vietnam › Ho Chi Minh › District 7 — this is the first time the client learns the district
- Show the accumulated total and rank at each of the three levels
- Show distance leaderboard rankings for the current game at each level
- Reveal exact target coordinates and compare guess vs actual on the map
9. Leaderboard Management
- Rollup fan-out: each game updates the score board and the distance board at every level above the panorama — normally district, province and Vietnam, or province and Vietnam when the panorama fell outside every district outline. The levels are written concurrently
- Score Leaderboards: Accumulated scoring system with single entry per user
- Distance Leaderboards: Best distance records with multiple entries per user allowed
- Redis Sorted Sets: Persistent storage using ZADD/ZRANGE operations
- Top 200 Limit: Automatic trimming per leaderboard to maintain top performers only
- Score Accumulation: New scores added to existing totals in score leaderboards
- Distance Records: Each game creates new timestamped distance record entry
- Real-time Ranking: Dynamic rank calculation using ZREVRANK/ZRANK for all leaderboard types
- Persistent Storage: No expiration on leaderboard data
10. Continue or Exit
- Option to start next round with new session and location in the same region
- Option to return to the region picker and choose somewhere else
- Option to view full leaderboard with pagination
- Redis session cleanup ensures fresh start for each round