shufflecom-calculations 1.2.1 → 1.2.2
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/lib/games/blackjack.d.ts +22 -4
- package/lib/games/blackjack.js +61 -23
- package/lib/games/blackjack.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/games/blackjack.spec.ts +439 -97
- package/src/games/blackjack.ts +95 -39
- package/src/games/cardGames.ts +55 -0
- package/src/index.ts +1 -0
package/src/games/blackjack.ts
CHANGED
|
@@ -11,6 +11,15 @@ export enum BlackjackAction {
|
|
|
11
11
|
REJECT_INSURANCE = 'REJECT_INSURANCE',
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
export enum HandOutcome {
|
|
15
|
+
WIN = 'WIN', // refers to a win that pays out 2:1. Blackjacks after splits are still considered a HandOutcome.WIN and not HandOutcome.BLACKJACK as the payout is 2:1
|
|
16
|
+
LOSS = 'LOSS',
|
|
17
|
+
PUSH = 'PUSH',
|
|
18
|
+
BLACKJACK = 'BLACKJACK', // split hand can NEVER have a HandOutcome.BLACKJACK as the payout is 2:1 so it's a HandOutcome.WIN
|
|
19
|
+
PENDING = 'PENDING',
|
|
20
|
+
NONE = 'NONE', // for split player hand if the user has not split
|
|
21
|
+
}
|
|
22
|
+
|
|
14
23
|
export enum PerfectPairType {
|
|
15
24
|
PERFECT_PAIR = 'PERFECT_PAIR',
|
|
16
25
|
COLORED_PAIR = 'COLORED_PAIR',
|
|
@@ -37,12 +46,23 @@ export interface SettleBetVars {
|
|
|
37
46
|
mainPlayerHand: number[];
|
|
38
47
|
splitPlayerHand: number[];
|
|
39
48
|
dealerHand: number[];
|
|
40
|
-
|
|
41
|
-
splitHandBetAmount: BigNumber;
|
|
49
|
+
mainBetAmount: BigNumber; // the amount that the user entered when they placed the main bet
|
|
42
50
|
twentyOnePlusThreeAmount: BigNumber;
|
|
43
51
|
perfectPairAmount: BigNumber;
|
|
44
52
|
boughtInsurance: boolean;
|
|
45
53
|
hasSplit: boolean;
|
|
54
|
+
mainHandDoubleDown: boolean;
|
|
55
|
+
splitHandDoubleDown: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface MainBetPayoutVars {
|
|
59
|
+
mainPlayerHand: number[];
|
|
60
|
+
splitPlayerHand: number[];
|
|
61
|
+
dealerHand: number[];
|
|
62
|
+
mainHandBetAmount: BigNumber;
|
|
63
|
+
splitHandBetAmount: BigNumber;
|
|
64
|
+
boughtInsurance: boolean;
|
|
65
|
+
hasSplit: boolean;
|
|
46
66
|
}
|
|
47
67
|
|
|
48
68
|
// Since the values are payout and not profit, it's the profit multiple + 1
|
|
@@ -135,41 +155,41 @@ export class Blackjack {
|
|
|
135
155
|
throw new Error('No available action');
|
|
136
156
|
}
|
|
137
157
|
|
|
138
|
-
static
|
|
139
|
-
const dealerBlackjack = this.isBlackjack(dealerCards
|
|
140
|
-
const playerBlackjack = this.isBlackjack(playerCards
|
|
158
|
+
static getHandOutcome(dealerCards: number[], playerCards: number[], hasSplit: boolean): { multiplier: BigNumber; outcome: HandOutcome } {
|
|
159
|
+
const dealerBlackjack = this.isBlackjack(dealerCards);
|
|
160
|
+
const playerBlackjack = this.isBlackjack(playerCards);
|
|
141
161
|
|
|
142
162
|
if (playerBlackjack && !dealerBlackjack && !hasSplit) {
|
|
143
|
-
return new BigNumber(2.5);
|
|
163
|
+
return { multiplier: new BigNumber(2.5), outcome: HandOutcome.BLACKJACK };
|
|
144
164
|
}
|
|
145
165
|
|
|
146
166
|
if (dealerBlackjack && !playerBlackjack) {
|
|
147
|
-
return new BigNumber(0);
|
|
167
|
+
return { multiplier: new BigNumber(0), outcome: HandOutcome.LOSS };
|
|
148
168
|
}
|
|
149
169
|
|
|
150
170
|
if (dealerBlackjack && playerBlackjack) {
|
|
151
|
-
return new BigNumber(1);
|
|
171
|
+
return { multiplier: new BigNumber(1), outcome: HandOutcome.PUSH };
|
|
152
172
|
}
|
|
153
173
|
|
|
154
174
|
// If it reaches here, neither player nor dealer has blackjack
|
|
155
175
|
// if player busted, dealer auto wins
|
|
156
176
|
if (this.hasBusted(playerCards)) {
|
|
157
|
-
return new BigNumber(0);
|
|
177
|
+
return { multiplier: new BigNumber(0), outcome: HandOutcome.LOSS };
|
|
158
178
|
}
|
|
159
179
|
|
|
160
180
|
if (this.hasBusted(dealerCards)) {
|
|
161
|
-
return new BigNumber(2);
|
|
181
|
+
return { multiplier: new BigNumber(2), outcome: HandOutcome.WIN };
|
|
162
182
|
}
|
|
163
183
|
|
|
164
184
|
// Both did not bust, so compare the sum of cards
|
|
165
185
|
const playerSum = this.calcHandValue(playerCards);
|
|
166
186
|
const dealerSum = this.calcHandValue(dealerCards);
|
|
167
187
|
if (playerSum > dealerSum) {
|
|
168
|
-
return new BigNumber(2);
|
|
188
|
+
return { multiplier: new BigNumber(2), outcome: HandOutcome.WIN };
|
|
169
189
|
} else if (playerSum < dealerSum) {
|
|
170
|
-
return new BigNumber(0);
|
|
190
|
+
return { multiplier: new BigNumber(0), outcome: HandOutcome.LOSS };
|
|
171
191
|
} else {
|
|
172
|
-
return new BigNumber(1);
|
|
192
|
+
return { multiplier: new BigNumber(1), outcome: HandOutcome.PUSH };
|
|
173
193
|
}
|
|
174
194
|
}
|
|
175
195
|
|
|
@@ -310,43 +330,79 @@ export class Blackjack {
|
|
|
310
330
|
* Called after bet ends. Players can still win insurance or sidebets even if they lose the main bet
|
|
311
331
|
* @returns total payout amount
|
|
312
332
|
*/
|
|
313
|
-
static
|
|
314
|
-
mainPlayerHand,
|
|
315
|
-
splitPlayerHand,
|
|
316
|
-
dealerHand,
|
|
317
|
-
mainHandBetAmount,
|
|
318
|
-
splitHandBetAmount,
|
|
319
|
-
twentyOnePlusThreeAmount,
|
|
320
|
-
// TODO: Include 2 more fields for sidebet win types
|
|
321
|
-
perfectPairAmount,
|
|
322
|
-
boughtInsurance,
|
|
323
|
-
hasSplit,
|
|
324
|
-
}: SettleBetVars): BigNumber {
|
|
333
|
+
static getGameOutcome(data: SettleBetVars): { payout: BigNumber; multiplier: BigNumber; mainHandOutcome: HandOutcome; splitHandOutcome: HandOutcome } {
|
|
325
334
|
// calculate main bet payout for main and split hand
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
// calculate insurance payout (insurance payout is 3:1)
|
|
332
|
-
const insurancePayout = boughtInsurance && Blackjack.isBlackjack(dealerHand) ? mainHandBetAmount.dividedBy(2).times(3) : new BigNumber(0);
|
|
335
|
+
const mainHandBetAmount = data.mainHandDoubleDown ? data.mainBetAmount.times(2) : data.mainBetAmount;
|
|
336
|
+
let splitHandBetAmount = new BigNumber(0);
|
|
337
|
+
if (data.hasSplit) {
|
|
338
|
+
splitHandBetAmount = data.splitHandDoubleDown ? data.mainBetAmount.times(2) : data.mainBetAmount;
|
|
339
|
+
}
|
|
333
340
|
|
|
334
341
|
// calculate sidebet payouts
|
|
335
342
|
let perfectPairPayoutAmt = new BigNumber(0);
|
|
336
343
|
let twentyOnePlusThreePayoutAmt = new BigNumber(0);
|
|
337
344
|
|
|
338
|
-
const
|
|
345
|
+
const { mainHandOutcome, payout: mainBetPayout, splitHandOutcome } = Blackjack.getMainBetPayout({ ...data, mainHandBetAmount, splitHandBetAmount });
|
|
339
346
|
|
|
340
|
-
const
|
|
347
|
+
const playerHand: [number, number] = data.hasSplit ? [data.mainPlayerHand[0], data.splitPlayerHand[0]] : [data.mainPlayerHand[0], data.mainPlayerHand[1]];
|
|
341
348
|
|
|
342
|
-
|
|
343
|
-
|
|
349
|
+
const { perfectPair, twentyOnePlusThree } = Blackjack.calcSideBetWins(data.dealerHand[0], playerHand);
|
|
350
|
+
|
|
351
|
+
if (perfectPairPayout[perfectPair] && data.perfectPairAmount.gt(0)) {
|
|
352
|
+
perfectPairPayoutAmt = data.perfectPairAmount.times(perfectPairPayout[perfectPair]);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (twentyOnePlusThreePayout[twentyOnePlusThree] && data.twentyOnePlusThreeAmount.gt(0)) {
|
|
356
|
+
twentyOnePlusThreePayoutAmt = data.twentyOnePlusThreeAmount.times(twentyOnePlusThreePayout[twentyOnePlusThree]);
|
|
344
357
|
}
|
|
345
358
|
|
|
346
|
-
|
|
347
|
-
|
|
359
|
+
const payout = mainBetPayout.plus(perfectPairPayoutAmt).plus(twentyOnePlusThreePayoutAmt);
|
|
360
|
+
const insuranceCost = data.boughtInsurance ? data.mainBetAmount.dividedBy(2) : new BigNumber(0); // insurance costs half of the main bet
|
|
361
|
+
const totalBetAmount = mainHandBetAmount.plus(splitHandBetAmount).plus(data.perfectPairAmount).plus(data.twentyOnePlusThreeAmount).plus(insuranceCost);
|
|
362
|
+
|
|
363
|
+
let multiplier = payout.dividedBy(totalBetAmount);
|
|
364
|
+
|
|
365
|
+
// when the user bets $0, assume an initial bet of $1 to calculate the multiplier
|
|
366
|
+
if (totalBetAmount.isZero()) {
|
|
367
|
+
const mainHandBetAmount = data.mainHandDoubleDown ? new BigNumber(2) : new BigNumber(1);
|
|
368
|
+
let splitHandBetAmount = new BigNumber(0);
|
|
369
|
+
if (data.hasSplit) {
|
|
370
|
+
splitHandBetAmount = data.splitHandDoubleDown ? new BigNumber(2) : new BigNumber(1);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const insuranceCost = data.boughtInsurance ? new BigNumber(0.5) : new BigNumber(0); // insurance costs half of the main bet
|
|
374
|
+
const totalBetAmount = mainHandBetAmount.plus(splitHandBetAmount).plus(insuranceCost);
|
|
375
|
+
|
|
376
|
+
multiplier = Blackjack.getMainBetPayout({ ...data, mainHandBetAmount, splitHandBetAmount }).payout.dividedBy(totalBetAmount);
|
|
348
377
|
}
|
|
349
378
|
|
|
350
|
-
return
|
|
379
|
+
return { payout, multiplier, mainHandOutcome, splitHandOutcome };
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
private static getMainBetPayout({
|
|
383
|
+
mainPlayerHand,
|
|
384
|
+
splitPlayerHand,
|
|
385
|
+
dealerHand,
|
|
386
|
+
mainHandBetAmount,
|
|
387
|
+
splitHandBetAmount,
|
|
388
|
+
boughtInsurance,
|
|
389
|
+
hasSplit,
|
|
390
|
+
}: MainBetPayoutVars) {
|
|
391
|
+
const { multiplier: mainHandMultiplier, outcome: mainHandOutcome } = Blackjack.getHandOutcome(dealerHand, mainPlayerHand, hasSplit);
|
|
392
|
+
const mainHandPayout = mainHandMultiplier.times(mainHandBetAmount);
|
|
393
|
+
|
|
394
|
+
const { multiplier: splitHandMultiplier, outcome: splitHandOutcome } = Blackjack.getHandOutcome(dealerHand, splitPlayerHand, hasSplit);
|
|
395
|
+
|
|
396
|
+
const splitHandPayout = splitPlayerHand.length > 0 ? splitHandMultiplier.times(splitHandBetAmount) : new BigNumber(0);
|
|
397
|
+
|
|
398
|
+
// calculate insurance payout (insurance payout is 3:1)
|
|
399
|
+
// insurance won't be claimed if double down occurs, so double downs won't affect insurance payout even though it doubles the mainHandBetAmount
|
|
400
|
+
const insurancePayout = boughtInsurance && Blackjack.isBlackjack(dealerHand) ? mainHandBetAmount.dividedBy(2).times(3) : new BigNumber(0);
|
|
401
|
+
|
|
402
|
+
return {
|
|
403
|
+
mainHandOutcome,
|
|
404
|
+
splitHandOutcome: hasSplit ? splitHandOutcome : HandOutcome.NONE,
|
|
405
|
+
payout: mainHandPayout.plus(splitHandPayout).plus(insurancePayout),
|
|
406
|
+
};
|
|
351
407
|
}
|
|
352
408
|
}
|
package/src/games/cardGames.ts
CHANGED
|
@@ -105,3 +105,58 @@ export class CardGames {
|
|
|
105
105
|
// ]
|
|
106
106
|
|
|
107
107
|
// A = 1, 2 = 2 ,...10 = 10, J = 11, Q = 12, K = 13
|
|
108
|
+
/**
|
|
109
|
+
* 0: ♦2
|
|
110
|
+
* 1: ♥2
|
|
111
|
+
* 2: ♠2
|
|
112
|
+
* 3: ♣2
|
|
113
|
+
* 4: ♦3
|
|
114
|
+
* 5: ♥3
|
|
115
|
+
* 6: ♠3
|
|
116
|
+
* 7: ♣3
|
|
117
|
+
* 8: ♦4
|
|
118
|
+
* 9: ♥4
|
|
119
|
+
* 10: ♠4
|
|
120
|
+
* 11: ♣4
|
|
121
|
+
* 12: ♦5
|
|
122
|
+
* 13: ♥5
|
|
123
|
+
* 14: ♠5
|
|
124
|
+
* 15: ♣5
|
|
125
|
+
* 16: ♦6
|
|
126
|
+
* 17: ♥6
|
|
127
|
+
* 18: ♠6
|
|
128
|
+
* 19: ♣6
|
|
129
|
+
* 20: ♦7
|
|
130
|
+
* 21: ♥7
|
|
131
|
+
* 22: ♠7
|
|
132
|
+
* 23: ♣7
|
|
133
|
+
* 24: ♦8
|
|
134
|
+
* 25: ♥8
|
|
135
|
+
* 26: ♠8
|
|
136
|
+
* 27: ♣8
|
|
137
|
+
* 28: ♦9
|
|
138
|
+
* 29: ♥9
|
|
139
|
+
* 30: ♠9
|
|
140
|
+
* 31: ♣9
|
|
141
|
+
* 32: ♦10
|
|
142
|
+
* 33: ♥10
|
|
143
|
+
* 34: ♠10
|
|
144
|
+
* 35: ♣10
|
|
145
|
+
* 36: ♦J
|
|
146
|
+
* 37: ♥J
|
|
147
|
+
* 38: ♠J
|
|
148
|
+
* 39: ♣J
|
|
149
|
+
* 40: ♦Q
|
|
150
|
+
* 41: ♥Q
|
|
151
|
+
* 42: ♠Q
|
|
152
|
+
* 43: ♣Q
|
|
153
|
+
* 44: ♦K
|
|
154
|
+
* 45: ♥K
|
|
155
|
+
* 46: ♠K
|
|
156
|
+
* 47: ♣K
|
|
157
|
+
* 48: ♦A
|
|
158
|
+
* 49: ♥A
|
|
159
|
+
* 50: ♠A
|
|
160
|
+
* 51: ♣A
|
|
161
|
+
*
|
|
162
|
+
*/
|