From de6bdf7eec4bfce35a49d49a6cf089938abea08b Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Sun, 26 Apr 2026 23:40:07 +0700 Subject: [PATCH] =?UTF-8?q?docs:=20lock=20scope=20to=20l=C3=B4=20t=C3=B4?= =?UTF-8?q?=20h=E1=BB=99i=20ch=E1=BB=A3=20t=C3=A2n=20t=C3=A2n=20variant?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- web/docs/codebase-summary.md | 18 +- web/docs/development-roadmap.md | 19 +- web/docs/project-overview-pdr.md | 54 ++++- web/docs/system-architecture.md | 9 +- .../researcher-260426-2324-loto-rules.md | 203 ++++++++++++++++++ 5 files changed, 277 insertions(+), 26 deletions(-) create mode 100644 web/plans/reports/researcher-260426-2324-loto-rules.md diff --git a/web/docs/codebase-summary.md b/web/docs/codebase-summary.md index 87afe39..ea30db3 100644 --- a/web/docs/codebase-summary.md +++ b/web/docs/codebase-summary.md @@ -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 diff --git a/web/docs/development-roadmap.md b/web/docs/development-roadmap.md index e2ed4bb..47ba202 100644 --- a/web/docs/development-roadmap.md +++ b/web/docs/development-roadmap.md @@ -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. --- diff --git a/web/docs/project-overview-pdr.md b/web/docs/project-overview-pdr.md index 302bf68..c1379d0 100644 --- a/web/docs/project-overview-pdr.md +++ b/web/docs/project-overview-pdr.md @@ -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) diff --git a/web/docs/system-architecture.md b/web/docs/system-architecture.md index 4303c70..5943c51 100644 --- a/web/docs/system-architecture.md +++ b/web/docs/system-architecture.md @@ -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"`) ``` diff --git a/web/plans/reports/researcher-260426-2324-loto-rules.md b/web/plans/reports/researcher-260426-2324-loto-rules.md new file mode 100644 index 0000000..5783de4 --- /dev/null +++ b/web/plans/reports/researcher-260426-2324-loto-rules.md @@ -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 1–90 pool) +- **Number distribution:** Column-by-column allocation (see below) + +### Column Organization & Number Ranges + +| Column | Range | Note | +|--------|-------|------| +| 1 | 1–9 | 9 numbers | +| 2 | 10–19 | 10 numbers | +| 3 | 20–29 | 10 numbers | +| 4 | 30–39 | 10 numbers | +| 5 | 40–49 | 10 numbers | +| 6 | 50–59 | 10 numbers | +| 7 | 60–69 | 10 numbers | +| 8 | 70–79 | 10 numbers | +| 9 | 80–90 | 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 1–3 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(1–9), I(10–19), N(20–29), G(30–39), O(40–49), …, O(80–90) [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:** 1–90 (confirmed for Bingo 90 adaptation in Vietnam) +- **Variation noted:** Some older sources mention 1–60, but modern Vietnamese games use 1–90 + +**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 (1–16 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 **1–3 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 (1–3 per column) + - Verify column ranges (1–9, 10–19, …, 80–90) + - 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 (1–90) | +| Vietcetera cultural article | LOW | Cultural significance only; rules vague | + +**Cross-check result:** Card layout (3×9, 15 numbers, column ranges 1–9 through 80–90) **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**