shufflecom-calculations 1.2.4 → 1.3.0
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.js +4 -1
- package/lib/games/blackjack.js.map +1 -1
- package/lib/games/roulette.d.ts +119 -0
- package/lib/games/roulette.js +353 -0
- package/lib/games/roulette.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/utils/dates-calculator.js +2 -2
- package/lib/utils/dates-calculator.js.map +1 -1
- package/package.json +2 -2
- package/src/games/blackjack.spec.ts +20 -1
- package/src/games/blackjack.ts +5 -1
- package/src/games/roulette.spec.ts +521 -0
- package/src/games/roulette.ts +521 -0
- package/src/index.ts +1 -0
- package/src/utils/dates-calculator.ts +2 -2
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import BigNumber from 'bignumber.js';
|
|
2
|
+
import { hexToBytes } from '../utils/hex-to-bytes';
|
|
3
|
+
const BYTE_TOTAL = BigNumber(256);
|
|
4
|
+
const TOTAL_TILES = BigNumber(37);
|
|
5
|
+
|
|
6
|
+
// Outside Bets
|
|
7
|
+
export enum RouletteParity {
|
|
8
|
+
EVEN = 'EVEN',
|
|
9
|
+
ODD = 'ODD',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface RouletteParityInput {
|
|
13
|
+
parity: RouletteParity;
|
|
14
|
+
amount: BigNumber; // check to be placed for negative numbers
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export enum RouletteColor {
|
|
18
|
+
RED = 'RED',
|
|
19
|
+
BLACK = 'BLACK',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface ColorInput {
|
|
23
|
+
color: RouletteColor;
|
|
24
|
+
amount: BigNumber;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export enum RouletteColumn {
|
|
28
|
+
TOP = 'TOP',
|
|
29
|
+
MIDDLE = 'MIDDLE',
|
|
30
|
+
BOTTOM = 'BOTTOM',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface ColumnInput {
|
|
34
|
+
column: RouletteColumn;
|
|
35
|
+
amount: BigNumber;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export enum RouletteDozen {
|
|
39
|
+
FIRST = 'FIRST',
|
|
40
|
+
SECOND = 'SECOND',
|
|
41
|
+
THIRD = 'THIRD',
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface DozenInput {
|
|
45
|
+
dozen: RouletteDozen;
|
|
46
|
+
amount: BigNumber;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export enum RouletteHalf {
|
|
50
|
+
LOW = 'LOW',
|
|
51
|
+
HIGH = 'HIGH',
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface HalfInput {
|
|
55
|
+
half: RouletteHalf;
|
|
56
|
+
amount: BigNumber;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Inside bets involving 0
|
|
60
|
+
// Straight 0
|
|
61
|
+
// Split 0,1/0,2/0,3
|
|
62
|
+
// Street 0,1,2/0,2,3 (0,1,3 is not included as it's not physically on the board)
|
|
63
|
+
// Corner 0,1,2,3
|
|
64
|
+
// No double street
|
|
65
|
+
|
|
66
|
+
export const STRAIGHT_VALUES = [
|
|
67
|
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
|
68
|
+
] as const;
|
|
69
|
+
export const STREET_VALUES = [
|
|
70
|
+
// these 2 are the only street that are not allowed in a double street as it's not physically possible on the board
|
|
71
|
+
[0, 1, 2],
|
|
72
|
+
[0, 2, 3],
|
|
73
|
+
// every other adjacent street below is a valid double street pair
|
|
74
|
+
[1, 2, 3],
|
|
75
|
+
[4, 5, 6],
|
|
76
|
+
[7, 8, 9],
|
|
77
|
+
[10, 11, 12],
|
|
78
|
+
[13, 14, 15],
|
|
79
|
+
[16, 17, 18],
|
|
80
|
+
[19, 20, 21],
|
|
81
|
+
[22, 23, 24],
|
|
82
|
+
[25, 26, 27],
|
|
83
|
+
[28, 29, 30],
|
|
84
|
+
[31, 32, 33],
|
|
85
|
+
[34, 35, 36],
|
|
86
|
+
] as const;
|
|
87
|
+
|
|
88
|
+
export type straightValue = (typeof STRAIGHT_VALUES)[number];
|
|
89
|
+
|
|
90
|
+
export type streetValue = (typeof STREET_VALUES)[number];
|
|
91
|
+
|
|
92
|
+
export interface StraightInput {
|
|
93
|
+
straightNumber: straightValue;
|
|
94
|
+
amount: BigNumber;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface SplitInput {
|
|
98
|
+
firstNumber: straightValue;
|
|
99
|
+
secondNumber: straightValue;
|
|
100
|
+
amount: BigNumber;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface CornerInput {
|
|
104
|
+
firstNumber: straightValue;
|
|
105
|
+
secondNumber: straightValue;
|
|
106
|
+
thirdNumber: straightValue;
|
|
107
|
+
fourthNumber: straightValue;
|
|
108
|
+
|
|
109
|
+
amount: BigNumber;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface StreetInput {
|
|
113
|
+
street: streetValue;
|
|
114
|
+
amount: BigNumber;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface DoubleStreetInput {
|
|
118
|
+
firstStreet: streetValue;
|
|
119
|
+
secondStreet: streetValue;
|
|
120
|
+
amount: BigNumber;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// !: Needs to match RoulettePlayInput input type
|
|
124
|
+
export interface RouletteInput {
|
|
125
|
+
// outside bets
|
|
126
|
+
parityValues: RouletteParityInput[];
|
|
127
|
+
colorValues: ColorInput[];
|
|
128
|
+
halfValues: HalfInput[];
|
|
129
|
+
columnValues: ColumnInput[];
|
|
130
|
+
dozenValues: DozenInput[];
|
|
131
|
+
|
|
132
|
+
// inside bets
|
|
133
|
+
straightValues: StraightInput[];
|
|
134
|
+
splitValues: SplitInput[];
|
|
135
|
+
streetValues: StreetInput[]; // number is the smallest number in the column
|
|
136
|
+
cornerValues: CornerInput[]; // check to be done that it's a valid corner
|
|
137
|
+
doubleStreetValues: DoubleStreetInput[]; // firstNumber is the smallest number in the column, secondNumber is the smallest number in the adjacent column
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const isValidStraight = (num: number): boolean => {
|
|
141
|
+
return STRAIGHT_VALUES.includes(num as straightValue);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export const isValidStreet = (street: streetValue): boolean => {
|
|
145
|
+
const sortedStreet = (street as unknown as number[]).sort((a, b) => a - b);
|
|
146
|
+
|
|
147
|
+
return sortedStreet.length === 3 && STREET_VALUES.some((val) => val[0] === sortedStreet[0] && val[1] === sortedStreet[1] && val[2] === sortedStreet[2]);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// for corners (up, down, left, right, and diagonally adjacent)
|
|
151
|
+
export const cornerNumbers = (num: straightValue): straightValue[] => {
|
|
152
|
+
if (!isValidStraight(num)) {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// need to hardcode as 0 is a special case
|
|
157
|
+
if (num === 0) {
|
|
158
|
+
return [1, 2, 3];
|
|
159
|
+
} else if (num === 1) {
|
|
160
|
+
return [0, 2, 3, 4, 5];
|
|
161
|
+
} else if (num === 2) {
|
|
162
|
+
return [0, 1, 3, 4, 5, 6];
|
|
163
|
+
} else if (num === 3) {
|
|
164
|
+
return [0, 1, 2, 5, 6];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// when num is 0
|
|
168
|
+
let possibleCornerNumbers: number[] = [];
|
|
169
|
+
if (num % 3 === 1) {
|
|
170
|
+
possibleCornerNumbers = [num - 3, num - 2, num + 1, num + 3, num + 4];
|
|
171
|
+
} else if (num % 3 === 2) {
|
|
172
|
+
possibleCornerNumbers = [num - 4, num - 3, num - 2, num - 1, num + 1, num + 2, num + 3, num + 4];
|
|
173
|
+
} else {
|
|
174
|
+
possibleCornerNumbers = [num - 4, num - 3, num - 1, num + 2, num + 3];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return possibleCornerNumbers.filter((num) => isValidStraight(num)) as straightValue[];
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// up, down, left, right
|
|
181
|
+
export const isValidSplit = (firstNumber: straightValue, secondNumber: straightValue): boolean => {
|
|
182
|
+
if (!isValidStraight(firstNumber) || !isValidStraight(secondNumber)) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let possibleSplitNumbers: number[] = [];
|
|
187
|
+
|
|
188
|
+
if (firstNumber % 3 === 1) {
|
|
189
|
+
possibleSplitNumbers = [firstNumber - 3, firstNumber + 1, firstNumber + 3];
|
|
190
|
+
} else if (firstNumber % 3 === 2) {
|
|
191
|
+
possibleSplitNumbers = [firstNumber - 3, firstNumber - 1, firstNumber + 1, firstNumber + 3];
|
|
192
|
+
} else {
|
|
193
|
+
possibleSplitNumbers = [firstNumber - 3, firstNumber - 1, firstNumber + 3];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const filteredPossibleSplitNumbers = possibleSplitNumbers.filter((num) => isValidStraight(num)) as straightValue[];
|
|
197
|
+
|
|
198
|
+
if (firstNumber !== 0 && secondNumber !== 0) {
|
|
199
|
+
return filteredPossibleSplitNumbers.includes(secondNumber);
|
|
200
|
+
} else if (firstNumber === 0) {
|
|
201
|
+
return secondNumber === 1 || secondNumber === 2 || secondNumber === 3;
|
|
202
|
+
} else if (secondNumber === 0) {
|
|
203
|
+
return firstNumber === 1 || firstNumber === 2 || firstNumber === 3;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return false; // should never reach here
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export const isValidCorner = (firstNumber: straightValue, secondNumber: straightValue, thirdNumber: straightValue, fourthNumber: straightValue): boolean => {
|
|
210
|
+
// all 4 numbers MUST be adjacent to every other number
|
|
211
|
+
const numbersAdjacentToFirstNumber = cornerNumbers(firstNumber);
|
|
212
|
+
const numbersAdjacentToSecondNumber = cornerNumbers(secondNumber);
|
|
213
|
+
const numbersAdjacentToThirdNumber = cornerNumbers(thirdNumber);
|
|
214
|
+
const numbersAdjacentToFourthNumber = cornerNumbers(fourthNumber);
|
|
215
|
+
|
|
216
|
+
const allNumsAdjacentToFirstNumber =
|
|
217
|
+
numbersAdjacentToFirstNumber.includes(secondNumber) &&
|
|
218
|
+
numbersAdjacentToFirstNumber.includes(thirdNumber) &&
|
|
219
|
+
numbersAdjacentToFirstNumber.includes(fourthNumber);
|
|
220
|
+
|
|
221
|
+
const allNumsAdjacentToSecondNumber =
|
|
222
|
+
numbersAdjacentToSecondNumber.includes(firstNumber) &&
|
|
223
|
+
numbersAdjacentToSecondNumber.includes(thirdNumber) &&
|
|
224
|
+
numbersAdjacentToSecondNumber.includes(fourthNumber);
|
|
225
|
+
|
|
226
|
+
const allNumsAdjacentToThirdNumber =
|
|
227
|
+
numbersAdjacentToThirdNumber.includes(firstNumber) &&
|
|
228
|
+
numbersAdjacentToThirdNumber.includes(secondNumber) &&
|
|
229
|
+
numbersAdjacentToThirdNumber.includes(fourthNumber);
|
|
230
|
+
|
|
231
|
+
const allNumsAdjacentToFourthNumber =
|
|
232
|
+
numbersAdjacentToFourthNumber.includes(firstNumber) &&
|
|
233
|
+
numbersAdjacentToFourthNumber.includes(secondNumber) &&
|
|
234
|
+
numbersAdjacentToFourthNumber.includes(thirdNumber);
|
|
235
|
+
|
|
236
|
+
return allNumsAdjacentToFirstNumber && allNumsAdjacentToSecondNumber && allNumsAdjacentToThirdNumber && allNumsAdjacentToFourthNumber;
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
export const isValidDoubleStreet = (firstStreet: streetValue, secondStreet: streetValue): boolean => {
|
|
240
|
+
if (!isValidStreet(firstStreet) || !isValidStreet(secondStreet)) {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const firstNumOfFirstStreet = firstStreet[0];
|
|
245
|
+
const firstNumOfSecondStreet = secondStreet[0];
|
|
246
|
+
|
|
247
|
+
// 0 is not in any valid double streets
|
|
248
|
+
if (firstNumOfFirstStreet === 0 || firstNumOfSecondStreet === 0) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return firstNumOfFirstStreet + 3 === firstNumOfSecondStreet || firstNumOfFirstStreet - 3 === firstNumOfSecondStreet;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
export enum BetType {
|
|
256
|
+
// outside bets
|
|
257
|
+
PARITY = 'PARITY',
|
|
258
|
+
COLOR = 'COLOR',
|
|
259
|
+
HALF = 'HALF',
|
|
260
|
+
COLUMN = 'COLUMN',
|
|
261
|
+
DOZEN = 'DOZEN',
|
|
262
|
+
|
|
263
|
+
// inside bets
|
|
264
|
+
STRAIGHT = 'STRAIGHT',
|
|
265
|
+
SPLIT = 'SPLIT',
|
|
266
|
+
STREET = 'STREET',
|
|
267
|
+
CORNER = 'CORNER',
|
|
268
|
+
DOUBLE_STREET = 'DOUBLE_STREET',
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// payout, not profit
|
|
272
|
+
const PAYOUT_MAP: Record<BetType, BigNumber> = {
|
|
273
|
+
[BetType.PARITY]: BigNumber(2),
|
|
274
|
+
[BetType.COLOR]: BigNumber(2),
|
|
275
|
+
[BetType.HALF]: BigNumber(2),
|
|
276
|
+
[BetType.COLUMN]: BigNumber(3),
|
|
277
|
+
[BetType.DOZEN]: BigNumber(3),
|
|
278
|
+
[BetType.STRAIGHT]: BigNumber(36),
|
|
279
|
+
[BetType.SPLIT]: BigNumber(18),
|
|
280
|
+
[BetType.STREET]: BigNumber(12),
|
|
281
|
+
[BetType.CORNER]: BigNumber(9),
|
|
282
|
+
[BetType.DOUBLE_STREET]: BigNumber(6),
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
export const RED_NUMBERS = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];
|
|
286
|
+
export const BLACK_NUMBERS = [2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 26, 28, 29, 31, 33, 35];
|
|
287
|
+
|
|
288
|
+
// Payout stuff
|
|
289
|
+
export const parityPayout = ({ parity, amount }: RouletteParityInput, result: straightValue): BigNumber => {
|
|
290
|
+
if (result === 0) return BigNumber(0);
|
|
291
|
+
|
|
292
|
+
const resultParity = result % 2 === 0 ? RouletteParity.EVEN : RouletteParity.ODD;
|
|
293
|
+
const isWin = parity === resultParity;
|
|
294
|
+
|
|
295
|
+
if (isWin) {
|
|
296
|
+
return amount.multipliedBy(PAYOUT_MAP[BetType.PARITY]);
|
|
297
|
+
}
|
|
298
|
+
return BigNumber(0);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
export const colorPayout = ({ color, amount }: ColorInput, result: straightValue): BigNumber => {
|
|
302
|
+
const isRed = RED_NUMBERS.includes(result);
|
|
303
|
+
const isBlack = BLACK_NUMBERS.includes(result);
|
|
304
|
+
|
|
305
|
+
if ((isRed && color === RouletteColor.RED) || (isBlack && color === RouletteColor.BLACK)) {
|
|
306
|
+
return amount.multipliedBy(PAYOUT_MAP[BetType.COLOR]);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return BigNumber(0);
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
export const halfsPayout = ({ half, amount }: HalfInput, result: straightValue): BigNumber => {
|
|
313
|
+
const isLow = result > 0 && result <= 18;
|
|
314
|
+
const isHigh = result > 18 && result <= 36;
|
|
315
|
+
|
|
316
|
+
if ((isLow && half === RouletteHalf.LOW) || (isHigh && half === RouletteHalf.HIGH)) {
|
|
317
|
+
return amount.multipliedBy(PAYOUT_MAP[BetType.HALF]);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return BigNumber(0);
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
export const columnPayout = ({ column, amount }: ColumnInput, result: straightValue): BigNumber => {
|
|
324
|
+
const topColumn = [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36];
|
|
325
|
+
const middleColumn = [2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35];
|
|
326
|
+
const bottomColumn = [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34];
|
|
327
|
+
|
|
328
|
+
if (
|
|
329
|
+
(column === RouletteColumn.TOP && topColumn.includes(result)) ||
|
|
330
|
+
(column === RouletteColumn.MIDDLE && middleColumn.includes(result)) ||
|
|
331
|
+
(column === RouletteColumn.BOTTOM && bottomColumn.includes(result))
|
|
332
|
+
) {
|
|
333
|
+
return amount.multipliedBy(PAYOUT_MAP[BetType.COLUMN]);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return BigNumber(0);
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
export const dozenPayout = ({ dozen, amount }: DozenInput, result: straightValue): BigNumber => {
|
|
340
|
+
const firstDozen = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
|
341
|
+
const secondDozen = [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24];
|
|
342
|
+
const thirdDozen = [25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36];
|
|
343
|
+
|
|
344
|
+
if (
|
|
345
|
+
(dozen === RouletteDozen.FIRST && firstDozen.includes(result)) ||
|
|
346
|
+
(dozen === RouletteDozen.SECOND && secondDozen.includes(result)) ||
|
|
347
|
+
(dozen === RouletteDozen.THIRD && thirdDozen.includes(result))
|
|
348
|
+
) {
|
|
349
|
+
return amount.multipliedBy(PAYOUT_MAP[BetType.DOZEN]);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return BigNumber(0);
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
export const straightPayout = ({ straightNumber, amount }: StraightInput, result: straightValue): BigNumber => {
|
|
356
|
+
if (result === straightNumber) {
|
|
357
|
+
return amount.multipliedBy(PAYOUT_MAP[BetType.STRAIGHT]);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return BigNumber(0);
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
export const splitPayout = ({ firstNumber, secondNumber, amount }: SplitInput, result: straightValue): BigNumber => {
|
|
364
|
+
if (result === firstNumber || result === secondNumber) {
|
|
365
|
+
return amount.multipliedBy(PAYOUT_MAP[BetType.SPLIT]);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return BigNumber(0);
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
export const streetPayout = ({ street, amount }: StreetInput, result: straightValue): BigNumber => {
|
|
372
|
+
if ((street as readonly number[]).includes(result)) {
|
|
373
|
+
return amount.multipliedBy(PAYOUT_MAP[BetType.STREET]);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return BigNumber(0);
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
export const cornerPayout = ({ firstNumber, secondNumber, thirdNumber, fourthNumber, amount }: CornerInput, result: straightValue): BigNumber => {
|
|
380
|
+
const cornerNumbers = [firstNumber, secondNumber, thirdNumber, fourthNumber];
|
|
381
|
+
|
|
382
|
+
if (cornerNumbers.includes(result)) {
|
|
383
|
+
return amount.multipliedBy(PAYOUT_MAP[BetType.CORNER]);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return BigNumber(0);
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
export const doubleStreetPayout = ({ firstStreet, secondStreet, amount }: DoubleStreetInput, result: straightValue): BigNumber => {
|
|
390
|
+
if ((firstStreet as readonly number[]).includes(result) || (secondStreet as readonly number[]).includes(result)) {
|
|
391
|
+
return amount.multipliedBy(PAYOUT_MAP[BetType.DOUBLE_STREET]);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return BigNumber(0);
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
export class Roulette {
|
|
398
|
+
// get a whole number from 0-36 inclusive
|
|
399
|
+
static getResult(hexStr: string): straightValue {
|
|
400
|
+
const gameResultBytes = hexToBytes(hexStr);
|
|
401
|
+
|
|
402
|
+
let result = BigNumber(0);
|
|
403
|
+
|
|
404
|
+
// Only use the first 4
|
|
405
|
+
for (let i = 0; i < 4; i++) {
|
|
406
|
+
const value = gameResultBytes[i];
|
|
407
|
+
result = result.plus(BigNumber(value).dividedBy(BYTE_TOTAL.pow(i + 1)));
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const resultNum = result.multipliedBy(TOTAL_TILES).integerValue(BigNumber.ROUND_DOWN).toNumber() as straightValue;
|
|
411
|
+
|
|
412
|
+
if (!isValidStraight(resultNum)) {
|
|
413
|
+
throw new Error('Invalid result');
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return resultNum;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
static getPayout(inputs: RouletteInput, result: straightValue): BigNumber {
|
|
420
|
+
if (!this.validateInputs(inputs)) {
|
|
421
|
+
throw new Error('Invalid inputs');
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const {
|
|
425
|
+
// outside bets
|
|
426
|
+
parityValues,
|
|
427
|
+
colorValues,
|
|
428
|
+
halfValues,
|
|
429
|
+
columnValues,
|
|
430
|
+
dozenValues,
|
|
431
|
+
|
|
432
|
+
// inside bets
|
|
433
|
+
straightValues,
|
|
434
|
+
splitValues,
|
|
435
|
+
streetValues,
|
|
436
|
+
cornerValues,
|
|
437
|
+
doubleStreetValues,
|
|
438
|
+
} = inputs;
|
|
439
|
+
|
|
440
|
+
const totalParityPayout = parityValues.reduce((totalPayout, input) => {
|
|
441
|
+
return totalPayout.plus(parityPayout(input, result));
|
|
442
|
+
}, BigNumber(0));
|
|
443
|
+
|
|
444
|
+
const totalColorPayout = colorValues.reduce((totalPayout, input) => {
|
|
445
|
+
return totalPayout.plus(colorPayout(input, result));
|
|
446
|
+
}, BigNumber(0));
|
|
447
|
+
|
|
448
|
+
const totalHalfsPayout = halfValues.reduce((totalPayout, input) => {
|
|
449
|
+
return totalPayout.plus(halfsPayout(input, result));
|
|
450
|
+
}, BigNumber(0));
|
|
451
|
+
|
|
452
|
+
const totalColumnsPayout = columnValues.reduce((totalPayout, input) => {
|
|
453
|
+
return totalPayout.plus(columnPayout(input, result));
|
|
454
|
+
}, BigNumber(0));
|
|
455
|
+
|
|
456
|
+
const totalDozensPayout = dozenValues.reduce((totalPayout, input) => {
|
|
457
|
+
return totalPayout.plus(dozenPayout(input, result));
|
|
458
|
+
}, BigNumber(0));
|
|
459
|
+
|
|
460
|
+
const totalStraightsPayout = straightValues.reduce((totalPayout, input) => {
|
|
461
|
+
return totalPayout.plus(straightPayout(input, result));
|
|
462
|
+
}, BigNumber(0));
|
|
463
|
+
|
|
464
|
+
const totalSplitPayout = splitValues.reduce((totalPayout, input) => {
|
|
465
|
+
return totalPayout.plus(splitPayout(input, result));
|
|
466
|
+
}, BigNumber(0));
|
|
467
|
+
|
|
468
|
+
const totalStreetPayout = streetValues.reduce((totalPayout, input) => {
|
|
469
|
+
return totalPayout.plus(streetPayout(input, result));
|
|
470
|
+
}, BigNumber(0));
|
|
471
|
+
|
|
472
|
+
const totalCornerPayout = cornerValues.reduce((totalPayout, input) => {
|
|
473
|
+
return totalPayout.plus(cornerPayout(input, result));
|
|
474
|
+
}, BigNumber(0));
|
|
475
|
+
|
|
476
|
+
const totalDoubleStreetPayout = doubleStreetValues.reduce((totalPayout, input) => {
|
|
477
|
+
return totalPayout.plus(doubleStreetPayout(input, result));
|
|
478
|
+
}, BigNumber(0));
|
|
479
|
+
|
|
480
|
+
const totalPayout = totalParityPayout
|
|
481
|
+
.plus(totalColorPayout)
|
|
482
|
+
.plus(totalHalfsPayout)
|
|
483
|
+
.plus(totalColumnsPayout)
|
|
484
|
+
.plus(totalDozensPayout)
|
|
485
|
+
.plus(totalStraightsPayout)
|
|
486
|
+
.plus(totalSplitPayout)
|
|
487
|
+
.plus(totalStreetPayout)
|
|
488
|
+
.plus(totalCornerPayout)
|
|
489
|
+
.plus(totalDoubleStreetPayout);
|
|
490
|
+
|
|
491
|
+
return totalPayout;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
static validateInputs(inputs: RouletteInput): boolean {
|
|
495
|
+
const { straightValues, splitValues, streetValues, cornerValues, doubleStreetValues, parityValues, colorValues, columnValues, dozenValues, halfValues } =
|
|
496
|
+
inputs;
|
|
497
|
+
// user must bet on at least one thing
|
|
498
|
+
if (
|
|
499
|
+
straightValues.length === 0 &&
|
|
500
|
+
splitValues.length === 0 &&
|
|
501
|
+
streetValues.length === 0 &&
|
|
502
|
+
cornerValues.length === 0 &&
|
|
503
|
+
doubleStreetValues.length === 0 &&
|
|
504
|
+
parityValues.length === 0 &&
|
|
505
|
+
colorValues.length === 0 &&
|
|
506
|
+
columnValues.length === 0 &&
|
|
507
|
+
dozenValues.length === 0 &&
|
|
508
|
+
halfValues.length === 0
|
|
509
|
+
) {
|
|
510
|
+
return false;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const straightsValid = straightValues.every((input) => isValidStraight(input.straightNumber));
|
|
514
|
+
const splitsValid = splitValues.every((input) => isValidSplit(input.firstNumber, input.secondNumber));
|
|
515
|
+
const streetsValid = streetValues.every((input) => isValidStreet(input.street));
|
|
516
|
+
const cornersValid = cornerValues.every((input) => isValidCorner(input.firstNumber, input.secondNumber, input.thirdNumber, input.fourthNumber));
|
|
517
|
+
const doubleStreetsValid = doubleStreetValues.every((input) => isValidDoubleStreet(input.firstStreet, input.secondStreet));
|
|
518
|
+
|
|
519
|
+
return straightsValid && splitsValid && streetsValid && cornersValid && doubleStreetsValid;
|
|
520
|
+
}
|
|
521
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export { VipBonusIssuanceStatus } from './utils/vip-bonus.type';
|
|
|
9
9
|
export { deriveBonusIssuances } from './utils/derive-vip-bonus';
|
|
10
10
|
export { convertBs58ToUuid, convertUuidToBs58 } from './utils/uuid-converter';
|
|
11
11
|
export { Dice, DiceDirection } from './games/dice';
|
|
12
|
+
export { Roulette } from './games/roulette';
|
|
12
13
|
export { Mines } from './games/mines';
|
|
13
14
|
export { Plinko, PlinkoRiskLevel } from './games/plinko';
|
|
14
15
|
export { Crash } from './games/crash';
|
|
@@ -6,7 +6,7 @@ export class DatesCalculator {
|
|
|
6
6
|
// Most recent thursday at 11:00 UTC
|
|
7
7
|
static startOfWeeklyBonus = (utcDate: Dayjs) => {
|
|
8
8
|
if (!utcDate.isUTC()) {
|
|
9
|
-
throw 'utcDate must be in UTC';
|
|
9
|
+
throw new Error('utcDate must be in UTC');
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
const thisThursday = utcDate.startOf('week').set('day', 4).set('hour', 11);
|
|
@@ -21,7 +21,7 @@ export class DatesCalculator {
|
|
|
21
21
|
// Most recent first friday of a month at 00:00 UTC
|
|
22
22
|
static startOfMonthlyBonus = (utcDate: Dayjs): Date => {
|
|
23
23
|
if (!utcDate.isUTC()) {
|
|
24
|
-
throw 'utcDate must be in UTC';
|
|
24
|
+
throw new Error('utcDate must be in UTC');
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const startOfMonth = utcDate.startOf('month');
|