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:
2026-04-26 23:40:07 +07:00
parent 189ae3d4e5
commit de6bdf7eec
5 changed files with 277 additions and 26 deletions
+10 -8
View File
@@ -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:149167 | 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 19, col 8 holds 8090. |
| `handleCellClick()` | PlayerBoard.svelte | Toggle crossed[row][col]. |
| `saveGrid()` / `loadGrid()` | game-logic.js | localStorage with prefix-based keys. |
Last reviewed: 2026-04-26
+12 -7
View File
@@ -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 190 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., 175 for American bingo) instead of hardcoded 190. Requires config UI and refactor of game logic constants.
Host selects range (e.g., 175 for American bingo) instead of hardcoded 190. 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.
---
+46 -8
View File
@@ -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 190. 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 (20142017)
where players ran build of physical bingo cards.
The inspiration comes from TN1 class reunions (20142017) 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 = 19, col 1 = 1019, …, col 7 = 7079,
col 8 = 8090.
- **Within a column**: numbers placed top-to-bottom in **ascending** order.
- **Number pool**: 190.
- **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 190 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 (175 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 190). Click cells to mark them as numbers are called.
- **Host**: Draws numbers randomly from a shuffled 190 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 190 deck, shows the
current number, and tracks all called numbers on an **11×9 master board
aligned by ones-digit** (col 0 = 19, col 8 = 8090; 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)
+6 -3
View File
@@ -13,8 +13,9 @@ Entry
└─ /master (Host Page)
├─ Load loto_master (called/remaining)
├─ Display 9×10 master board (numbers 190)
├─ Draw button shows next called number
├─ Display 11×9 master board (numbers 190, aligned by ones-digit;
│ col 0 = 19, col 8 = 8090; 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"`)
```
@@ -0,0 +1,203 @@
# Lô Tô Rules Reference: SvelteKit Web App Implementation Guide
**Report Date:** 26 Apr 2026
**Research Scope:** Vietnamese Lô tô (Bingo 90 / Tombola) rules, card layout, winning conditions, and host mechanics
**Sources Consulted:** Wikipedia tiếng Việt, English Bingo 90 references, Vietnamese gaming blogs, official game set descriptions
---
## 1. PLAYER CARD LAYOUT
### Standard Format (Confirmed across sources)
- **Dimensions:** 3 rows × 9 columns grid
- **Numbers per row:** 5 marked, 4 blank spaces
- **Total numbers per card:** 15 (out of 190 pool)
- **Number distribution:** Column-by-column allocation (see below)
### Column Organization & Number Ranges
| Column | Range | Note |
|--------|-------|------|
| 1 | 19 | 9 numbers |
| 2 | 1019 | 10 numbers |
| 3 | 2029 | 10 numbers |
| 4 | 3039 | 10 numbers |
| 5 | 4049 | 10 numbers |
| 6 | 5059 | 10 numbers |
| 7 | 6069 | 10 numbers |
| 8 | 7079 | 10 numbers |
| 9 | 8090 | 11 numbers |
**Source:** [Bingo 90 Standard Rules](https://www.tombola.co.uk/bingo/how-to-play-bingo90), [Wikipedia Lô tô](https://vi.wikipedia.org/wiki/Lô_tô), [Tombola Rules](https://www.mundigames.com/multiplayer/tombola/rules/)
### Ascending Order Rule
**Within each column, numbers appear in ascending order from top to bottom.** A column may have 1, 2, or 3 numbers; never more than 3 per column (due to 3 rows).
**Source:** [Tombola Card Layout Explanation](https://oboe.com/learn/create-tombola-bingo-cards-in-pdf-fdzo/understanding-tombola-card-layout-0)
### Card Generation Implications for Your App
- **Exactly 5 per row:** Standard requirement (not an invention)
- **Exactly 5 per column (on average):** NOT a hard rule. Columns can have 13 numbers each; the total is always 15.
- **Current implementation (9×9 with 5 per row & per column):** **INCORRECT** — This creates a 45-number card (3×15), not standard 15-number card. Should be **3×9 grid with 15 total.**
---
## 2. MASTER BOARD (QUẢN TRÒ DISPLAY)
### Layout & Tracking Function
No single standardized master board layout found in Vietnamese sources. However, British Bingo 90 practice is:
- **9 columns × 10 rows** (representing 90 positions)
- Column headings: B(19), I(1019), N(2029), G(3039), O(4049), …, O(8090) [note: "O" at start & end for symmetry in physical boards]
- Marked/crossed when called
### Vietnamese Quản Trò Practice
One person (quản trò or "cái") draws and calls numbers. Tracking happens verbally + manually via:
- Physical board with markers, or
- Pen-marked paper grid
No specific Vietnamese master board convention found; recommend adopting **9×10 column-by-tens layout** (matches player card column structure for easy mapping).
**Source:** [Bingo Caller Setup](https://www.bingocardcreator.com/bingo-caller/1-90/), [Game Master Role](https://antoursvietnam.com/how-to-play-lotto-show-lo-to-guide/)
---
## 3. DRAWING & CALLING MECHANICS
### Number Range
- **Standard:** 190 (confirmed for Bingo 90 adaptation in Vietnam)
- **Variation noted:** Some older sources mention 160, but modern Vietnamese games use 190
**Source:** [Lô Tô App References](https://apps.apple.com/vn/app/lô-tô/id1353746681), [Wikipedia tiếng Việt](https://vi.wikipedia.org/wiki/Lô_tô)
### Drawing Order
- **Method:** Pure random draw from bag/cage
- **No fixed opening number:** Unlike some lotteries, no mandated first-draw convention found
- **Hô lô tô chants:** Cultural recitation/singing occurs during calling (entertainment), but does NOT affect game rules
**Source:** [Vietnamese Game Master Culture](https://dochoicholon.com/bo-tro-choi-keu-lo-to-90-so-bang-giay-va-go.html)
---
## 4. WINNING CONDITIONS & CALLING PATTERNS
### Primary Win Condition: "Kinh"
**Definition:** Player completes one full horizontal row (5 consecutive marked numbers on that row).
**Call:** Player shouts "Kinh!" (Vietnamese: "Kinh!" = "I won!")
**Verification:** Quản trò checks the winning card to confirm all 5 numbers on that row were called.
**Source:** [Vietnamese Game Rules](https://shopee.vn/blog/cach-choi-lo-to/), [Wikipedia](https://vi.wikipedia.org/wiki/Lô_tô), [Vietcetera](https://vietcetera.com/en/feeling-lucky-try-this-vietnamese-traditional-game-called-lo-to)
### Waiting State: "Hò"
**Definition:** Player has 4 numbers in a row, waiting on 1 final number.
**Call:** Player announces "Hò" (Vietnamese: "Hò" = "I'm waiting")
**Effect:** Signals to quản trò and other players that this player is close to winning. Does NOT stop the game.
**Source:** [Vietnamese Game Master Mechanics](https://dochoicholon.com/bo-tro-choi-keu-lo-to-90-so-bang-giay-va-go.html)
### Extended Winning Patterns (Bingo 90 Standard, adopted in Vietnam)
1. **One Line ("một hàng"):** First horizontal row completed → **Primary prize**
2. **Two Lines ("hai hàng"):** Any two horizontal rows completed → **Secondary prize** (higher payout)
3. **Full House ("bingo" or "toàn bộ"):** All 15 numbers on the card marked → **Grand prize** (highest payout)
**Note:** "Kinh đôi" and "kinh ba" (mentioned in some sources) refer to secondary/tertiary prizes, not distinct patterns—terminology varies by region/host.
**Source:** [Bingo 90 Winning Patterns](https://www.bingosites.co.uk/90-ball-bingo/), [Tombola Multiplayer Rules](https://www.mundigames.com/multiplayer/tombola/rules/)
### Multiple Winners
**Same-draw rule:** If two players complete the same pattern (e.g., both fill one line on same draw), **prize splits equally** or house rules determine payout.
---
## 5. HOUSE & MASTER RULES
### Can Master Play Their Own Card?
**Yes, confirmed.** Quản trò can participate as a player while managing the draw.
**Source:** [Game Master as Player](https://dochoicholon.com/bo-tro-choi-keu-lo-to-90-so-bang-giay-va-go.html) (implies dual role), [Vietnamese game sets](https://www.sayweee.com/en/product/Vietnamese-Loto-Games/85136) (standard sets include 16 cards, host takes 1 or more)
### Stake / Pot Structure
Not a rules matter—informal/social game. No standardized betting mechanism in traditional rules; modern apps may implement custom stake systems.
### Game Flow
1. Quản trò distributes cards (116 per set)
2. First number drawn; quản trò calls it
3. Players mark matching numbers
4. On each draw: players check for "hò" (4-in-row) or "kinh" (5-in-row)
5. Winner verified → prize awarded
6. Game continues until all cards are full or organizer stops
---
## 6. IMPLEMENTATION VALIDATION & GOTCHAS
### Current App Issues (Assumed from Your Description)
| Issue | Severity | Fix |
|-------|----------|-----|
| **9×9 grid (45 numbers)** | CRITICAL | Change to **3×9 grid (15 numbers)** |
| **Enforce exactly 5 per column** | MINOR | Relax: allow **13 per column**, total 15; column sums should average ~1.67 |
| **Master board as 11×9 (99 positions)** | MODERATE | Change to **9×10 (90 positions)** or keep 11×9 if you're tracking an extra row; ensure column labeling matches player card ranges |
| **Missing "Hò" state** | MODERATE | Add call state when 4 numbers marked in a row; player can announce before "kinh" |
| **Missing two-line / full-house detection** | MODERATE | Implement pattern detection for 2 rows + full card (Bingo 90 standard) |
### Regional Variations (Unconfirmed in Sources)
No North/Central/South differences for Lô tô rules found. Game appears standardized across Vietnam, with cultural/entertainment variations (chanting, poetry) but not rule variations.
---
## 7. RECOMMENDATIONS FOR YOUR APP
### Immediate Changes (Pre-Release)
1. **Revert card to 3 rows × 9 columns × 15 numbers total**
- Regenerate card algorithm to pick 5 random per row, ensuring column constraints (13 per column)
- Verify column ranges (19, 1019, …, 8090)
- Enforce ascending order within each column
2. **Add "Hò" state tracking**
- Player can announce "Hò" when 4 in a row marked
- Display visually on card UI (e.g., highlight the waiting row)
3. **Master board: align with 9×10 layout or 9×9 (clarify your choice)**
- If 11×9: document why (e.g., custom feature) so it doesn't confuse players
4. **Implement full-house & two-line detection**
- Not just one-line (kinh) wins
### Nice-to-Have (Post-Release)
- Add hô lô tô chant audio library (for authenticity, entertainment)
- Regional chant variants (if monetizing regionally)
- Multiplayer: simultaneous "kinh" handling & pot-splitting logic
---
## 8. UNRESOLVED / CONTESTED CLAIMS
1. **Master board standard layout:** No Vietnamese source specifies quản trò's tracking board. British Bingo 90 uses 9×10; your 11×9 may be valid local variation.
- **Action:** Verify with your user base or adopt 9×10 as safer default
2. **"Kinh đôi" / "kinh ba" terminology:** Mentioned in searches but not defined as distinct win conditions. Likely regional slang for two-line / full-house wins.
- **Action:** Treat as marketing terminology, implement underlying Bingo 90 patterns
3. **Regional rule differences (Bắc/Trung/Nam):** No sources confirm variations
- **Action:** Assume rules are nationwide; note for future regional research if user feedback suggests otherwise
4. **Card generation randomness:** Sources don't specify algorithm (fully random per card? seeded per player? repeated numbers across decks?). Assumed independent random per card.
- **Action:** Implement independent random generation; allow deck-wide seed if you need reproducible games
---
## 9. SOURCE CREDIBILITY SUMMARY
| Source | Credibility | Used For |
|--------|------------|----------|
| Wikipedia Lô tô (tiếng Việt) | HIGH | Card layout, "kinh" definition, 3×9 grid |
| Tombola.co.uk (British Bingo 90) | HIGH | Column ranges, ascending order rule, master board concept |
| Vietnamese gaming blogs (Shopee, BachHoaXanh) | MEDIUM | Game flow, "hò" state, cultural context |
| Game set product descriptions (Amazon, Sayweee) | MEDIUM | Game components, number ranges (190) |
| Vietcetera cultural article | LOW | Cultural significance only; rules vague |
**Cross-check result:** Card layout (3×9, 15 numbers, column ranges 19 through 8090) **confirmed across 3+ independent sources**. Winning conditions (kinh for one row, two rows, full house) **confirmed via Bingo 90 standard + Vietnamese sources**.
---
**End of Report**