| 1 | import type { Tile } from './tiles'; |
| 2 | |
| 3 | export type SeatId = 0 | 1 | 2 | 3; |
| 4 | |
| 5 | /** Placeholder names, until somebody types their own on the settings screen. */ |
| 6 | export const DEFAULT_NAMES = ['玩家 1', '玩家 2', '玩家 3', '玩家 4']; |
| 7 | |
| 8 | export type MeldKind = |
| 9 | | 'chow' // 吃 |
| 10 | | 'pung' // 碰 |
| 11 | | 'kong' // 明槓 (claimed from a discard) |
| 12 | | 'ankong' // 暗槓 (four from hand) |
| 13 | | 'addkong'; // 加槓 (fourth tile added to an exposed pung) |
| 14 | |
| 15 | export interface Meld { |
| 16 | kind: MeldKind; |
| 17 | /** Sorted tiles making up the meld. */ |
| 18 | tiles: Tile[]; |
| 19 | /** Whose discard it came from, if any. */ |
| 20 | from?: SeatId; |
| 21 | } |
| 22 | |
| 23 | export const meldIsConcealed = (m: Meld) => m.kind === 'ankong'; |
| 24 | export const meldIsKong = (m: Meld) => m.kind === 'kong' || m.kind === 'ankong' || m.kind === 'addkong'; |
| 25 | |
| 26 | export interface Player { |
| 27 | name: string; |
| 28 | hand: Tile[]; // concealed, sorted |
| 29 | melds: Meld[]; |
| 30 | flowers: Tile[]; |
| 31 | discards: Tile[]; |
| 32 | score: number; |
| 33 | } |
| 34 | |
| 35 | export interface Rules { |
| 36 | /** 底 — flat amount every payer contributes. */ |
| 37 | base: number; |
| 38 | /** 台 — value of one tai. */ |
| 39 | taiValue: number; |
| 40 | /** Tiles left in the wall when the hand is declared a draw (流局). */ |
| 41 | wallReserve: number; |
| 42 | /** Starting chips per player. */ |
| 43 | startingScore: number; |
| 44 | /** |
| 45 | * 過水 — pass on a tile you could have won on and it is dead to you until |
| 46 | * your own next draw. |
| 47 | */ |
| 48 | sacredDiscard: boolean; |
| 49 | /** |
| 50 | * Whether taking a 碰/吃/槓 also lifts a 過水 lock, or only drawing does. |
| 51 | * Tables genuinely differ, hence the flag. |
| 52 | */ |
| 53 | sacredClearedByClaim: boolean; |
| 54 | /** 一炮多響 — one discard pays out to every seat that declares on it. */ |
| 55 | multipleWinners: boolean; |
| 56 | /** |
| 57 | * 包牌 — feed the third dragon or wind pung to an obvious 大三元 / 大四喜 |
| 58 | * and you answer for the whole hand yourself. |
| 59 | */ |
| 60 | liability: boolean; |
| 61 | } |
| 62 | |
| 63 | export const DEFAULT_RULES: Rules = { |
| 64 | base: 3, |
| 65 | taiValue: 1, |
| 66 | wallReserve: 16, |
| 67 | startingScore: 100, |
| 68 | sacredDiscard: true, |
| 69 | sacredClearedByClaim: false, |
| 70 | multipleWinners: false, |
| 71 | liability: true, |
| 72 | }; |