mirror of
https://github.com/tiennm99/loto.git
synced 2026-10-13 22:16:07 +00:00
docs: lock scope to lô tô hội chợ tân tân variant
- pdr: explicit in-scope (9x9, 5/row + 5/col, ascending cols, single-row Kinh, "Chờ N", continue-after-win) vs out-of-scope (3x9 european bingo 90, two-line / full-house tiers, custom number ranges) - update codebase-summary, system-architecture, development-roadmap to reflect 11x9 master board, draw-order overlay, exact 5/col picker - add researcher report comparing tân tân vs european bingo 90
This commit is contained in:
1 parent
189ae3d4e5
commit
de6bdf7eec
5 files changed
+277
-26
No files matched your search
@@ -7,7 +7,7 @@
|
||||
|------|---------|
|
||||
| `src/routes/+layout.svelte` | Root HTML layout. Sets Vietnamese lang, imports Geist font, applies global flex layout. |
|
||||
| `src/routes/+page.svelte` | Player page (`/`). Instructions toggle, PlayerBoard component, indigo gradient branding. |
|
||||
| `src/routes/master/+page.svelte` | Host page (`/master`). Controls (new game, draw number), 9×10 master board, host's player card. |
|
||||
| `src/routes/master/+page.svelte` | Host page (`/master`). Controls (new game, draw number), 11×9 last-digit-aligned master board with draw-order overlay, host's player card. |
|
||||
|
||||
### Shared Components
|
||||
| File | Purpose |
|
||||
@@ -17,7 +17,7 @@
|
||||
### Game Logic
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `src/lib/game-logic.js` | Stateless utilities: generateGrid (weighted column selection), saveGrid, loadGrid, saveCrossedState, loadCrossedState, isRowComplete, getWaitingNumber. |
|
||||
| `src/lib/game-logic.js` | Stateless utilities: generateGrid (constraint-aware picker — exact 5 per row & per col, ascending-sorted columns), saveGrid, loadGrid, saveCrossedState, loadCrossedState, isRowComplete, getWaitingNumber. |
|
||||
|
||||
### Styling
|
||||
| File | Purpose |
|
||||
@@ -60,7 +60,7 @@ RootLayout
|
||||
│ └── PlayerBoard (storagePrefix="loto")
|
||||
└── MasterPage (/master)
|
||||
├── Controls (new game, draw)
|
||||
├── Master board (9×10)
|
||||
├── Master board (11×9, last-digit aligned, draw-order overlay)
|
||||
└── PlayerBoard (storagePrefix="loto_master_card")
|
||||
```
|
||||
|
||||
@@ -68,10 +68,12 @@ RootLayout
|
||||
|
||||
| Function | Location | Effect |
|
||||
|----------|----------|--------|
|
||||
| `generateGrid()` | game-logic.js:74 | Creates 9×9 with weighted column selection (5 nums/row). |
|
||||
| `isRowComplete()` | game-logic.js:200 | Boolean: all non-zero cells in row crossed? |
|
||||
| `getWaitingNumber()` | game-logic.js:218 | Returns the single uncrossed number in row, or null. |
|
||||
| `handleCellClick()` | PlayerBoard.svelte:127 | Toggle crossed[row][col]. |
|
||||
| `saveGrid()` / `loadGrid()` | game-logic.js:149–167 | localStorage with prefix-based keys. |
|
||||
| `pickFilledCols()` | game-logic.js | Per-row column selection that guarantees exact 5 per col (forces any col whose remaining quota equals rowsLeft, random-fills the rest). |
|
||||
| `generateGrid()` | game-logic.js | Builds 9×9; ascending-sorted numbers per column. |
|
||||
| `isRowComplete()` | game-logic.js | Boolean: all non-zero cells in row crossed? |
|
||||
| `getWaitingNumber()` | game-logic.js | Returns the single uncrossed number in row, or null. |
|
||||
| `buildBoard()` | master/+page.svelte | Builds 11×9 master grid; row = ones-digit, col = tens-digit; col 0 holds 1–9, col 8 holds 80–90. |
|
||||
| `handleCellClick()` | PlayerBoard.svelte | Toggle crossed[row][col]. |
|
||||
| `saveGrid()` / `loadGrid()` | game-logic.js | localStorage with prefix-based keys. |
|
||||
|
||||
Last reviewed: 2026-04-26
|
||||
@@ -4,13 +4,15 @@ This document tracks **future work only**. Completed features live in git commit
|
||||
|
||||
## Currently Implemented Features
|
||||
|
||||
The app is fully functional for core gameplay:
|
||||
- 9×9 player card generation with weighted number distribution
|
||||
- Cell marking (toggle crossed state)
|
||||
- Bingo detection and celebration popup
|
||||
The app is fully functional for core gameplay (Lô tô hội chợ Tân Tân variant):
|
||||
- 9×9 player card with **exactly 5 per row and 5 per column**, columns
|
||||
ascending top-to-bottom
|
||||
- Cell marking (toggle crossed state); player can keep playing after Kinh
|
||||
- Bingo detection and "Kinh!" celebration popup
|
||||
- "Chờ X" waiting notifications
|
||||
- Host number drawing from 1–90 deck
|
||||
- 9×10 master board tracking called numbers
|
||||
- 11×9 last-digit-aligned master board with draw-order overlay for fast
|
||||
Kinh verification
|
||||
- Host's own player card (isolated instance)
|
||||
- localStorage persistence
|
||||
- Dark mode
|
||||
@@ -79,10 +81,13 @@ Track games won, time per bingo, etc. Requires server-side persistence. Out of s
|
||||
- Screen reader support
|
||||
|
||||
### Custom Number Range
|
||||
Host selects range (e.g., 1–75 for American bingo) instead of hardcoded 1–90. Requires config UI and refactor of game logic constants.
|
||||
Host selects range (e.g., 1–75 for American bingo) instead of hardcoded 1–90. Requires config UI and refactor of game logic constants. **Out of scope** per Lô tô hội chợ Tân Tân focus.
|
||||
|
||||
### Different Grid Sizes
|
||||
Support 8×8 or 10×10 grids. Major refactor (NUM_ROWS, NUM_COLS constants, weighted selection algorithm).
|
||||
Support 8×8 or 10×10 grids, or 3×9 European Bingo 90 tickets. **Out of scope** — variant locked to 9×9 Tân Tân format.
|
||||
|
||||
### Two-line / Full-house Win Tiers
|
||||
European Bingo 90 patterns. **Out of scope** — Tân Tân uses single-line "Kinh!" only.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -2,15 +2,50 @@
|
||||
|
||||
## What is Lô Tô?
|
||||
|
||||
Lô tô is a traditional Vietnamese bingo game. The app replicates the game digitally for players to generate their own 9×9 number cards and mark cells as a host calls numbers from 1–90. First player to complete an entire row wins and shouts "Kinh!" (the game's victory cheer).
|
||||
This app replicates **Lô tô hội chợ** (Vietnamese fairground / carnival lô tô),
|
||||
specifically the **Tân Tân** style most familiar from southern Vietnam class
|
||||
reunions and Tết gatherings. Inspiration: TN1 class reunions (2014–2017)
|
||||
where players ran build of physical bingo cards.
|
||||
|
||||
The inspiration comes from TN1 class reunions (2014–2017) where players often ran build of physical bingo cards.
|
||||
It is **not** the British Bingo 90 / Italian Tombola 3×9 / 15-number ticket.
|
||||
That format is intentionally out of scope.
|
||||
|
||||
## Game Variant & Scope
|
||||
|
||||
### In scope (Lô tô hội chợ Tân Tân)
|
||||
- **Card**: 9 rows × 9 columns. Exactly **5 numbers per row** AND exactly
|
||||
**5 numbers per column** (45 numbers per card; 36 blanks).
|
||||
- **Column ranges**: col 0 = 1–9, col 1 = 10–19, …, col 7 = 70–79,
|
||||
col 8 = 80–90.
|
||||
- **Within a column**: numbers placed top-to-bottom in **ascending** order.
|
||||
- **Number pool**: 1–90.
|
||||
- **Win condition**: 1 row complete = **"Kinh!"**. After winning, the player
|
||||
may keep playing further rows (game does not end).
|
||||
- **Waiting state**: when a row needs only 1 number, app announces **"Chờ N"**.
|
||||
- **Host (quản trò)** draws numbers from a shuffled 1–90 deck, tracks them on
|
||||
a master board, and may also play their own card.
|
||||
|
||||
### Out of scope
|
||||
- 3×9 / 15-number Bingo 90 / Tombola tickets (European format).
|
||||
- Two-line and full-house win tiers.
|
||||
- Custom number ranges (1–75 American bingo, etc.).
|
||||
- Stake / pot / payout logic.
|
||||
- Multiplayer real-time sync.
|
||||
|
||||
## Core Mechanics
|
||||
|
||||
- **Players**: Generate a randomized 9×9 card with 45 numbers (5 per row, weighted distribution across columns 1–90). Click cells to mark them as numbers are called.
|
||||
- **Host**: Draws numbers randomly from a shuffled 1–90 deck, displays the current number on a large board, and tracks which numbers have been called.
|
||||
- **Bingo**: When a row is complete, the player's card triggers a celebration popup showing "Kinh!" with confetti emojis. Before bingo, toast notifications prompt "Chờ X" (waiting for X) when only one number remains in a row.
|
||||
- **Players**: Generate a randomized 9×9 card. The generator guarantees 5 per
|
||||
row and 5 per column (constraint-aware picker, not loose weighted random).
|
||||
Numbers within each column ascend top-to-bottom. Click cells to mark them.
|
||||
- **Host**: Draws numbers randomly from a shuffled 1–90 deck, shows the
|
||||
current number, and tracks all called numbers on an **11×9 master board
|
||||
aligned by ones-digit** (col 0 = 1–9, col 8 = 80–90; 1 / 11 / 21 / … / 81
|
||||
share row 1, etc.). Each called cell shows its 1-based **draw order** as a
|
||||
small superscript so the host can quickly verify a "Kinh!" claim by reading
|
||||
the order across the winning row.
|
||||
- **Bingo**: When a row is complete, a celebration popup shows "Kinh!" with
|
||||
confetti. Player keeps playing afterward — no game-end gate.
|
||||
- **Waiting**: "Chờ N" toast when a row is one number away.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
@@ -37,11 +72,14 @@ State is entirely client-side. Each page/card instance uses a unique localStorag
|
||||
|
||||
## Key Acceptance Criteria
|
||||
|
||||
- [x] Player can generate a new 9×9 card with valid number distribution.
|
||||
- [x] Player card is 9×9 with **exactly 5 per row and 5 per column**.
|
||||
- [x] Numbers within each column are **ascending top-to-bottom**.
|
||||
- [x] Player can click cells to toggle crossed state.
|
||||
- [x] Bingo popup triggers when row is complete, shows row number and "Kinh!" message.
|
||||
- [x] Player may keep marking after a Kinh — no game-end lock.
|
||||
- [x] Toast notifications show "Chờ X" before bingo (one number remaining).
|
||||
- [x] Host can draw numbers and see them on the 9×10 master board.
|
||||
- [x] Host can draw numbers and see them on the **11×9 last-digit-aligned master board**.
|
||||
- [x] Master board shows **draw order** on each called cell for Kinh verification.
|
||||
- [x] Host has their own player card (isolated by localStorage prefix).
|
||||
- [x] Offline persistence via localStorage (grid and crossed state).
|
||||
- [x] Dark mode support (Tailwind dark classes).
|
||||
@@ -65,4 +103,4 @@ State is entirely client-side. Each page/card instance uses a unique localStorag
|
||||
- Multiplayer sync (real-time via WebSocket)
|
||||
- i18n beyond Vietnamese
|
||||
|
||||
Last reviewed: 2026-04-26
|
||||
Last reviewed: 2026-04-26 (scope locked: Lô tô hội chợ Tân Tân)
|
||||
@@ -13,8 +13,9 @@ Entry
|
||||
│
|
||||
└─ /master (Host Page)
|
||||
├─ Load loto_master (called/remaining)
|
||||
├─ Display 9×10 master board (numbers 1–90)
|
||||
├─ Draw button shows next called number
|
||||
├─ Display 11×9 master board (numbers 1–90, aligned by ones-digit;
|
||||
│ col 0 = 1–9, col 8 = 80–90; each called cell shows draw order)
|
||||
├─ Draw button shows next called number (highlighted in red on board)
|
||||
├─ Display host's own card (loto_master_card prefix)
|
||||
└─ New Game button resets called/remaining
|
||||
```
|
||||
@@ -27,7 +28,9 @@ grid: number[][] // 9×9 numbers (0 = empty)
|
||||
crossed: boolean[][] // 9×9 marked state
|
||||
```
|
||||
|
||||
Each row has exactly 5 non-zero numbers (distributed across columns via weighted random).
|
||||
Each row has exactly 5 non-zero numbers AND each column has exactly 5
|
||||
(constraint-aware picker — no slack). Numbers within a column are sorted
|
||||
ascending top-to-bottom (lô tô hội chợ Tân Tân convention).
|
||||
|
||||
### Host State (`storagePrefix="loto_master"`)
|
||||
```
|
||||
|
||||
Reference in new issue
Block a user