shufflecom-calculations 1.2.0 → 1.2.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.
@@ -0,0 +1,1074 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import { Blackjack, BlackjackAction, InsuranceStatus, PerfectPairType, SettleBetVars, TwentyOnePlusThreeType } from './blackjack';
3
+ import { CardGames, CardValue, Suits, suitsArr } from './cardGames';
4
+
5
+ const getIndex = (value: CardValue) => CardGames.getCardIndexFromDetails({ suit: suitsArr[Math.floor(Math.random() * 4)], value });
6
+
7
+ describe('Blackjack', () => {
8
+ it('should get the correct list of available next actions', () => {
9
+ const funcParams: Array<{ input: [number[], number[], InsuranceStatus, boolean]; output: BlackjackAction[] }> = [
10
+ {
11
+ input: [
12
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '4' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '2' })],
13
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '5' })],
14
+ InsuranceStatus.ELIGIBLE,
15
+ false,
16
+ ],
17
+ output: [BlackjackAction.BUY_INSURANCE, BlackjackAction.REJECT_INSURANCE],
18
+ },
19
+ {
20
+ input: [
21
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '2' })],
22
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '6' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '5' })],
23
+ InsuranceStatus.INELIGIBLE,
24
+ false,
25
+ ],
26
+ output: [BlackjackAction.HIT, BlackjackAction.STAND, BlackjackAction.DOUBLE_DOWN],
27
+ },
28
+ {
29
+ input: [
30
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' })],
31
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '6' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '5' })],
32
+ InsuranceStatus.INELIGIBLE,
33
+ true,
34
+ ],
35
+ output: [BlackjackAction.HIT, BlackjackAction.STAND, BlackjackAction.DOUBLE_DOWN, BlackjackAction.SPLIT],
36
+ },
37
+ {
38
+ input: [
39
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' })],
40
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '6' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '5' })],
41
+ InsuranceStatus.INELIGIBLE,
42
+ false,
43
+ ],
44
+ output: [BlackjackAction.HIT, BlackjackAction.STAND, BlackjackAction.DOUBLE_DOWN],
45
+ },
46
+ {
47
+ input: [
48
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' })],
49
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '6' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '5' })],
50
+ InsuranceStatus.INELIGIBLE,
51
+ false,
52
+ ],
53
+ output: [],
54
+ },
55
+ {
56
+ input: [
57
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '3' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' })],
58
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' })],
59
+ InsuranceStatus.INELIGIBLE,
60
+ false,
61
+ ],
62
+ output: [],
63
+ },
64
+ {
65
+ input: [
66
+ [
67
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'J' }),
68
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'J' }),
69
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
70
+ ],
71
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '2' })],
72
+ InsuranceStatus.INELIGIBLE,
73
+ false,
74
+ ],
75
+ output: [],
76
+ },
77
+ {
78
+ input: [
79
+ [
80
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'J' }),
81
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'J' }),
82
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }),
83
+ ],
84
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '2' })],
85
+ InsuranceStatus.INELIGIBLE,
86
+ false,
87
+ ],
88
+ output: [],
89
+ },
90
+ {
91
+ input: [
92
+ [
93
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'J' }),
94
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '2' }),
95
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }),
96
+ ],
97
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '2' })],
98
+ InsuranceStatus.INELIGIBLE,
99
+ false,
100
+ ],
101
+ output: [BlackjackAction.HIT, BlackjackAction.STAND],
102
+ },
103
+ ];
104
+
105
+ funcParams.forEach((param) => {
106
+ const result = Blackjack.availableNextActions(...param.input);
107
+ expect(result).toEqual(expect.arrayContaining(param.output));
108
+ });
109
+
110
+ /**
111
+ * 1. Eligible for insurance (should return either 'insurance' or 'no insurance')
112
+ * 2. Blackjack for either player, shuld return no actions as the game is over
113
+ * 3. Player or dealer has busted, should return no actions as the game is over
114
+ * 4. Player has 21 (full), should return no actions
115
+ * 5. On first hand not same cards, should return 'hit', 'stand', 'double'
116
+ * 6. on first hand AND haven't split AND same cards, should return 'hit', 'stand', 'double', 'split'
117
+ * 7. on first hand but alr split, should return 'hit', 'stand', 'double'
118
+ * 8. on split hand AND only 2 cards AND same cards, should return 'hit', 'stand' 'double'
119
+ * 9. not on first hand, should return 'hit', 'stand'
120
+ */
121
+ });
122
+
123
+ it('should correctly detect if the player is playing his main hand or split hand', () => {
124
+ const funcParams: Array<{ input: [number[], number[], BlackjackAction[], BlackjackAction[]]; output?: boolean }> = [
125
+ {
126
+ input: [[getIndex('2'), getIndex('5'), getIndex('10')], [], [BlackjackAction.HIT], []],
127
+ output: true,
128
+ },
129
+ {
130
+ input: [
131
+ [getIndex('2'), getIndex('5'), getIndex('10')],
132
+ [getIndex('2'), getIndex('5')],
133
+ [BlackjackAction.SPLIT, BlackjackAction.HIT],
134
+ [BlackjackAction.SPLIT],
135
+ ],
136
+ output: true,
137
+ },
138
+ {
139
+ input: [
140
+ [getIndex('2'), getIndex('5'), getIndex('10')],
141
+ [getIndex('2'), getIndex('5')],
142
+ [BlackjackAction.SPLIT, BlackjackAction.DOUBLE_DOWN],
143
+ [BlackjackAction.SPLIT],
144
+ ],
145
+ output: false,
146
+ },
147
+ {
148
+ input: [
149
+ [getIndex('2'), getIndex('5'), getIndex('10')],
150
+ [getIndex('2'), getIndex('5')],
151
+ [BlackjackAction.SPLIT, BlackjackAction.HIT, BlackjackAction.STAND],
152
+ [BlackjackAction.SPLIT],
153
+ ],
154
+ output: false,
155
+ },
156
+ {
157
+ input: [
158
+ [getIndex('2'), getIndex('5'), getIndex('10'), getIndex('10')],
159
+ [getIndex('2'), getIndex('5')],
160
+ [BlackjackAction.SPLIT, BlackjackAction.HIT, BlackjackAction.HIT],
161
+ [BlackjackAction.SPLIT],
162
+ ],
163
+ output: false,
164
+ },
165
+ {
166
+ input: [
167
+ [getIndex('2'), getIndex('5'), getIndex('10'), getIndex('2')],
168
+ [getIndex('2'), getIndex('6')],
169
+ [BlackjackAction.SPLIT, BlackjackAction.HIT, BlackjackAction.HIT],
170
+ [BlackjackAction.SPLIT],
171
+ ],
172
+ output: true,
173
+ },
174
+ {
175
+ input: [
176
+ [getIndex('2'), getIndex('5'), getIndex('10'), getIndex('5')],
177
+ [getIndex('2'), getIndex('10'), getIndex('10')],
178
+ [BlackjackAction.SPLIT, BlackjackAction.HIT, BlackjackAction.HIT],
179
+ [BlackjackAction.SPLIT, BlackjackAction.HIT],
180
+ ],
181
+ },
182
+ {
183
+ input: [
184
+ [getIndex('2'), getIndex('5'), getIndex('10'), getIndex('5')],
185
+ [getIndex('2'), getIndex('6'), getIndex('3')],
186
+ [BlackjackAction.SPLIT, BlackjackAction.HIT, BlackjackAction.HIT],
187
+ [BlackjackAction.SPLIT, BlackjackAction.DOUBLE_DOWN],
188
+ ],
189
+ },
190
+ {
191
+ input: [
192
+ [getIndex('2'), getIndex('5'), getIndex('10'), getIndex('5')],
193
+ [getIndex('2'), getIndex('6'), getIndex('3'), getIndex('3')],
194
+ [BlackjackAction.SPLIT, BlackjackAction.HIT, BlackjackAction.HIT],
195
+ [BlackjackAction.SPLIT, BlackjackAction.HIT, BlackjackAction.STAND],
196
+ ],
197
+ },
198
+ {
199
+ input: [[getIndex('2'), getIndex('5'), getIndex('10'), getIndex('5')], [], [BlackjackAction.HIT, BlackjackAction.HIT], []],
200
+ },
201
+ {
202
+ input: [
203
+ [getIndex('2'), getIndex('5'), getIndex('10'), getIndex('5')],
204
+ [getIndex('2'), getIndex('6'), getIndex('5'), getIndex('10')],
205
+ [BlackjackAction.SPLIT, BlackjackAction.HIT, BlackjackAction.HIT],
206
+ [BlackjackAction.SPLIT, BlackjackAction.HIT, BlackjackAction.HIT],
207
+ ],
208
+ },
209
+ ];
210
+
211
+ funcParams.forEach((param) => {
212
+ if (param.output !== undefined) {
213
+ const result = Blackjack.playingMainHand(...param.input);
214
+ expect(result).toEqual(param.output);
215
+ } else {
216
+ try {
217
+ Blackjack.playingMainHand(...param.input);
218
+ expect(true).toEqual(false);
219
+ } catch (error: unknown) {
220
+ expect((error as Error).message).toEqual('No available action');
221
+ }
222
+ }
223
+ });
224
+
225
+ /**
226
+ * 1. If sum of mainPlayerCards < 21, AND the user has not 'double down' or 'stand' then TRUE even if splitPlayerCards is not empty
227
+ * 2. If sum of mainPlayerCards < 21 AND user has either 'double down' or 'stand' then FALSE/error
228
+ * 3. If player is not playing his main hand, AND user has split hand AND split hand fulfils criteria of continuing to play split hand, then FALSE
229
+ * NEED TO TRY THE DIFFERENT SCENARIOS FOR THE ABOVE
230
+ * 4. otherwise throw error, such as when the user has busted main hand but no split hand, or when both hands have ended. Since it should never reach this point
231
+ */
232
+ });
233
+
234
+ it('calculate main bet payout correctly, accounting for blackjacks after splitting', () => {
235
+ const funcParams: Array<{ input: [number[], number[], boolean]; output: BigNumber }> = [
236
+ { input: [[getIndex('4'), getIndex('5')], [getIndex('A'), getIndex('10')], false], output: new BigNumber(2.5) },
237
+ { input: [[getIndex('9'), getIndex('10')], [getIndex('10'), getIndex('A')], false], output: new BigNumber(2.5) },
238
+ { input: [[getIndex('9'), getIndex('10')], [getIndex('10'), getIndex('A')], true], output: new BigNumber(2) },
239
+ { input: [[getIndex('10'), getIndex('A')], [], false], output: new BigNumber(0) },
240
+ { input: [[getIndex('10'), getIndex('A')], [getIndex('J'), getIndex('A')], false], output: new BigNumber(1) },
241
+ { input: [[getIndex('8'), getIndex('A')], [getIndex('J'), getIndex('10'), getIndex('9')], false], output: new BigNumber(0) },
242
+ { input: [[getIndex('8'), getIndex('10'), getIndex('9')], [getIndex('J'), getIndex('2'), getIndex('5')], false], output: new BigNumber(2) },
243
+ { input: [[getIndex('8'), getIndex('10')], [getIndex('J'), getIndex('2'), getIndex('5')], false], output: new BigNumber(0) },
244
+ { input: [[getIndex('8'), getIndex('10')], [getIndex('J'), getIndex('3'), getIndex('5')], false], output: new BigNumber(1) },
245
+ { input: [[getIndex('8'), getIndex('10')], [getIndex('J'), getIndex('4'), getIndex('5')], false], output: new BigNumber(2) },
246
+ ];
247
+ funcParams.forEach((param) => {
248
+ const result = Blackjack.calcMainBetMultiplier(...param.input);
249
+ expect(result).toEqual(param.output);
250
+ });
251
+
252
+ /**
253
+ * 1. Player has blackjack, dealer does not, should return 2.5x
254
+ * 2. Dealer has blackjack, player doesn't
255
+ * 3. Player and dealer both have blackjack
256
+ * REPEAT THE ABOVE FOR SPLIT HANDS AS SPLIT HANDS DON'T PAY OUT 2.5X
257
+ * 4. Player has busted
258
+ * 5. Dealer has busted
259
+ * 6. Both no bust, player > dealer
260
+ * 7. Both no bust, player < dealer
261
+ * 8. Both no bust, player = dealer
262
+ */
263
+ });
264
+
265
+ it('calculates side bet wins correctly', () => {
266
+ const funcParams: Array<{ input: [number, number[]]; output: { perfectPair?: PerfectPairType; twentyOnePlusThree?: TwentyOnePlusThreeType } }> = [
267
+ {
268
+ input: [
269
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '3' }),
270
+ [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' })],
271
+ ],
272
+ output: { perfectPair: PerfectPairType.PERFECT_PAIR },
273
+ },
274
+ {
275
+ input: [
276
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '3' }),
277
+ [CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '10' }), CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' })],
278
+ ],
279
+ output: { perfectPair: PerfectPairType.COLORED_PAIR },
280
+ },
281
+ {
282
+ input: [
283
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '9' }),
284
+ [CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '3' }), CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '3' })],
285
+ ],
286
+ output: { perfectPair: PerfectPairType.MIXED_PAIR },
287
+ },
288
+ {
289
+ input: [
290
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '3' }),
291
+ [CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '3' }), CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '3' })],
292
+ ],
293
+ output: { perfectPair: PerfectPairType.PERFECT_PAIR, twentyOnePlusThree: TwentyOnePlusThreeType.SUITED_TRIPS },
294
+ },
295
+ {
296
+ input: [
297
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '3' }),
298
+ [CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '4' }), CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '5' })],
299
+ ],
300
+ output: { twentyOnePlusThree: TwentyOnePlusThreeType.STRAIGHT_FLUSH },
301
+ },
302
+ {
303
+ input: [
304
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: 'A' }),
305
+ [CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '2' }), CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '3' })],
306
+ ],
307
+ output: { twentyOnePlusThree: TwentyOnePlusThreeType.STRAIGHT_FLUSH },
308
+ },
309
+ {
310
+ input: [
311
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: 'Q' }),
312
+ [CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: 'A' }), CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: 'K' })],
313
+ ],
314
+ output: { twentyOnePlusThree: TwentyOnePlusThreeType.STRAIGHT_FLUSH },
315
+ },
316
+ {
317
+ input: [
318
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '4' }),
319
+ [CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '4' }), CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '4' })],
320
+ ],
321
+ output: { perfectPair: PerfectPairType.MIXED_PAIR, twentyOnePlusThree: TwentyOnePlusThreeType.THREE_OF_A_KIND },
322
+ },
323
+ {
324
+ input: [
325
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '4' }),
326
+ [CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '4' }), CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '4' })],
327
+ ],
328
+ output: { perfectPair: PerfectPairType.PERFECT_PAIR, twentyOnePlusThree: TwentyOnePlusThreeType.THREE_OF_A_KIND },
329
+ },
330
+ {
331
+ input: [
332
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '2' }),
333
+ [CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '3' }), CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '4' })],
334
+ ],
335
+ output: { twentyOnePlusThree: TwentyOnePlusThreeType.STRAIGHT },
336
+ },
337
+ {
338
+ input: [
339
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '2' }),
340
+ [CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '3' }), CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: 'A' })],
341
+ ],
342
+ output: { twentyOnePlusThree: TwentyOnePlusThreeType.STRAIGHT },
343
+ },
344
+ {
345
+ input: [
346
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'Q' }),
347
+ [CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: 'K' }), CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: 'A' })],
348
+ ],
349
+ output: { twentyOnePlusThree: TwentyOnePlusThreeType.STRAIGHT },
350
+ },
351
+ {
352
+ input: [
353
+ CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '3' }),
354
+ [CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: 'K' }), CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: 'A' })],
355
+ ],
356
+ output: { twentyOnePlusThree: TwentyOnePlusThreeType.FLUSH },
357
+ },
358
+ {
359
+ input: [
360
+ CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '3' }),
361
+ [CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: 'K' }), CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: 'K' })],
362
+ ],
363
+ output: { perfectPair: PerfectPairType.PERFECT_PAIR, twentyOnePlusThree: TwentyOnePlusThreeType.FLUSH },
364
+ },
365
+ // No wrap around for straight
366
+ {
367
+ input: [
368
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: 'K' }),
369
+ [CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: 'A' }), CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '2' })],
370
+ ],
371
+ output: { twentyOnePlusThree: TwentyOnePlusThreeType.FLUSH },
372
+ },
373
+ ];
374
+
375
+ funcParams.forEach((param) => {
376
+ const result = Blackjack.calcSideBetWins(...param.input);
377
+ expect(result.perfectPair).toEqual(param.output.perfectPair);
378
+ expect(result.twentyOnePlusThree).toEqual(param.output?.twentyOnePlusThree);
379
+ });
380
+ /**
381
+ * Check for all possible combinations of each side bet individually (5 and 3)
382
+ * Check for a few together (2)
383
+ */
384
+ });
385
+
386
+ it('can calculate the value of cards', () => {
387
+ const funcParams: Array<{ input: number[]; output: number }> = [
388
+ { input: [getIndex('10'), getIndex('A')], output: 21 },
389
+ { input: [getIndex('9'), getIndex('A')], output: 20 },
390
+ { input: [getIndex('5'), getIndex('A')], output: 16 },
391
+ { input: [getIndex('A'), getIndex('10'), getIndex('10')], output: 21 },
392
+ { input: [getIndex('A'), getIndex('A'), getIndex('10'), getIndex('7')], output: 19 },
393
+ { input: [getIndex('A'), getIndex('A')], output: 12 },
394
+ { input: [getIndex('A'), getIndex('A'), getIndex('5')], output: 17 },
395
+ { input: [getIndex('A'), getIndex('A'), getIndex('A'), getIndex('A'), getIndex('5')], output: 19 },
396
+ {
397
+ input: [
398
+ getIndex('A'),
399
+ getIndex('A'),
400
+ getIndex('A'),
401
+ getIndex('A'),
402
+ getIndex('A'),
403
+ getIndex('A'),
404
+ getIndex('A'),
405
+ getIndex('A'),
406
+ getIndex('A'),
407
+ getIndex('A'),
408
+ getIndex('A'),
409
+ getIndex('A'),
410
+ getIndex('2'),
411
+ ],
412
+ output: 14,
413
+ },
414
+ {
415
+ input: [
416
+ getIndex('A'),
417
+ getIndex('A'),
418
+ getIndex('A'),
419
+ getIndex('A'),
420
+ getIndex('A'),
421
+ getIndex('A'),
422
+ getIndex('A'),
423
+ getIndex('A'),
424
+ getIndex('A'),
425
+ getIndex('A'),
426
+ getIndex('A'),
427
+ ],
428
+ output: 21,
429
+ },
430
+ // max number of cards in a player's hand is 20
431
+ {
432
+ input: [
433
+ getIndex('A'),
434
+ getIndex('A'),
435
+ getIndex('A'),
436
+ getIndex('A'),
437
+ getIndex('A'),
438
+ getIndex('A'),
439
+ getIndex('A'),
440
+ getIndex('A'),
441
+ getIndex('A'),
442
+ getIndex('A'),
443
+ getIndex('2'),
444
+ getIndex('A'),
445
+ getIndex('A'),
446
+ getIndex('A'),
447
+ getIndex('A'),
448
+ getIndex('A'),
449
+ getIndex('A'),
450
+ getIndex('A'),
451
+ getIndex('A'),
452
+ getIndex('2'),
453
+ ],
454
+ output: 22,
455
+ },
456
+ { input: [getIndex('A'), getIndex('A'), getIndex('A'), getIndex('A'), getIndex('5')], output: 19 },
457
+ { input: [getIndex('A'), getIndex('4'), getIndex('5'), getIndex('10')], output: 20 },
458
+ { input: [getIndex('A'), getIndex('4'), getIndex('5'), getIndex('10'), getIndex('J')], output: 30 },
459
+ { input: [getIndex('2'), getIndex('4'), getIndex('6'), getIndex('7')], output: 19 },
460
+ { input: [getIndex('3'), getIndex('10'), getIndex('6'), getIndex('7')], output: 26 },
461
+ { input: [getIndex('2'), getIndex('3'), getIndex('4'), getIndex('5'), getIndex('6'), getIndex('7')], output: 27 },
462
+ { input: [getIndex('A'), getIndex('8'), getIndex('9'), getIndex('10')], output: 28 },
463
+ ];
464
+
465
+ funcParams.forEach((param) => {
466
+ expect(Blackjack.calcHandValue(param.input)).toEqual(param.output);
467
+ });
468
+ });
469
+
470
+ it('can check if a hand has blackjack', () => {
471
+ const funcParams: Array<{ input: number[]; output: boolean }> = [
472
+ { input: [getIndex('10'), getIndex('A')], output: true },
473
+ { input: [getIndex('A'), getIndex('J')], output: true },
474
+ { input: [getIndex('Q'), getIndex('A')], output: true },
475
+ { input: [getIndex('K'), getIndex('A')], output: true },
476
+ { input: [getIndex('A'), getIndex('A')], output: false },
477
+ { input: [getIndex('10'), getIndex('J')], output: false },
478
+ { input: [getIndex('9'), getIndex('3')], output: false },
479
+ { input: [getIndex('A'), getIndex('8')], output: false },
480
+ ];
481
+
482
+ funcParams.forEach((param) => {
483
+ expect(Blackjack.isBlackjack(param.input)).toEqual(param.output);
484
+ });
485
+ /**
486
+ * Blackjack
487
+ * No blackjack because sum is not 21
488
+ * No blackjack even though sum is 21 because there are more than 2 cards
489
+ */
490
+ });
491
+
492
+ it('can check if a player can buy insurance', () => {
493
+ const funcParams: Array<{ input: number[]; output: boolean }> = [
494
+ { input: [getIndex('A'), getIndex('10')], output: true },
495
+ { input: [getIndex('A'), getIndex('4')], output: true },
496
+ { input: [getIndex('10'), getIndex('A')], output: false },
497
+ { input: [getIndex('10'), getIndex('3')], output: false },
498
+ { input: [getIndex('3'), getIndex('4')], output: false },
499
+ ];
500
+
501
+ funcParams.forEach((param) => {
502
+ expect(Blackjack.canBuyInsurance(param.input)).toEqual(param.output);
503
+ });
504
+ });
505
+
506
+ it('can check if a dealer should hit', () => {
507
+ const funcParams: Array<{ input: number[]; output: boolean }> = [
508
+ { input: [getIndex('A'), getIndex('10')], output: false },
509
+ { input: [getIndex('A'), getIndex('6')], output: false },
510
+ { input: [getIndex('6'), getIndex('10')], output: true },
511
+ { input: [getIndex('7'), getIndex('10')], output: false },
512
+ { input: [getIndex('10'), getIndex('10')], output: false },
513
+ { input: [getIndex('A'), getIndex('A'), getIndex('A'), getIndex('A'), getIndex('A'), getIndex('A'), getIndex('5')], output: false },
514
+ { input: [getIndex('A'), getIndex('A'), getIndex('A'), getIndex('A'), getIndex('A'), getIndex('A'), getIndex('6')], output: true },
515
+ // max number of cards while dealer still hits is 11
516
+ {
517
+ input: [
518
+ getIndex('A'),
519
+ getIndex('A'),
520
+ getIndex('A'),
521
+ getIndex('A'),
522
+ getIndex('A'),
523
+ getIndex('A'),
524
+ getIndex('6'),
525
+ getIndex('A'),
526
+ getIndex('A'),
527
+ getIndex('A'),
528
+ getIndex('A'),
529
+ ],
530
+ output: true,
531
+ },
532
+ {
533
+ input: [getIndex('2'), getIndex('3'), getIndex('4'), getIndex('5'), getIndex('3')],
534
+ output: false,
535
+ },
536
+ // dealer stands on soft 17
537
+ {
538
+ input: [getIndex('2'), getIndex('6'), getIndex('A')],
539
+ output: false,
540
+ },
541
+ ];
542
+
543
+ funcParams.forEach((param) => {
544
+ expect(Blackjack.shouldDealerHit(param.input)).toEqual(param.output);
545
+ });
546
+ });
547
+
548
+ it('can calculate the total payout correctly', () => {
549
+ const funcParams: Array<{ input: SettleBetVars; output: BigNumber }> = [
550
+ // Without sidebets
551
+ // blackjack win
552
+ {
553
+ input: {
554
+ mainPlayerHand: [getIndex('A'), getIndex('10')],
555
+ splitPlayerHand: [],
556
+ dealerHand: [getIndex('10'), getIndex('10')],
557
+ mainHandBetAmount: new BigNumber(10),
558
+ splitHandBetAmount: new BigNumber(0),
559
+ twentyOnePlusThreeAmount: new BigNumber(0),
560
+ perfectPairAmount: new BigNumber(0),
561
+ boughtInsurance: false,
562
+ hasSplit: false,
563
+ },
564
+ output: new BigNumber(25),
565
+ },
566
+ // blackjack push
567
+ {
568
+ input: {
569
+ mainPlayerHand: [getIndex('A'), getIndex('10')],
570
+ splitPlayerHand: [],
571
+ dealerHand: [getIndex('10'), getIndex('A')],
572
+ mainHandBetAmount: new BigNumber(10),
573
+ splitHandBetAmount: new BigNumber(0),
574
+ twentyOnePlusThreeAmount: new BigNumber(0),
575
+ perfectPairAmount: new BigNumber(0),
576
+ boughtInsurance: false,
577
+ hasSplit: false,
578
+ },
579
+ output: new BigNumber(10),
580
+ },
581
+ // blackjack lose
582
+ {
583
+ input: {
584
+ mainPlayerHand: [getIndex('A'), getIndex('6')],
585
+ splitPlayerHand: [],
586
+ dealerHand: [getIndex('10'), getIndex('A')],
587
+ mainHandBetAmount: new BigNumber(10),
588
+ splitHandBetAmount: new BigNumber(0),
589
+ twentyOnePlusThreeAmount: new BigNumber(0),
590
+ perfectPairAmount: new BigNumber(0),
591
+ boughtInsurance: false,
592
+ hasSplit: false,
593
+ },
594
+ output: new BigNumber(0),
595
+ },
596
+ // no blackjack win
597
+ {
598
+ input: {
599
+ mainPlayerHand: [getIndex('A'), getIndex('6'), getIndex('4')],
600
+ splitPlayerHand: [],
601
+ dealerHand: [getIndex('10'), getIndex('4')],
602
+ mainHandBetAmount: new BigNumber(10),
603
+ splitHandBetAmount: new BigNumber(0),
604
+ twentyOnePlusThreeAmount: new BigNumber(0),
605
+ perfectPairAmount: new BigNumber(0),
606
+ boughtInsurance: false,
607
+ hasSplit: false,
608
+ },
609
+ output: new BigNumber(20),
610
+ },
611
+ {
612
+ input: {
613
+ mainPlayerHand: [getIndex('A'), getIndex('6'), getIndex('4')],
614
+ splitPlayerHand: [],
615
+ dealerHand: [getIndex('10'), getIndex('4'), getIndex('10')],
616
+ mainHandBetAmount: new BigNumber(10),
617
+ splitHandBetAmount: new BigNumber(0),
618
+ twentyOnePlusThreeAmount: new BigNumber(0),
619
+ perfectPairAmount: new BigNumber(0),
620
+ boughtInsurance: false,
621
+ hasSplit: false,
622
+ },
623
+ output: new BigNumber(20),
624
+ },
625
+ // no blackjack push
626
+ {
627
+ input: {
628
+ mainPlayerHand: [getIndex('A'), getIndex('6')],
629
+ splitPlayerHand: [],
630
+ dealerHand: [getIndex('10'), getIndex('4'), getIndex('3')],
631
+ mainHandBetAmount: new BigNumber(10),
632
+ splitHandBetAmount: new BigNumber(0),
633
+ twentyOnePlusThreeAmount: new BigNumber(0),
634
+ perfectPairAmount: new BigNumber(0),
635
+ boughtInsurance: false,
636
+ hasSplit: false,
637
+ },
638
+ output: new BigNumber(10),
639
+ },
640
+ {
641
+ input: {
642
+ mainPlayerHand: [getIndex('10'), getIndex('6'), getIndex('4')],
643
+ splitPlayerHand: [],
644
+ dealerHand: [getIndex('10'), getIndex('4'), getIndex('6')],
645
+ mainHandBetAmount: new BigNumber(10),
646
+ splitHandBetAmount: new BigNumber(0),
647
+ twentyOnePlusThreeAmount: new BigNumber(0),
648
+ perfectPairAmount: new BigNumber(0),
649
+ boughtInsurance: false,
650
+ hasSplit: false,
651
+ },
652
+ output: new BigNumber(10),
653
+ },
654
+ // no blackjack lose
655
+ {
656
+ input: {
657
+ mainPlayerHand: [getIndex('A'), getIndex('6')],
658
+ splitPlayerHand: [],
659
+ dealerHand: [getIndex('10'), getIndex('J')],
660
+ mainHandBetAmount: new BigNumber(10),
661
+ splitHandBetAmount: new BigNumber(0),
662
+ twentyOnePlusThreeAmount: new BigNumber(0),
663
+ perfectPairAmount: new BigNumber(0),
664
+ boughtInsurance: false,
665
+ hasSplit: false,
666
+ },
667
+ output: new BigNumber(0),
668
+ },
669
+ {
670
+ input: {
671
+ mainPlayerHand: [getIndex('J'), getIndex('6'), getIndex('9')],
672
+ splitPlayerHand: [],
673
+ dealerHand: [getIndex('10'), getIndex('J')],
674
+ mainHandBetAmount: new BigNumber(10),
675
+ splitHandBetAmount: new BigNumber(0),
676
+ twentyOnePlusThreeAmount: new BigNumber(0),
677
+ perfectPairAmount: new BigNumber(0),
678
+ boughtInsurance: false,
679
+ hasSplit: false,
680
+ },
681
+ output: new BigNumber(0),
682
+ },
683
+
684
+ {
685
+ input: {
686
+ mainPlayerHand: [
687
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
688
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
689
+ ],
690
+ splitPlayerHand: [],
691
+ dealerHand: [CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }), getIndex('7')],
692
+ mainHandBetAmount: new BigNumber(10),
693
+ splitHandBetAmount: new BigNumber(0),
694
+ twentyOnePlusThreeAmount: new BigNumber(10),
695
+ perfectPairAmount: new BigNumber(20),
696
+ boughtInsurance: false,
697
+ hasSplit: false,
698
+ },
699
+ output: new BigNumber(1550), // 10 * 101 + 20 * 26 + 2 * 10
700
+ },
701
+ {
702
+ input: {
703
+ mainPlayerHand: [CardGames.getCardIndexFromDetails({ suit: Suits.HEARTS, value: '10' }), getIndex('A')],
704
+ splitPlayerHand: [],
705
+ dealerHand: [
706
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
707
+ CardGames.getCardIndexFromDetails({ suit: Suits.HEARTS, value: '10' }),
708
+ ],
709
+ mainHandBetAmount: new BigNumber(10),
710
+ splitHandBetAmount: new BigNumber(0),
711
+ twentyOnePlusThreeAmount: new BigNumber(0),
712
+ perfectPairAmount: new BigNumber(10),
713
+ boughtInsurance: false,
714
+ hasSplit: false,
715
+ },
716
+ output: new BigNumber(25),
717
+ },
718
+ {
719
+ input: {
720
+ mainPlayerHand: [
721
+ CardGames.getCardIndexFromDetails({ suit: Suits.HEARTS, value: '10' }),
722
+ CardGames.getCardIndexFromDetails({ suit: Suits.HEARTS, value: '10' }),
723
+ ],
724
+ splitPlayerHand: [],
725
+ dealerHand: [CardGames.getCardIndexFromDetails({ suit: Suits.HEARTS, value: 'J' }), getIndex('A')],
726
+ mainHandBetAmount: new BigNumber(10),
727
+ splitHandBetAmount: new BigNumber(0),
728
+ twentyOnePlusThreeAmount: new BigNumber(10),
729
+ perfectPairAmount: new BigNumber(0),
730
+ boughtInsurance: false,
731
+ hasSplit: false,
732
+ },
733
+ output: new BigNumber(60),
734
+ },
735
+
736
+ // With insurance
737
+ {
738
+ input: {
739
+ mainPlayerHand: [getIndex('A'), getIndex('10')],
740
+ splitPlayerHand: [],
741
+ dealerHand: [getIndex('A'), getIndex('3')],
742
+ mainHandBetAmount: new BigNumber(10),
743
+ splitHandBetAmount: new BigNumber(0),
744
+ twentyOnePlusThreeAmount: new BigNumber(0),
745
+ perfectPairAmount: new BigNumber(0),
746
+ boughtInsurance: true,
747
+ hasSplit: false,
748
+ },
749
+ output: new BigNumber(25),
750
+ },
751
+ // blackjack push
752
+ {
753
+ input: {
754
+ mainPlayerHand: [getIndex('A'), getIndex('10')],
755
+ splitPlayerHand: [],
756
+ dealerHand: [getIndex('A'), getIndex('K')],
757
+ mainHandBetAmount: new BigNumber(10),
758
+ splitHandBetAmount: new BigNumber(0),
759
+ twentyOnePlusThreeAmount: new BigNumber(0),
760
+ perfectPairAmount: new BigNumber(0),
761
+ boughtInsurance: true,
762
+ hasSplit: false,
763
+ },
764
+ output: new BigNumber(25),
765
+ },
766
+ // blackjack lose
767
+ {
768
+ input: {
769
+ mainPlayerHand: [getIndex('A'), getIndex('6')],
770
+ splitPlayerHand: [],
771
+ dealerHand: [getIndex('A'), getIndex('J')],
772
+ mainHandBetAmount: new BigNumber(10),
773
+ splitHandBetAmount: new BigNumber(0),
774
+ twentyOnePlusThreeAmount: new BigNumber(0),
775
+ perfectPairAmount: new BigNumber(0),
776
+ boughtInsurance: false,
777
+ hasSplit: false,
778
+ },
779
+ output: new BigNumber(0),
780
+ },
781
+
782
+ // With insurance and sidebets
783
+ {
784
+ input: {
785
+ mainPlayerHand: [
786
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
787
+ CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '10' }),
788
+ ],
789
+ splitPlayerHand: [],
790
+ dealerHand: [getIndex('A'), getIndex('J')],
791
+ mainHandBetAmount: new BigNumber(10),
792
+ splitHandBetAmount: new BigNumber(0),
793
+ twentyOnePlusThreeAmount: new BigNumber(0),
794
+ perfectPairAmount: new BigNumber(0),
795
+ boughtInsurance: true,
796
+ hasSplit: false,
797
+ },
798
+ output: new BigNumber(15),
799
+ },
800
+ {
801
+ input: {
802
+ mainPlayerHand: [
803
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
804
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '10' }),
805
+ ],
806
+ splitPlayerHand: [],
807
+ dealerHand: [getIndex('A'), getIndex('9')],
808
+ mainHandBetAmount: new BigNumber(10),
809
+ splitHandBetAmount: new BigNumber(0),
810
+ twentyOnePlusThreeAmount: new BigNumber(0),
811
+ perfectPairAmount: new BigNumber(0),
812
+ boughtInsurance: true,
813
+ hasSplit: false,
814
+ },
815
+ output: new BigNumber(10),
816
+ },
817
+
818
+ // Split bets without sidebets or insurance
819
+ // Split 2 wins
820
+ {
821
+ input: {
822
+ mainPlayerHand: [
823
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
824
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '10' }),
825
+ ],
826
+ splitPlayerHand: [
827
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
828
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '7' }),
829
+ ],
830
+ dealerHand: [getIndex('6'), getIndex('10')],
831
+ mainHandBetAmount: new BigNumber(10),
832
+ splitHandBetAmount: new BigNumber(10),
833
+ twentyOnePlusThreeAmount: new BigNumber(0),
834
+ perfectPairAmount: new BigNumber(0),
835
+ boughtInsurance: false,
836
+ hasSplit: true,
837
+ },
838
+ output: new BigNumber(40),
839
+ },
840
+ // Split 1 win 1 push
841
+ {
842
+ input: {
843
+ mainPlayerHand: [
844
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
845
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '10' }),
846
+ ],
847
+ splitPlayerHand: [
848
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
849
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '8' }),
850
+ ],
851
+ dealerHand: [getIndex('8'), getIndex('10')],
852
+ mainHandBetAmount: new BigNumber(10),
853
+ splitHandBetAmount: new BigNumber(10),
854
+ twentyOnePlusThreeAmount: new BigNumber(0),
855
+ perfectPairAmount: new BigNumber(0),
856
+ boughtInsurance: false,
857
+ hasSplit: true,
858
+ },
859
+ output: new BigNumber(30),
860
+ },
861
+ // Split 1 win 1 lose
862
+ {
863
+ input: {
864
+ mainPlayerHand: [
865
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
866
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '10' }),
867
+ ],
868
+ splitPlayerHand: [
869
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
870
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '5' }),
871
+ ],
872
+ dealerHand: [getIndex('8'), getIndex('10')],
873
+ mainHandBetAmount: new BigNumber(10),
874
+ splitHandBetAmount: new BigNumber(10),
875
+ twentyOnePlusThreeAmount: new BigNumber(0),
876
+ perfectPairAmount: new BigNumber(0),
877
+ boughtInsurance: false,
878
+ hasSplit: true,
879
+ },
880
+ output: new BigNumber(20),
881
+ },
882
+ // Split 2 push
883
+ {
884
+ input: {
885
+ mainPlayerHand: [
886
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
887
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '10' }),
888
+ ],
889
+ splitPlayerHand: [
890
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
891
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
892
+ ],
893
+ dealerHand: [getIndex('10'), getIndex('10')],
894
+ mainHandBetAmount: new BigNumber(10),
895
+ splitHandBetAmount: new BigNumber(10),
896
+ twentyOnePlusThreeAmount: new BigNumber(0),
897
+ perfectPairAmount: new BigNumber(0),
898
+ boughtInsurance: false,
899
+ hasSplit: true,
900
+ },
901
+ output: new BigNumber(20),
902
+ },
903
+ // Split 1 push 1 lose
904
+ {
905
+ input: {
906
+ mainPlayerHand: [
907
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
908
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '7' }),
909
+ ],
910
+ splitPlayerHand: [
911
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
912
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '5' }),
913
+ ],
914
+ dealerHand: [getIndex('10'), getIndex('7')],
915
+ mainHandBetAmount: new BigNumber(10),
916
+ splitHandBetAmount: new BigNumber(10),
917
+ twentyOnePlusThreeAmount: new BigNumber(0),
918
+ perfectPairAmount: new BigNumber(0),
919
+ boughtInsurance: false,
920
+ hasSplit: true,
921
+ },
922
+ output: new BigNumber(10),
923
+ },
924
+ // Split 2 lose
925
+ {
926
+ input: {
927
+ mainPlayerHand: [
928
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
929
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '7' }),
930
+ ],
931
+ splitPlayerHand: [
932
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
933
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '8' }),
934
+ ],
935
+ dealerHand: [getIndex('10'), getIndex('10')],
936
+ mainHandBetAmount: new BigNumber(10),
937
+ splitHandBetAmount: new BigNumber(10),
938
+ twentyOnePlusThreeAmount: new BigNumber(0),
939
+ perfectPairAmount: new BigNumber(0),
940
+ boughtInsurance: false,
941
+ hasSplit: true,
942
+ },
943
+ output: new BigNumber(0),
944
+ },
945
+
946
+ // Split blackjacks
947
+ {
948
+ input: {
949
+ mainPlayerHand: [
950
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
951
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: 'A' }),
952
+ ],
953
+ splitPlayerHand: [
954
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
955
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }),
956
+ ],
957
+ dealerHand: [getIndex('10'), getIndex('10')],
958
+ mainHandBetAmount: new BigNumber(10),
959
+ splitHandBetAmount: new BigNumber(10),
960
+ twentyOnePlusThreeAmount: new BigNumber(0),
961
+ perfectPairAmount: new BigNumber(0),
962
+ boughtInsurance: false,
963
+ hasSplit: true,
964
+ },
965
+ output: new BigNumber(40),
966
+ },
967
+
968
+ // Split Aces
969
+ {
970
+ input: {
971
+ mainPlayerHand: [
972
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }),
973
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '4' }),
974
+ ],
975
+ splitPlayerHand: [
976
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }),
977
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
978
+ ],
979
+ dealerHand: [getIndex('10'), getIndex('10')],
980
+ mainHandBetAmount: new BigNumber(10),
981
+ splitHandBetAmount: new BigNumber(10),
982
+ twentyOnePlusThreeAmount: new BigNumber(0),
983
+ perfectPairAmount: new BigNumber(0),
984
+ boughtInsurance: false,
985
+ hasSplit: true,
986
+ },
987
+ output: new BigNumber(20),
988
+ },
989
+
990
+ // Split bets with double down and sidebets and insurance
991
+ {
992
+ input: {
993
+ mainPlayerHand: [
994
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
995
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '4' }),
996
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '5' }),
997
+ ],
998
+ splitPlayerHand: [
999
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
1000
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
1001
+ ],
1002
+ dealerHand: [
1003
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }),
1004
+ CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '7' }),
1005
+ ],
1006
+ mainHandBetAmount: new BigNumber(20),
1007
+ splitHandBetAmount: new BigNumber(10),
1008
+ twentyOnePlusThreeAmount: new BigNumber(10),
1009
+ perfectPairAmount: new BigNumber(10),
1010
+ boughtInsurance: true,
1011
+ hasSplit: true,
1012
+ },
1013
+ output: new BigNumber(380), // win main (40) + win split (20) + perfect pair (10*26) + flush (10*6)
1014
+ },
1015
+ {
1016
+ input: {
1017
+ mainPlayerHand: [
1018
+ CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '10' }),
1019
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '4' }),
1020
+ CardGames.getCardIndexFromDetails({ suit: Suits.SPADES, value: '4' }),
1021
+ ],
1022
+ splitPlayerHand: [
1023
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: '10' }),
1024
+ CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '10' }),
1025
+ ],
1026
+ dealerHand: [
1027
+ CardGames.getCardIndexFromDetails({ suit: Suits.CLUBS, value: 'A' }),
1028
+ CardGames.getCardIndexFromDetails({ suit: Suits.DIAMONDS, value: '9' }),
1029
+ ],
1030
+ mainHandBetAmount: new BigNumber(10),
1031
+ splitHandBetAmount: new BigNumber(20),
1032
+ twentyOnePlusThreeAmount: new BigNumber(10),
1033
+ perfectPairAmount: new BigNumber(10),
1034
+ boughtInsurance: true,
1035
+ hasSplit: true,
1036
+ },
1037
+ output: new BigNumber(90), // push split (20) + mixed pair (7*10)
1038
+ },
1039
+ ];
1040
+
1041
+ funcParams.forEach((param) => {
1042
+ expect(Blackjack.getPayout(param.input)).toEqual(param.output);
1043
+ });
1044
+ /**
1045
+ * ONLY 1 HAND(no splits)
1046
+ * 1. Only main bet
1047
+ * - 1 win scenario
1048
+ * - 1 push scenario
1049
+ * - 1 lose scenario (no need to test specifics as it's alr tested above)
1050
+ *
1051
+ * 2. Main bet with sidebets
1052
+ * - test 1 win/lose/push scenario for main bet
1053
+ * - win 1 sidebet
1054
+ * - win 2 sidebets
1055
+ *
1056
+ * 3. Main bet with sidebets and insurance
1057
+ * - test 1 win/lose/push scenario for main bet
1058
+ * - with/without sidebets
1059
+ * - win insurance
1060
+ * - lose insurance
1061
+ *
1062
+ * 4. Split bets
1063
+ * - test 1 win/lose/push scenario for main hand
1064
+ * - test 1 win/lose/push for split hand
1065
+ * - with/without sidebets
1066
+ * - with/without insurance :(
1067
+ *
1068
+ * 5. Split bets with double down and sidebets and insurance
1069
+ *
1070
+ * 6. Split bets with split aces and sidebets and insurance
1071
+ *
1072
+ */
1073
+ });
1074
+ });