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.
- package/lib/games/blackjack.d.ts +58 -0
- package/lib/games/blackjack.js +253 -0
- package/lib/games/blackjack.js.map +1 -0
- package/lib/games/cardGames.d.ts +20 -0
- package/lib/games/cardGames.js +86 -0
- package/lib/games/cardGames.js.map +1 -0
- package/lib/games/hilo.d.ts +0 -4
- package/lib/games/hilo.js +4 -49
- package/lib/games/hilo.js.map +1 -1
- package/lib/index.d.ts +3 -1
- package/lib/index.js +13 -2
- package/lib/index.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.js +4 -1
- package/lib/utils/index.js.map +1 -1
- package/package.json +2 -2
- package/src/games/blackjack.spec.ts +1074 -0
- package/src/games/blackjack.ts +352 -0
- package/src/games/cardGames.spec.ts +94 -0
- package/src/games/cardGames.ts +107 -0
- package/src/games/hilo.spec.ts +1 -84
- package/src/games/hilo.ts +6 -68
- package/src/index.ts +11 -1
- package/src/utils/index.ts +1 -0
|
@@ -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
|
+
});
|