texas-poker-core 1.4.23 → 1.4.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -598,5 +598,14 @@ fix: 修复结算金额分配异常
598
598
 
599
599
  增加外部设置玩家手牌&结算信息的方法
600
600
 
601
- ## 1.4.23
602
- bugfix
601
+ ## 1.4.24
602
+
603
+ - `HandEnded` / `HandSettlement` 快照增加 `bestRankSignature`,与桌上最强 `bestPokes[0]` 对齐
604
+ - 导出 `rankSignatureToDisplayGroups`;顺子 wheel 在 `rankSignatureToRanks` 中 A 置于末位
605
+
606
+ ## 1.4.25
607
+
608
+ - 导出 `createStandardDeckPokes`,生成标准 52 张牌(与 `Deck` 建牌顺序一致)
609
+
610
+ ## 1.4.26
611
+ export new functiono
@@ -38,7 +38,8 @@ var HandSettlement = exports.HandSettlement = /*#__PURE__*/function () {
38
38
  _classPrivateFieldInitSpec(this, _snapshot, {
39
39
  rankCategory: undefined,
40
40
  pokes: [],
41
- rankStrength: 0
41
+ rankStrength: 0,
42
+ rankSignature: undefined
42
43
  });
43
44
  _classPrivateFieldInitSpec(this, _evalByUserId, new Map());
44
45
  }
@@ -63,7 +64,8 @@ var HandSettlement = exports.HandSettlement = /*#__PURE__*/function () {
63
64
  _classPrivateFieldSet(_snapshot, this, {
64
65
  rankCategory: undefined,
65
66
  pokes: [],
66
- rankStrength: 0
67
+ rankStrength: 0,
68
+ rankSignature: undefined
67
69
  });
68
70
  _classPrivateFieldGet(_evalByUserId, this).clear();
69
71
  }
@@ -94,7 +96,8 @@ function _snapshotFromShowdownPlayers(stillIn) {
94
96
  return {
95
97
  rankCategory: undefined,
96
98
  pokes: [],
97
- rankStrength: 0
99
+ rankStrength: 0,
100
+ rankSignature: undefined
98
101
  };
99
102
  }
100
103
  var maxStrength = Math.max.apply(Math, _toConsumableArray(stillIn.map(function (p) {
@@ -110,7 +113,8 @@ function _snapshotFromShowdownPlayers(stillIn) {
110
113
  return {
111
114
  rankCategory: undefined,
112
115
  pokes: [],
113
- rankStrength: 0
116
+ rankStrength: 0,
117
+ rankSignature: undefined
114
118
  };
115
119
  }
116
120
  return {
@@ -118,6 +122,7 @@ function _snapshotFromShowdownPlayers(stillIn) {
118
122
  pokes: tiedAtTop.map(function (p) {
119
123
  return _this2.getPlayerEval(p.id).bestFiveCards;
120
124
  }),
121
- rankStrength: maxStrength
125
+ rankStrength: maxStrength,
126
+ rankSignature: topEval.rankSignature
122
127
  };
123
128
  }
@@ -655,7 +655,8 @@ function _emitShowdownHandEnded() {
655
655
  var _classPrivateFieldGet5 = _classPrivateFieldGet(_hand, this).settlement.snapshot,
656
656
  rankCategory = _classPrivateFieldGet5.rankCategory,
657
657
  pokes = _classPrivateFieldGet5.pokes,
658
- rankStrength = _classPrivateFieldGet5.rankStrength;
658
+ rankStrength = _classPrivateFieldGet5.rankStrength,
659
+ rankSignature = _classPrivateFieldGet5.rankSignature;
659
660
  var endStage = _classPrivateFieldGet(_hand, this).stage;
660
661
  var pokesRevealed = this.getRevealedPokes();
661
662
  _classPrivateFieldGet(_handEvents, this).push({
@@ -667,6 +668,7 @@ function _emitShowdownHandEnded() {
667
668
  showHandPokes: true,
668
669
  bestPokes: pokes,
669
670
  bestRankCategory: rankCategory,
671
+ bestRankSignature: rankSignature,
670
672
  bestRankStrength: rankStrength
671
673
  })
672
674
  });
package/dist/Deck/core.js CHANGED
@@ -21,6 +21,12 @@ Object.defineProperty(exports, "compareRankSignature", {
21
21
  return _handCompare.compareRankSignature;
22
22
  }
23
23
  });
24
+ Object.defineProperty(exports, "createStandardDeckPokes", {
25
+ enumerable: true,
26
+ get: function get() {
27
+ return _standardDeck.createStandardDeckPokes;
28
+ }
29
+ });
24
30
  Object.defineProperty(exports, "formatterPoke", {
25
31
  enumerable: true,
26
32
  get: function get() {
@@ -69,6 +75,19 @@ Object.defineProperty(exports, "isStraight", {
69
75
  return _handEvaluation.isStraight;
70
76
  }
71
77
  });
78
+ Object.defineProperty(exports, "rankSignatureToDisplayGroups", {
79
+ enumerable: true,
80
+ get: function get() {
81
+ return _handCompare.rankSignatureToDisplayGroups;
82
+ }
83
+ });
84
+ Object.defineProperty(exports, "rankSignatureToRanks", {
85
+ enumerable: true,
86
+ get: function get() {
87
+ return _handCompare.rankSignatureToRanks;
88
+ }
89
+ });
90
+ var _standardDeck = require("./standardDeck");
72
91
  var _format = require("./format");
73
92
  var _handEvaluation = require("./handEvaluation");
74
93
  var _handCompare = require("./handCompare");
@@ -6,7 +6,176 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.compareRankSignature = exports.compareFn = void 0;
7
7
  exports.getFiveCardsStrength = getFiveCardsStrength;
8
8
  exports.getStrengthFromRankSignature = getStrengthFromRankSignature;
9
+ exports.rankSignatureToDisplayGroups = rankSignatureToDisplayGroups;
10
+ exports.rankSignatureToRanks = rankSignatureToRanks;
9
11
  var _handEvaluation = require("./handEvaluation");
12
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
13
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
14
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
15
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
16
+ function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
17
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
18
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
19
+ function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
20
+ function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
21
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
22
+ var NUMERIC_TO_RANK = {
23
+ 2: '2',
24
+ 3: '3',
25
+ 4: '4',
26
+ 5: '5',
27
+ 6: '6',
28
+ 7: '7',
29
+ 8: '8',
30
+ 9: '9',
31
+ 10: 't',
32
+ 11: 'j',
33
+ 12: 'q',
34
+ 13: 'k',
35
+ 14: 'a'
36
+ };
37
+ function numericRankToRank(v) {
38
+ var r = NUMERIC_TO_RANK[v];
39
+ if (r === undefined) {
40
+ throw new Error("rankSignatureToRanks: \u975E\u6CD5\u70B9\u6570 ".concat(v, "\uFF08\u987B\u4E3A 2\u201314\uFF09"));
41
+ }
42
+ return r;
43
+ }
44
+
45
+ /**
46
+ * 与 `isStraight` / 签名中 `u`/`y` 的 `max` 一致:五张顺子点数顺序。
47
+ * 仅 Broadway(A-K-Q-J-T,`max === 14`)A 作高牌;其余含 A 的顺子仅为 wheel,A 视为 1 排在末位。
48
+ */
49
+ function straightRanksFromMax(max) {
50
+ if (max === 5) {
51
+ return ['5', '4', '3', '2', 'a'];
52
+ }
53
+ return [max, max - 1, max - 2, max - 3, max - 4].map(numericRankToRank);
54
+ }
55
+
56
+ /**
57
+ * 将 `RankSignature` 展开为五张牌的点数(`Rank`),与 `getFiveCardsRankSignature` 编码对称。
58
+ * 顺子 wheel(`u5`/`y5`)为 5→A 展示顺序,A 在末位;Broadway 仍为 A→T。
59
+ * `x`(四条)当前签名仅含四条点数,踢脚未编码,第五位为 `null`。
60
+ */
61
+ function rankSignatureToRanks(rankSignature) {
62
+ var category = rankSignature[0];
63
+ var nums = parseRankNumbersFromRankSignature(rankSignature);
64
+ switch (category) {
65
+ case 'z':
66
+ return ['a', 'k', 'q', 'j', 't'];
67
+ case 'y':
68
+ case 'u':
69
+ {
70
+ if (nums.length !== 1) {
71
+ throw new Error("rankSignatureToRanks: ".concat(category, " \u578B\u7B7E\u540D\u987B\u542B 1 \u4E2A max \u6BB5\uFF0C\u5B9E\u9645 ").concat(nums.length));
72
+ }
73
+ return straightRanksFromMax(nums[0]);
74
+ }
75
+ case 'q':
76
+ case 'v':
77
+ {
78
+ if (nums.length !== 5) {
79
+ throw new Error("rankSignatureToRanks: ".concat(category, " \u578B\u7B7E\u540D\u987B\u542B 5 \u4E2A\u70B9\u6570\u6BB5\uFF0C\u5B9E\u9645 ").concat(nums.length));
80
+ }
81
+ return nums.map(numericRankToRank);
82
+ }
83
+ case 'r':
84
+ {
85
+ if (nums.length !== 4) {
86
+ throw new Error("rankSignatureToRanks: r \u578B\u7B7E\u540D\u987B\u4E3A\u300C\u5BF9\u5B50+3 \u8E22\u811A\u300D\u5171 4 \u6BB5\uFF0C\u5B9E\u9645 ".concat(nums.length));
87
+ }
88
+ var p = nums[0],
89
+ kick = nums.slice(1);
90
+ var pr = numericRankToRank(p);
91
+ return [pr, pr].concat(_toConsumableArray(kick.map(numericRankToRank)));
92
+ }
93
+ case 's':
94
+ {
95
+ if (nums.length !== 3) {
96
+ throw new Error("rankSignatureToRanks: s \u578B\u7B7E\u540D\u987B\u4E3A\u300C\u9AD8\u5BF9+\u4F4E\u5BF9+\u8E22\u811A\u300D\u5171 3 \u6BB5\uFF0C\u5B9E\u9645 ".concat(nums.length));
97
+ }
98
+ var _nums$map = nums.map(numericRankToRank),
99
+ _nums$map2 = _slicedToArray(_nums$map, 3),
100
+ hi = _nums$map2[0],
101
+ lo = _nums$map2[1],
102
+ k = _nums$map2[2];
103
+ return [hi, hi, lo, lo, k];
104
+ }
105
+ case 't':
106
+ {
107
+ if (nums.length !== 3) {
108
+ throw new Error("rankSignatureToRanks: t \u578B\u7B7E\u540D\u987B\u4E3A\u300C\u4E09\u6761+2 \u8E22\u811A\u300D\u5171 3 \u6BB5\uFF0C\u5B9E\u9645 ".concat(nums.length));
109
+ }
110
+ var _nums$map3 = nums.map(numericRankToRank),
111
+ _nums$map4 = _slicedToArray(_nums$map3, 3),
112
+ tr = _nums$map4[0],
113
+ k1 = _nums$map4[1],
114
+ k2 = _nums$map4[2];
115
+ return [tr, tr, tr, k1, k2];
116
+ }
117
+ case 'w':
118
+ {
119
+ if (nums.length !== 2) {
120
+ throw new Error("rankSignatureToRanks: w \u578B\u7B7E\u540D\u987B\u4E3A\u300C\u4E09\u6761+\u5BF9\u5B50\u300D\u5171 2 \u6BB5\uFF0C\u5B9E\u9645 ".concat(nums.length));
121
+ }
122
+ var _nums$map5 = nums.map(numericRankToRank),
123
+ _nums$map6 = _slicedToArray(_nums$map5, 2),
124
+ _tr = _nums$map6[0],
125
+ _pr = _nums$map6[1];
126
+ return [_tr, _tr, _tr, _pr, _pr];
127
+ }
128
+ case 'x':
129
+ {
130
+ if (nums.length !== 1) {
131
+ throw new Error("rankSignatureToRanks: x \u578B\u7B7E\u540D\u987B\u542B 1 \u4E2A\u70B9\u6570\u6BB5\uFF0C\u5B9E\u9645 ".concat(nums.length));
132
+ }
133
+ var q = numericRankToRank(nums[0]);
134
+ return [q, q, q, q, null];
135
+ }
136
+ default:
137
+ throw new Error("rankSignatureToRanks: \u672A\u77E5\u724C\u578B\u524D\u7F00 ".concat(category));
138
+ }
139
+ }
140
+
141
+ /** 供 UI 分组渲染:每组 `ranks` 为从左到右、已合并同点的连续张(与 `rankSignatureToRanks` 顺序一致)。 */
142
+
143
+ var FLAT_DISPLAY_CATEGORIES = new Set(['q', 'v', 'u', 'y', 'z']);
144
+
145
+ /**
146
+ * 将牌力签名映射为展示用分组(间距与样式由应用层决定)。
147
+ * - `q`/`v`/`u`/`y`/`z`:每张一组;顺子 wheel 时 A 已在末位(见 `straightRanksFromMax`)。
148
+ * - `r`/`s`/`t`/`w`/`x`:连续同点合并为一组。
149
+ */
150
+ function rankSignatureToDisplayGroups(rankSignature) {
151
+ var category = rankSignature[0];
152
+ var expanded = rankSignatureToRanks(rankSignature);
153
+ if (FLAT_DISPLAY_CATEGORIES.has(category)) {
154
+ var _ranks = expanded.filter(function (r) {
155
+ return r !== null;
156
+ });
157
+ return _ranks.map(function (r) {
158
+ return {
159
+ ranks: [r]
160
+ };
161
+ });
162
+ }
163
+ var ranks = expanded.filter(function (r) {
164
+ return r !== null;
165
+ });
166
+ var groups = [];
167
+ var i = 0;
168
+ while (i < ranks.length) {
169
+ var j = i + 1;
170
+ while (j < ranks.length && ranks[j] === ranks[i]) j++;
171
+ groups.push({
172
+ ranks: ranks.slice(i, j)
173
+ });
174
+ i = j;
175
+ }
176
+ return groups;
177
+ }
178
+
10
179
  /**
11
180
  * RankSignature 解析、两副五张牌比较、可排序强度(与具体组合枚举无关)。
12
181
  */
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.default = void 0;
8
- var _constant = require("./constant");
8
+ var _standardDeck = require("./standardDeck");
9
9
  function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
10
10
  function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
11
11
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
@@ -83,10 +83,7 @@ var Deck = /*#__PURE__*/function () {
83
83
  }]);
84
84
  }();
85
85
  function _createDeck() {
86
- var pokes = new Array(_constant.suits.length * _constant.ranks.length).fill(0).map(function (_, i) {
87
- return "".concat(_constant.suits[Math.floor(i / _constant.ranks.length)]).concat(_constant.ranks[i % _constant.ranks.length]);
88
- });
89
- _classPrivateFieldSet(_deck, this, pokes);
86
+ _classPrivateFieldSet(_deck, this, (0, _standardDeck.createStandardDeckPokes)());
90
87
  }
91
88
  function _shuffle() {
92
89
  for (var i = _classPrivateFieldGet(_deck, this).length - 1; i > 0; i--) {
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createStandardDeckPokes = createStandardDeckPokes;
7
+ var _constant = require("./constant");
8
+ /**
9
+ * 生成标准 52 张牌(无洗牌)。
10
+ * 顺序与 `Deck` 内部建牌一致:按 `suits` 顺序,每种花色内 `ranks` 从 2 到 a(如 `h2`…`ha`,再 `s2`…)。
11
+ */
12
+ function createStandardDeckPokes() {
13
+ var n = _constant.suits.length * _constant.ranks.length;
14
+ var out = new Array(n);
15
+ for (var i = 0; i < n; i++) {
16
+ out[i] = "".concat(_constant.suits[Math.floor(i / _constant.ranks.length)]).concat(_constant.ranks[i % _constant.ranks.length]);
17
+ }
18
+ return out;
19
+ }
@@ -215,7 +215,11 @@ function reduceLastHandEndedFromDomainEvents(events) {
215
215
  outcome: p.outcome,
216
216
  pokesRevealed: p.pokesRevealed,
217
217
  endStage: p.endStage,
218
- showHandPokes: p.showHandPokes
218
+ showHandPokes: p.showHandPokes,
219
+ bestPokes: p.bestPokes,
220
+ bestRankCategory: p.bestRankCategory,
221
+ bestRankSignature: p.bestRankSignature,
222
+ bestRankStrength: p.bestRankStrength
219
223
  };
220
224
  }
221
225
  }
package/dist/index.js CHANGED
@@ -8,11 +8,14 @@ var _exportNames = {
8
8
  Texas: true,
9
9
  Deck: true,
10
10
  formatterPoke: true,
11
+ createStandardDeckPokes: true,
11
12
  getBestPokesRankSignature: true,
12
13
  compareRankSignature: true,
13
14
  getFiveCardsStrength: true,
14
15
  getStrengthFromRankSignature: true,
15
16
  getFiveCardCombinationIndices: true,
17
+ rankSignatureToRanks: true,
18
+ rankSignatureToDisplayGroups: true,
16
19
  TableStakes: true,
17
20
  CurrentHand: true,
18
21
  stageMap: true,
@@ -367,6 +370,12 @@ Object.defineProperty(exports, "createInMemoryDomainEventStore", {
367
370
  return _replay.createInMemoryDomainEventStore;
368
371
  }
369
372
  });
373
+ Object.defineProperty(exports, "createStandardDeckPokes", {
374
+ enumerable: true,
375
+ get: function get() {
376
+ return _core.createStandardDeckPokes;
377
+ }
378
+ });
370
379
  Object.defineProperty(exports, "defaultPipelineOrdered", {
371
380
  enumerable: true,
372
381
  get: function get() {
@@ -517,6 +526,18 @@ Object.defineProperty(exports, "projectCompositeReadModel", {
517
526
  return _replay.projectCompositeReadModel;
518
527
  }
519
528
  });
529
+ Object.defineProperty(exports, "rankSignatureToDisplayGroups", {
530
+ enumerable: true,
531
+ get: function get() {
532
+ return _core.rankSignatureToDisplayGroups;
533
+ }
534
+ });
535
+ Object.defineProperty(exports, "rankSignatureToRanks", {
536
+ enumerable: true,
537
+ get: function get() {
538
+ return _core.rankSignatureToRanks;
539
+ }
540
+ });
520
541
  Object.defineProperty(exports, "reduceCanonicalSessionToTableStateV1", {
521
542
  enumerable: true,
522
543
  get: function get() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "texas-poker-core",
3
- "version": "1.4.23",
3
+ "version": "1.4.26",
4
4
  "description": "德州扑克核心功能",
5
5
  "main": "dist/index.js",
6
6
  "types": "types/index.d.ts",
@@ -4,6 +4,8 @@ export type RankSettlementSnapshot = {
4
4
  rankCategory?: RankCategory;
5
5
  pokes: Poke[][];
6
6
  rankStrength: number;
7
+ /** 与 `pokes[0]` 一致的最强牌签名(多人平分牌型时各赢家 bestFive 的签名相同)。 */
8
+ rankSignature?: RankSignature;
7
9
  };
8
10
  /** 单座摊牌评估(唯一数据源;`Player` 经 `Controller.getShowdownEvalForPlayer` 只读) */
9
11
  export type ShowdownPlayerEval = {
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * 牌力相关入口:按职责拆分为 `format` / `handEvaluation` / `handCompare` / `handCombinations`,本文件保持向后兼容的聚合导出。
3
3
  */
4
+ export { createStandardDeckPokes } from './standardDeck';
4
5
  export { formatterPoke } from './format';
5
6
  export { isStraight, getFiveCardCombinationIndices, allFiveCardHandsFromPool, getFiveCardsRankSignature } from './handEvaluation';
6
- export { compareFn, compareRankSignature, getStrengthFromRankSignature, getFiveCardsStrength } from './handCompare';
7
+ export { compareFn, compareRankSignature, getStrengthFromRankSignature, getFiveCardsStrength, rankSignatureToRanks, rankSignatureToDisplayGroups } from './handCompare';
8
+ export type { RankSignatureDisplayGroup } from './handCompare';
7
9
  export { getBestFiveCards, getBestPokesRankSignature } from './handCombinations';
@@ -1,4 +1,20 @@
1
- import { Poke, RankSignature } from './constant';
1
+ import { Poke, Rank, RankSignature } from './constant';
2
+ /**
3
+ * 将 `RankSignature` 展开为五张牌的点数(`Rank`),与 `getFiveCardsRankSignature` 编码对称。
4
+ * 顺子 wheel(`u5`/`y5`)为 5→A 展示顺序,A 在末位;Broadway 仍为 A→T。
5
+ * `x`(四条)当前签名仅含四条点数,踢脚未编码,第五位为 `null`。
6
+ */
7
+ export declare function rankSignatureToRanks(rankSignature: RankSignature): (Rank | null)[];
8
+ /** 供 UI 分组渲染:每组 `ranks` 为从左到右、已合并同点的连续张(与 `rankSignatureToRanks` 顺序一致)。 */
9
+ export type RankSignatureDisplayGroup = {
10
+ ranks: Rank[];
11
+ };
12
+ /**
13
+ * 将牌力签名映射为展示用分组(间距与样式由应用层决定)。
14
+ * - `q`/`v`/`u`/`y`/`z`:每张一组;顺子 wheel 时 A 已在末位(见 `straightRanksFromMax`)。
15
+ * - `r`/`s`/`t`/`w`/`x`:连续同点合并为一组。
16
+ */
17
+ export declare function rankSignatureToDisplayGroups(rankSignature: RankSignature): RankSignatureDisplayGroup[];
2
18
  export declare const compareFn: (a: Poke[], b: Poke[]) => number;
3
19
  export declare const compareRankSignature: (p1: string, p2: string) => number;
4
20
  export declare function getStrengthFromRankSignature(rankSignature: RankSignature): number;
@@ -0,0 +1,6 @@
1
+ import { type Poke } from './constant';
2
+ /**
3
+ * 生成标准 52 张牌(无洗牌)。
4
+ * 顺序与 `Deck` 内部建牌一致:按 `suits` 顺序,每种花色内 `ranks` 从 2 到 a(如 `h2`…`ha`,再 `s2`…)。
5
+ */
6
+ export declare function createStandardDeckPokes(): Poke[];
@@ -0,0 +1 @@
1
+ export {};
@@ -1,7 +1,7 @@
1
1
  import type { Role } from '../Player/constant';
2
2
  import type { Stage } from '../Controller/stage';
3
3
  import type { ActionTypeEnum } from '../Player/constant';
4
- import type { Poke, RankCategory } from '../Deck/constant';
4
+ import type { Poke, RankCategory, RankSignature } from '../Deck/constant';
5
5
  /**
6
6
  * 思考权结束原因(计时由业务层负责时,`timeout` 在收到超时 Command 后由 Core 标记;
7
7
  * `leave`:`FoldDueToLeave` 且为本席思考窗内离场时标记)。
@@ -125,6 +125,8 @@ export type HandDomainEvent = {
125
125
  showHandPokes: boolean;
126
126
  bestPokes?: Poke[][];
127
127
  bestRankCategory?: RankCategory;
128
+ /** 与 `bestPokes[0]` 对应的牌力签名;摊牌时由引擎写入,供 WS `game-end` / 回放磁带一致下发。 */
129
+ bestRankSignature?: RankSignature;
128
130
  bestRankStrength?: number;
129
131
  };
130
132
  };
@@ -1,7 +1,7 @@
1
- import type { Poke } from '../Deck/constant';
2
1
  import type { Role } from '../Player/constant';
3
2
  import type { Stage } from '../Controller/stage';
4
3
  import type { ActionTypeEnum } from '../Player/constant';
4
+ import type { Poke, RankCategory, RankSignature } from '../Deck/constant';
5
5
  import type { TurnEndedReason, TexasDomainEvent } from '../domain/handDomainEvents';
6
6
  /** 将多段事件批(如 `dispatchCommand` + 若干 `flush*`)按顺序拼成一条磁带(新数组)。 */
7
7
  export declare function flatConcatDomainEvents(parts: readonly (readonly TexasDomainEvent[])[]): TexasDomainEvent[];
@@ -50,6 +50,10 @@ export type HandEndedReadModel = Readonly<{
50
50
  pokesRevealed: readonly Poke[];
51
51
  endStage: Stage;
52
52
  showHandPokes: boolean;
53
+ bestPokes?: readonly (readonly Poke[])[];
54
+ bestRankCategory?: RankCategory;
55
+ bestRankSignature?: RankSignature;
56
+ bestRankStrength?: number;
53
57
  }>;
54
58
  export declare function reduceLastHandEndedFromDomainEvents(events: readonly TexasDomainEvent[]): HandEndedReadModel | null;
55
59
  /** 本批中**最后一条** `PotAwarded`(结算分配快照)。 */
package/types/index.d.ts CHANGED
@@ -15,7 +15,8 @@ import Controller, { Stage, StageEnum, HandLifecycle, type PendingFlowOp, type P
15
15
  import { User, Role, Action, RoleEnum, ActionType, ActionTypeEnum, type PlayerStatus, default as Player, resolveAllowedActions, type AllowedActionsContext, isPlayerEligibleForStreetBetting } from './Player';
16
16
  import TexasError, { texasErrorMap, TexasCoreErrorCode, texasErrorCategory, type TexasErrorCode, getTexasErrorSeverity, isFatalTexasErrorCode, type TexasErrorPayload, type TexasErrorSeverity, formatTexasErrorMessage, type TexasErrorCodeLegacy } from './TexasError';
17
17
  export * from './Deck/constant';
18
- export { getBestPokesRankSignature, compareRankSignature, getFiveCardsStrength, getStrengthFromRankSignature, getFiveCardCombinationIndices } from './Deck/core';
18
+ export { createStandardDeckPokes, getBestPokesRankSignature, compareRankSignature, getFiveCardsStrength, getStrengthFromRankSignature, getFiveCardCombinationIndices, rankSignatureToRanks, rankSignatureToDisplayGroups } from './Deck/core';
19
+ export type { RankSignatureDisplayGroup } from './Deck/core';
19
20
  export { Player, User, ActionType, ActionTypeEnum, Role, RoleEnum, Action, roleMap, ActionTypeMap, Stage, StageEnum, HandLifecycle, type ShowdownPlayerEval, type PendingFlowOp, type PendingFlowOpKind, TableStakes, type PlayerDealerRing, type PlayerHandSession, type PlayerStreetBetLedger, type StreetPotSink, StreetBetLedger, stageMap, Controller, Dealer, Table, DealerService, Deck, DealtBoard, type DealSnapshot, Room, RoomStatus, PlayerSeatStatus, type RoomCreateOptions, type RoomMemberCounts, formatterPoke, TexasError, TexasErrorCode, TexasErrorPayload, TexasErrorSeverity, TexasCoreErrorCode, formatTexasErrorMessage, getTexasErrorSeverity, isFatalTexasErrorCode, texasErrorMap, texasErrorCategory, TexasEngineContext, Texas, type PlayerStatus, type AllowedActionsContext, resolveAllowedActions, isPlayerEligibleForStreetBetting, type TexasEngineGlobalOptions, type TexasSimulationFlags,
20
21
  /** @deprecated 旧版宽泛 code 类型,请逐步迁移到 TexasErrorCode */
21
22
  type TexasErrorCodeLegacy, CurrentHand };