CombinationDetector
通用牌型检测器,将一组卡牌识别为 CardCombination。
概述
CombinationDetector 是 combination 系统的识别组件,位于 src/combination/CombinationDetector.ts。它仅覆盖与具体游戏无关的常见牌型:
- 单张(
SINGLE) - 对子(
PAIR) - 三张(
TRIPLE) - 四张(
FOUR_OF_A_KIND) - 顺子(
STRAIGHT,长度由minStraightLength决定)
不可识别的组合统一返回 CombinationType.UNKNOWN,并在 metadata.reason 中给出原因。
设计上为纯函数式:依赖注入 RankResolver,不持有可变状态,可在多个游戏间共享实例。
各游戏的专属牌型(如斗地主的飞机、火箭)应在
src/plugins/<game>/combinations/中独立扩展,不应在此处添加。
构造函数
new CombinationDetector(options?)
ts
new CombinationDetector(options?: CombinationDetectorOptions)参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
options | CombinationDetectorOptions | 否 | {} | 配置选项 |
CombinationDetectorOptions
ts
interface CombinationDetectorOptions {
resolver?: RankResolver
minStraightLength?: number
}| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
resolver | RankResolver | 否 | new StandardPokerRankResolver() | 点数解析器 |
minStraightLength | number | 否 | 5 | 顺子所需的最短长度 |
属性
无公开属性。
方法
detect()
检测卡牌集合的牌型。
ts
detect(cards: readonly Card[]): CardCombination参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
cards | readonly Card[] | 是 | — | 待检测的卡牌集合(不会被修改) |
返回值
CardCombination:包含类型、排序后卡牌与点数信息的描述对象。
行为
识别流程按以下顺序执行,命中即返回:
- 空集:返回
{ type: UNKNOWN, cards: [], metadata: { reason: 'empty' } }。 - 单张(
cards.length === 1):返回SINGLE,rank与value均设为该牌点数。 - 单点数多张(
uniqueRankCount === 1):- 2 张 →
PAIR - 3 张 →
TRIPLE - 4 张 →
FOUR_OF_A_KIND - 其他张数 →
UNKNOWN,metadata.reason = 'too many cards of same rank'
- 2 张 →
- 顺子(
uniqueRankCount === cards.length && cards.length >= minStraightLength):- 对去重后的点数序列升序排序,调用内部
isConsecutive判定是否每相邻两项差 1; - 若连续,返回
STRAIGHT,rank与value设为最高点数high,metadata包含{ length, low, high }。
- 对去重后的点数序列升序排序,调用内部
- 其他:返回
UNKNOWN,metadata.reason = 'no matching pattern'。
isConsecutive 内部函数
判定给定的(已排序、去重的)点数序列是否连续递增 1。用于识别 STRAIGHT 牌型;不足 2 个元素的序列视为非连续。该函数为模块私有,不对外导出。
示例
ts
import { CombinationDetector } from '../combination/CombinationDetector.js'
import { CombinationType } from '../combination/CombinationType.js'
import type { Card } from '../card/Card.js'
const detector = new CombinationDetector()
const single: Card[] = [
{ id: 'c1', type: 'standard', suit: 'spade', rank: '5', data: {} }
]
detector.detect(single)
// -> { type: SINGLE, cards: [...], rank: 5, value: 5 }
const pair: Card[] = [
{ id: 'c1', type: 'standard', suit: 'spade', rank: '5', data: {} },
{ id: 'c2', type: 'standard', suit: 'heart', rank: '5', data: {} }
]
detector.detect(pair)
// -> { type: PAIR, cards: [...], rank: 5, value: 5 }
const straight: Card[] = [
{ id: 's5', type: 'standard', suit: 'spade', rank: '5', data: {} },
{ id: 's6', type: 'standard', suit: 'spade', rank: '6', data: {} },
{ id: 's7', type: 'standard', suit: 'spade', rank: '7', data: {} },
{ id: 's8', type: 'standard', suit: 'spade', rank: '8', data: {} },
{ id: 's9', type: 'standard', suit: 'spade', rank: '9', data: {} }
]
detector.detect(straight)
// -> { type: STRAIGHT, cards: [...], rank: 9, value: 9, metadata: { length: 5, low: 5, high: 9 } }
detector.detect([])
// -> { type: UNKNOWN, cards: [], metadata: { reason: 'empty' } }自定义顺子长度
通过 minStraightLength 可调整识别顺子所需的最短长度:
ts
import { CombinationDetector } from '../combination/CombinationDetector.js'
// 三张连续即视为顺子
const detector = new CombinationDetector({ minStraightLength: 3 })自定义点数语义
注入 LowAceRankResolver 可让 A 视为最低牌(1),支持 A-2-3-4-5 形态的低 A 顺子:
ts
import { CombinationDetector } from '../combination/CombinationDetector.js'
import { LowAceRankResolver } from '../combination/CombinationValue.js'
const detector = new CombinationDetector({ resolver: new LowAceRankResolver() })注意事项
- 该检测器不识别同花、葫芦、同花顺等高级牌型。源码
CombinationType枚举中亦未定义FLUSH/FULL_HOUSE/STRAIGHT_FLUSH,仅在任务文档中提及 —— 实际源码以CombinationType为准。 - 同一实例可被多个游戏共享;构造一次后多次调用
detect()之间无副作用。 - 返回的
cards字段是经sortByRank排序后的新数组,不会持有对入参数组的引用。