maid-poker-cli 1.0.0 → 1.0.1
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 +81 -5
- package/dist/client.js +72 -76
- package/dist/game/__tests__/logic.test.js +467 -0
- package/dist/game/logic.js +217 -60
- package/dist/game/poker.js +19 -0
- package/dist/index.js +33 -2
- package/dist/server.js +69 -61
- package/package.json +9 -1
package/dist/game/logic.js
CHANGED
|
@@ -2,36 +2,74 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.analyzeHand = analyzeHand;
|
|
4
4
|
exports.canBeat = canBeat;
|
|
5
|
-
|
|
5
|
+
exports.getHandTypeForEffect = getHandTypeForEffect;
|
|
6
|
+
// 获取牌的频率统计
|
|
7
|
+
function getCardCounts(cards) {
|
|
8
|
+
const counts = {};
|
|
9
|
+
cards.forEach(c => counts[c.value] = (counts[c.value] || 0) + 1);
|
|
10
|
+
return counts;
|
|
11
|
+
}
|
|
12
|
+
// 统计王的数量
|
|
13
|
+
function countJokers(cards) {
|
|
14
|
+
let big = 0, small = 0;
|
|
15
|
+
cards.forEach(c => {
|
|
16
|
+
if (c.value === 17)
|
|
17
|
+
big++;
|
|
18
|
+
if (c.value === 16)
|
|
19
|
+
small++;
|
|
20
|
+
});
|
|
21
|
+
return { big, small };
|
|
22
|
+
}
|
|
23
|
+
function analyzeHand(cards, gameMode = 'three_player') {
|
|
6
24
|
const len = cards.length;
|
|
7
25
|
if (len === 0)
|
|
8
26
|
return { type: 'invalid', rankValue: 0, length: 0 };
|
|
9
27
|
// Sort descending
|
|
10
28
|
cards.sort((a, b) => b.value - a.value);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
29
|
+
const counts = getCardCounts(cards);
|
|
30
|
+
const jokers = countJokers(cards);
|
|
31
|
+
const totalJokers = jokers.big + jokers.small;
|
|
32
|
+
// ====== 四人模式特殊牌型 ======
|
|
33
|
+
if (gameMode === 'four_player') {
|
|
34
|
+
// 天王炸(4王,最强)- 2大王+2小王
|
|
35
|
+
if (len === 4 && totalJokers === 4) {
|
|
36
|
+
return { type: 'quad_joker', rankValue: 200, length: 4, bombLevel: 4 };
|
|
37
|
+
}
|
|
38
|
+
// 八炸(8张相同)
|
|
39
|
+
if (len === 8) {
|
|
40
|
+
const vals = Object.keys(counts).map(Number);
|
|
41
|
+
if (vals.length === 1 && counts[vals[0]] === 8) {
|
|
42
|
+
return { type: 'octo_bomb', rankValue: vals[0], length: 8, bombLevel: 3 };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// 普通王炸(1大1小)- 四人模式下等级为2,介于普通炸弹和八炸之间
|
|
46
|
+
if (len === 2 && jokers.big >= 1 && jokers.small >= 1) {
|
|
47
|
+
return { type: 'rocket', rankValue: 100, length: 2, bombLevel: 2 };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// ====== 通用牌型(三人和四人模式共享) ======
|
|
51
|
+
// 普通王炸(三人模式:1大1小;四人模式不适用这里,已在上面处理)
|
|
52
|
+
if (gameMode === 'three_player' && len === 2 && cards[0].value === 17 && cards[1].value === 16) {
|
|
53
|
+
return { type: 'rocket', rankValue: 100, length: 2, bombLevel: 5 }; // 三人模式王炸最大
|
|
14
54
|
}
|
|
15
|
-
//
|
|
55
|
+
// 普通炸弹(4张相同)
|
|
16
56
|
if (len === 4 && cards[0].value === cards[3].value) {
|
|
17
|
-
return { type: 'bomb', rankValue: cards[0].value, length: 4 };
|
|
57
|
+
return { type: 'bomb', rankValue: cards[0].value, length: 4, bombLevel: 1 };
|
|
18
58
|
}
|
|
19
|
-
//
|
|
59
|
+
// 单张
|
|
20
60
|
if (len === 1) {
|
|
21
61
|
return { type: 'single', rankValue: cards[0].value, length: 1 };
|
|
22
62
|
}
|
|
23
|
-
//
|
|
63
|
+
// 对子
|
|
24
64
|
if (len === 2 && cards[0].value === cards[1].value) {
|
|
25
65
|
return { type: 'pair', rankValue: cards[0].value, length: 2 };
|
|
26
66
|
}
|
|
27
|
-
//
|
|
67
|
+
// 三张
|
|
28
68
|
if (len === 3 && cards[0].value === cards[2].value) {
|
|
29
69
|
return { type: 'triple', rankValue: cards[0].value, length: 3 };
|
|
30
70
|
}
|
|
31
|
-
//
|
|
71
|
+
// 三带一
|
|
32
72
|
if (len === 4) {
|
|
33
|
-
// 3 same + 1 diff. Because sorted, 3 same must be at start or end.
|
|
34
|
-
// AAA B or B AAA
|
|
35
73
|
if (cards[0].value === cards[2].value) { // AAA B
|
|
36
74
|
return { type: 'triple_one', rankValue: cards[0].value, length: 4 };
|
|
37
75
|
}
|
|
@@ -39,9 +77,8 @@ function analyzeHand(cards) {
|
|
|
39
77
|
return { type: 'triple_one', rankValue: cards[1].value, length: 4 };
|
|
40
78
|
}
|
|
41
79
|
}
|
|
42
|
-
//
|
|
80
|
+
// 三带对
|
|
43
81
|
if (len === 5) {
|
|
44
|
-
// AAA BB or BB AAA
|
|
45
82
|
if (cards[0].value === cards[2].value && cards[3].value === cards[4].value) { // AAA BB
|
|
46
83
|
return { type: 'triple_pair', rankValue: cards[0].value, length: 5 };
|
|
47
84
|
}
|
|
@@ -49,29 +86,96 @@ function analyzeHand(cards) {
|
|
|
49
86
|
return { type: 'triple_pair', rankValue: cards[2].value, length: 5 };
|
|
50
87
|
}
|
|
51
88
|
}
|
|
52
|
-
//
|
|
89
|
+
// ====== 四带二(四人模式) ======
|
|
90
|
+
if (gameMode === 'four_player' && len === 6) {
|
|
91
|
+
const vals = Object.keys(counts).map(Number);
|
|
92
|
+
const fourVal = vals.find(v => counts[v] === 4);
|
|
93
|
+
if (fourVal !== undefined) {
|
|
94
|
+
// 找到4张相同的牌,剩下2张是单牌
|
|
95
|
+
const others = vals.filter(v => v !== fourVal);
|
|
96
|
+
if (others.length === 2 || (others.length === 1 && counts[others[0]] === 2)) {
|
|
97
|
+
return { type: 'four_with_two', rankValue: fourVal, length: 6 };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// 四带两对(四人模式)
|
|
102
|
+
if (gameMode === 'four_player' && len === 8) {
|
|
103
|
+
const vals = Object.keys(counts).map(Number);
|
|
104
|
+
const fourVal = vals.find(v => counts[v] === 4);
|
|
105
|
+
if (fourVal !== undefined) {
|
|
106
|
+
const others = vals.filter(v => v !== fourVal);
|
|
107
|
+
// 检查剩余是否都是对子
|
|
108
|
+
const allPairs = others.every(v => counts[v] === 2);
|
|
109
|
+
if (allPairs && others.length === 2) {
|
|
110
|
+
return { type: 'four_with_pairs', rankValue: fourVal, length: 8 };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// ====== 顺子 ======
|
|
115
|
+
// 三人模式:5张及以上连牌,不含2和王
|
|
116
|
+
// 四人模式:5张及以上连牌,可含2,不含王(如 A2345, 10JQKA 都可以)
|
|
53
117
|
if (len >= 5) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
118
|
+
// 检查是否包含王
|
|
119
|
+
const hasJoker = cards.some(c => c.value >= 16);
|
|
120
|
+
if (!hasJoker) {
|
|
121
|
+
let isStraight = true;
|
|
122
|
+
// 四人模式特殊处理:支持包含2的顺子
|
|
123
|
+
if (gameMode === 'four_player') {
|
|
124
|
+
// 检查是否是 A2345 这种情况(A作为1使用)
|
|
125
|
+
const sortedValues = cards.map(c => c.value).sort((a, b) => a - b);
|
|
126
|
+
const minVal = sortedValues[0];
|
|
127
|
+
const maxVal = sortedValues[sortedValues.length - 1];
|
|
128
|
+
// 正常顺子检查
|
|
129
|
+
for (let i = 0; i < len - 1; i++) {
|
|
130
|
+
if (sortedValues[i + 1] - sortedValues[i] !== 1) {
|
|
131
|
+
isStraight = false;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// 检查 A2345 (值: 3,4,5,14,15 -> 需要把A视为1)
|
|
136
|
+
if (!isStraight && sortedValues.includes(14) && sortedValues.includes(15)) {
|
|
137
|
+
const adjustedValues = sortedValues.map(v => v === 14 ? 1 : v === 15 ? 2 : v).sort((a, b) => a - b);
|
|
138
|
+
isStraight = true;
|
|
139
|
+
for (let i = 0; i < len - 1; i++) {
|
|
140
|
+
if (adjustedValues[i + 1] - adjustedValues[i] !== 1) {
|
|
141
|
+
isStraight = false;
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (isStraight) {
|
|
146
|
+
return { type: 'straight', rankValue: 15, length: len }; // 2是最大值
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// 三人模式:不能包含2
|
|
152
|
+
if (cards[0].value >= 15) {
|
|
153
|
+
isStraight = false;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
for (let i = 0; i < len - 1; i++) {
|
|
157
|
+
if (cards[i].value - cards[i + 1].value !== 1) {
|
|
158
|
+
isStraight = false;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (isStraight && cards[0].value < 16) {
|
|
165
|
+
return { type: 'straight', rankValue: cards[0].value, length: len };
|
|
166
|
+
}
|
|
63
167
|
}
|
|
64
168
|
}
|
|
65
|
-
//
|
|
169
|
+
// ====== 连对 ======
|
|
170
|
+
// 三人模式:3对及以上连对,不含2和王
|
|
171
|
+
// 四人模式:3对及以上连对
|
|
66
172
|
if (len >= 6 && len % 2 === 0) {
|
|
67
173
|
let isConsecutivePairs = true;
|
|
68
174
|
for (let i = 0; i < len; i += 2) {
|
|
69
|
-
// Check pair
|
|
70
175
|
if (cards[i].value !== cards[i + 1].value) {
|
|
71
176
|
isConsecutivePairs = false;
|
|
72
177
|
break;
|
|
73
178
|
}
|
|
74
|
-
// Check consecutive with previous pair
|
|
75
179
|
if (i > 0) {
|
|
76
180
|
if (cards[i].value !== cards[i - 2].value - 1) {
|
|
77
181
|
isConsecutivePairs = false;
|
|
@@ -79,59 +183,112 @@ function analyzeHand(cards) {
|
|
|
79
183
|
}
|
|
80
184
|
}
|
|
81
185
|
}
|
|
82
|
-
|
|
186
|
+
// 三人模式不能包含2
|
|
187
|
+
const maxVal = gameMode === 'three_player' ? 14 : 15;
|
|
188
|
+
if (isConsecutivePairs && cards[0].value <= maxVal) {
|
|
83
189
|
return { type: 'consecutive_pairs', rankValue: cards[0].value, length: len };
|
|
84
190
|
}
|
|
85
191
|
}
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
// or heuristic: if we find consecutive triples, we call it airplane for effect.
|
|
89
|
-
// Let's do a basic frequency map check.
|
|
90
|
-
const counts = {};
|
|
91
|
-
cards.forEach(c => counts[c.value] = (counts[c.value] || 0) + 1);
|
|
192
|
+
// ====== 飞机 ======
|
|
193
|
+
// 检测连续三张(可带翅膀)
|
|
92
194
|
const triples = [];
|
|
93
195
|
for (const val in counts) {
|
|
94
196
|
if (counts[val] >= 3)
|
|
95
197
|
triples.push(Number(val));
|
|
96
198
|
}
|
|
97
|
-
triples.sort((a, b) => b - a);
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
199
|
+
triples.sort((a, b) => b - a);
|
|
200
|
+
// 检查连续三张的数量
|
|
201
|
+
if (triples.length >= 2) {
|
|
202
|
+
// 找最长的连续三张序列
|
|
203
|
+
let maxConsecutive = 1;
|
|
204
|
+
let currentConsecutive = 1;
|
|
205
|
+
let startTriple = triples[0];
|
|
206
|
+
for (let i = 0; i < triples.length - 1; i++) {
|
|
207
|
+
const maxAllowed = gameMode === 'three_player' ? 14 : 15; // 三人模式不含2
|
|
208
|
+
if (triples[i] <= maxAllowed && triples[i] === triples[i + 1] + 1) {
|
|
209
|
+
currentConsecutive++;
|
|
210
|
+
if (currentConsecutive > maxConsecutive) {
|
|
211
|
+
maxConsecutive = currentConsecutive;
|
|
212
|
+
startTriple = triples[i - maxConsecutive + 2];
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
currentConsecutive = 1;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (maxConsecutive >= 2) {
|
|
220
|
+
// 验证翅膀数量
|
|
221
|
+
const tripleCount = maxConsecutive;
|
|
222
|
+
const expectedLen = tripleCount * 3; // 无翅膀
|
|
223
|
+
const expectedLenWithSingles = tripleCount * 4; // 带单
|
|
224
|
+
const expectedLenWithPairs = tripleCount * 5; // 带对
|
|
225
|
+
if (len === expectedLen || len === expectedLenWithSingles || len === expectedLenWithPairs) {
|
|
226
|
+
return { type: 'airplane', rankValue: startTriple, length: len };
|
|
227
|
+
}
|
|
103
228
|
}
|
|
104
|
-
}
|
|
105
|
-
// minimal airplane is 2 consecutive triples
|
|
106
|
-
if (consecutiveTriples >= 1) {
|
|
107
|
-
// This is a loose check, mostly for the Visual Effect triggering
|
|
108
|
-
// Since we want to show "Airplane" effect.
|
|
109
|
-
return { type: 'airplane', rankValue: triples[0], length: len };
|
|
110
229
|
}
|
|
111
230
|
return { type: 'invalid', rankValue: 0, length: 0 };
|
|
112
231
|
}
|
|
113
|
-
function canBeat(lastHand, newHand) {
|
|
114
|
-
const last = analyzeHand(lastHand);
|
|
115
|
-
const curr = analyzeHand(newHand);
|
|
232
|
+
function canBeat(lastHand, newHand, gameMode = 'three_player') {
|
|
233
|
+
const last = analyzeHand(lastHand, gameMode);
|
|
234
|
+
const curr = analyzeHand(newHand, gameMode);
|
|
116
235
|
if (curr.type === 'invalid')
|
|
117
236
|
return false;
|
|
118
|
-
//
|
|
119
|
-
|
|
237
|
+
// ====== 炸弹比较逻辑 ======
|
|
238
|
+
const isBombType = (type) => ['bomb', 'rocket', 'quad_joker', 'octo_bomb'].includes(type);
|
|
239
|
+
const currIsBomb = isBombType(curr.type);
|
|
240
|
+
const lastIsBomb = isBombType(last.type);
|
|
241
|
+
if (currIsBomb && lastIsBomb) {
|
|
242
|
+
// 都是炸弹类型,比较炸弹级别
|
|
243
|
+
// 炸弹等级:普通炸(1) < 双王炸(2) < 八炸(3) < 天王炸(4) ; 三人王炸(5)
|
|
244
|
+
const currLevel = curr.bombLevel || 0;
|
|
245
|
+
const lastLevel = last.bombLevel || 0;
|
|
246
|
+
if (currLevel !== lastLevel) {
|
|
247
|
+
return currLevel > lastLevel;
|
|
248
|
+
}
|
|
249
|
+
// 同级别炸弹比较点数
|
|
250
|
+
return curr.rankValue > last.rankValue;
|
|
251
|
+
}
|
|
252
|
+
// 炸弹类型打非炸弹类型
|
|
253
|
+
if (currIsBomb && !lastIsBomb) {
|
|
120
254
|
return true;
|
|
121
|
-
|
|
255
|
+
}
|
|
256
|
+
// 非炸弹类型不能打炸弹类型
|
|
257
|
+
if (!currIsBomb && lastIsBomb) {
|
|
122
258
|
return false;
|
|
123
|
-
// Bomb beats everything except rocket and bigger bomb
|
|
124
|
-
if (curr.type === 'bomb') {
|
|
125
|
-
if (last.type === 'bomb')
|
|
126
|
-
return curr.rankValue > last.rankValue;
|
|
127
|
-
return true;
|
|
128
259
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
// Otherwise, types must match and lengths must match (usually)
|
|
260
|
+
// ====== 非炸弹牌型比较 ======
|
|
261
|
+
// 类型必须相同
|
|
132
262
|
if (curr.type !== last.type)
|
|
133
263
|
return false;
|
|
264
|
+
// 长度必须相同
|
|
134
265
|
if (curr.length !== last.length)
|
|
135
266
|
return false;
|
|
136
267
|
return curr.rankValue > last.rankValue;
|
|
137
268
|
}
|
|
269
|
+
// 导出用于特效判断
|
|
270
|
+
function getHandTypeForEffect(cards, gameMode = 'three_player') {
|
|
271
|
+
const analysis = analyzeHand(cards, gameMode);
|
|
272
|
+
const typeNames = {
|
|
273
|
+
'single': '单张',
|
|
274
|
+
'pair': '对子',
|
|
275
|
+
'triple': '三张',
|
|
276
|
+
'triple_one': '三带一',
|
|
277
|
+
'triple_pair': '三带对',
|
|
278
|
+
'four_with_two': '四带二',
|
|
279
|
+
'four_with_pairs': '四带两对',
|
|
280
|
+
'bomb': '炸弹',
|
|
281
|
+
'rocket': gameMode === 'four_player' ? '双王炸' : '王炸',
|
|
282
|
+
'quad_joker': '天王炸',
|
|
283
|
+
'octo_bomb': '八炸',
|
|
284
|
+
'straight': '顺子',
|
|
285
|
+
'consecutive_pairs': '连对',
|
|
286
|
+
'airplane': '飞机',
|
|
287
|
+
'invalid': '无效'
|
|
288
|
+
};
|
|
289
|
+
return {
|
|
290
|
+
type: analysis.type,
|
|
291
|
+
rankValue: analysis.rankValue,
|
|
292
|
+
displayName: typeNames[analysis.type]
|
|
293
|
+
};
|
|
294
|
+
}
|
package/dist/game/poker.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.RANKS = void 0;
|
|
4
4
|
exports.getCardValue = getCardValue;
|
|
5
5
|
exports.createDeck = createDeck;
|
|
6
|
+
exports.createDoubleDeck = createDoubleDeck;
|
|
6
7
|
exports.shuffleDeck = shuffleDeck;
|
|
7
8
|
exports.sortHand = sortHand;
|
|
8
9
|
exports.formatCard = formatCard;
|
|
@@ -28,6 +29,24 @@ function createDeck() {
|
|
|
28
29
|
deck.push({ suit: '', rank: 'RJ', value: 17 });
|
|
29
30
|
return deck;
|
|
30
31
|
}
|
|
32
|
+
// 创建双副牌(用于四人斗地主,共108张牌)
|
|
33
|
+
function createDoubleDeck() {
|
|
34
|
+
const suits = ['♠', '♥', '♣', '♦'];
|
|
35
|
+
const normalRanks = exports.RANKS.slice(0, 13); // 3 to 2
|
|
36
|
+
let deck = [];
|
|
37
|
+
// 两副牌
|
|
38
|
+
for (let deckIdx = 0; deckIdx < 2; deckIdx++) {
|
|
39
|
+
for (const r of normalRanks) {
|
|
40
|
+
for (const s of suits) {
|
|
41
|
+
deck.push({ suit: s, rank: r, value: getCardValue(r), deckIndex: deckIdx });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Jokers
|
|
45
|
+
deck.push({ suit: '', rank: 'BJ', value: 16, deckIndex: deckIdx });
|
|
46
|
+
deck.push({ suit: '', rank: 'RJ', value: 17, deckIndex: deckIdx });
|
|
47
|
+
}
|
|
48
|
+
return deck; // 共 108 张牌
|
|
49
|
+
}
|
|
31
50
|
function shuffleDeck(deck) {
|
|
32
51
|
for (let i = deck.length - 1; i > 0; i--) {
|
|
33
52
|
const j = Math.floor(Math.random() * (i + 1));
|
package/dist/index.js
CHANGED
|
@@ -45,10 +45,41 @@ function main() {
|
|
|
45
45
|
}
|
|
46
46
|
]);
|
|
47
47
|
if (mode.includes('Host')) {
|
|
48
|
+
// 选择游戏模式
|
|
49
|
+
const { gameMode } = yield inquirer_1.default.prompt([
|
|
50
|
+
{
|
|
51
|
+
type: 'list',
|
|
52
|
+
name: 'gameMode',
|
|
53
|
+
message: '请选择游戏模式:',
|
|
54
|
+
choices: [
|
|
55
|
+
{ name: '三人斗地主 (1副牌, 每人17张)', value: 'three_player' },
|
|
56
|
+
{ name: '四人斗地主 (2副牌, 每人25张)', value: 'four_player' }
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
]);
|
|
60
|
+
const selectedMode = gameMode;
|
|
61
|
+
const requiredPlayers = selectedMode === 'three_player' ? 3 : 4;
|
|
62
|
+
const modeText = selectedMode === 'three_player' ? '三人斗地主' : '四人斗地主(2副牌)';
|
|
63
|
+
console.log(chalk_1.default.magenta(`\n已选择: ${modeText}`));
|
|
64
|
+
console.log(chalk_1.default.gray(`需要 ${requiredPlayers} 位玩家参与\n`));
|
|
65
|
+
// 显示规则提示
|
|
66
|
+
if (selectedMode === 'four_player') {
|
|
67
|
+
console.log(chalk_1.default.yellow('=== 四人斗地主规则 ==='));
|
|
68
|
+
console.log(chalk_1.default.gray('• 使用2副牌(108张),每人25张,8张底牌'));
|
|
69
|
+
console.log(chalk_1.default.gray('• 顺子可含2 (如 A2345, 10JQKA)'));
|
|
70
|
+
console.log(chalk_1.default.gray('• 新增牌型:'));
|
|
71
|
+
console.log(chalk_1.default.cyan(' - 四带二: 4张相同 + 2张单牌'));
|
|
72
|
+
console.log(chalk_1.default.cyan(' - 四带两对: 4张相同 + 2对'));
|
|
73
|
+
console.log(chalk_1.default.cyan(' - 双王炸: 2大王 + 2小王'));
|
|
74
|
+
console.log(chalk_1.default.cyan(' - 八炸: 8张相同牌'));
|
|
75
|
+
console.log(chalk_1.default.cyan(' - 天王炸: 4张王 (最强)'));
|
|
76
|
+
console.log(chalk_1.default.gray('• 炸弹大小: 天王炸 > 八炸 > 双王炸 > 普通炸弹'));
|
|
77
|
+
console.log('');
|
|
78
|
+
}
|
|
48
79
|
const ips = getLocalIPs();
|
|
49
80
|
console.log(chalk_1.default.blue(`\n服务器已启动,请尝试以下IP: \n${ips.map(ip => ` - ${ip}`).join('\n')}`));
|
|
50
|
-
// Start the server
|
|
51
|
-
new server_1.GameServer();
|
|
81
|
+
// Start the server with selected game mode
|
|
82
|
+
new server_1.GameServer(selectedMode);
|
|
52
83
|
const { joinAsPlayer } = yield inquirer_1.default.prompt([{
|
|
53
84
|
type: 'confirm',
|
|
54
85
|
name: 'joinAsPlayer',
|