poker-bitvaljs 1.1.0 → 1.1.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/bitval-worker.js +152 -0
- package/package.json +3 -2
package/bitval-worker.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// Web Worker for parallel matchup evaluation
|
|
2
|
+
// Loads bitval.js to access BitVal class and dependencies
|
|
3
|
+
importScripts('bitval.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Deserializes setup data from main thread (converts string BigInts back to BigInt)
|
|
7
|
+
*/
|
|
8
|
+
function deserializeSetup(setupData) {
|
|
9
|
+
const setup = {
|
|
10
|
+
...setupData,
|
|
11
|
+
boardMask: BigInt(setupData.boardMask),
|
|
12
|
+
deadCardsMask: BigInt(setupData.deadCardsMask),
|
|
13
|
+
comboArray: setupData.comboArray ? setupData.comboArray.map(s => BigInt(s)) : null,
|
|
14
|
+
// Keep other properties as-is
|
|
15
|
+
boardCards: setupData.boardCards,
|
|
16
|
+
numberOfBoardCards: setupData.numberOfBoardCards,
|
|
17
|
+
iterations: setupData.iterations,
|
|
18
|
+
isExhaustive: setupData.isExhaustive,
|
|
19
|
+
numberOfCardsToDeal: setupData.numberOfCardsToDeal
|
|
20
|
+
};
|
|
21
|
+
return setup;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Deserializes matchup data (converts string BigInt masks back to BigInt)
|
|
26
|
+
*/
|
|
27
|
+
function deserializeMatchup(matchupData) {
|
|
28
|
+
return {
|
|
29
|
+
...matchupData,
|
|
30
|
+
heroMask: BigInt(matchupData.heroMask),
|
|
31
|
+
villainMask: BigInt(matchupData.villainMask)
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Evaluates a single matchup in the worker context
|
|
37
|
+
* Similar to _evaluateMatchup but without progress callbacks
|
|
38
|
+
*/
|
|
39
|
+
async function evaluateMatchupInWorker(heroMask, villainMask, setup, evalCache, cacheInfo, bitval) {
|
|
40
|
+
let win = 0, tie = 0, lose = 0;
|
|
41
|
+
const deadMask = heroMask | villainMask | setup.deadCardsMask;
|
|
42
|
+
|
|
43
|
+
// Initialize random number generator for Monte Carlo (not needed for exhaustive)
|
|
44
|
+
if (!setup.isExhaustive) {
|
|
45
|
+
bitval.xorShift = new XorShift32();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Prepare for exhaustive enumeration if applicable
|
|
49
|
+
let comboArray = null;
|
|
50
|
+
let iterations = setup.iterations;
|
|
51
|
+
if (setup.isExhaustive) {
|
|
52
|
+
// Use comboArray from setup if available, otherwise compute it
|
|
53
|
+
if (setup.comboArray && setup.comboArray.length > 0) {
|
|
54
|
+
comboArray = setup.comboArray;
|
|
55
|
+
iterations = comboArray.length;
|
|
56
|
+
} else {
|
|
57
|
+
// Compute comboArray if not provided
|
|
58
|
+
const availableMasks = bitval._getAvailableCardMasksByLookUp(deadMask);
|
|
59
|
+
comboArray = bitval._getCombinations(availableMasks, setup.numberOfCardsToDeal);
|
|
60
|
+
iterations = comboArray.length;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Main evaluation loop
|
|
65
|
+
for (let i = 0; i < iterations; i++) {
|
|
66
|
+
// Generate board: use pre-computed combo for exhaustive, or deal randomly
|
|
67
|
+
const board = setup.isExhaustive
|
|
68
|
+
? setup.boardMask | comboArray[i]
|
|
69
|
+
: bitval.deal(setup.boardMask, deadMask, setup.numberOfCardsToDeal) | setup.boardMask;
|
|
70
|
+
|
|
71
|
+
// Evaluate both hands
|
|
72
|
+
let hEval, hKick, vEval, vKick;
|
|
73
|
+
if (cacheInfo && evalCache) {
|
|
74
|
+
[hEval, hKick] = bitval._getCachedEvaluation(cacheInfo.heroKey, cacheInfo.heroHand, board, evalCache);
|
|
75
|
+
[vEval, vKick] = bitval._getCachedEvaluation(cacheInfo.villainKey, cacheInfo.villainHand, board, evalCache);
|
|
76
|
+
} else {
|
|
77
|
+
[hEval, hKick] = bitval.evaluate(heroMask | board);
|
|
78
|
+
[vEval, vKick] = bitval.evaluate(villainMask | board);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Compare and accumulate results
|
|
82
|
+
if (hEval > vEval || (hEval === vEval && hKick > vKick)) {
|
|
83
|
+
win++;
|
|
84
|
+
} else if (vEval > hEval || (vEval === hEval && vKick > hKick)) {
|
|
85
|
+
lose++;
|
|
86
|
+
} else {
|
|
87
|
+
tie++;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return { matchupWin: win, matchupTie: tie, matchupLose: lose };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Worker message handler
|
|
95
|
+
self.onmessage = async function(e) {
|
|
96
|
+
try {
|
|
97
|
+
const { matchups, setupData, workerId } = e.data;
|
|
98
|
+
|
|
99
|
+
// Deserialize setup
|
|
100
|
+
const setup = deserializeSetup(setupData);
|
|
101
|
+
|
|
102
|
+
// Create BitVal instance and cache for this worker (reused for all matchups)
|
|
103
|
+
const bitval = new BitVal();
|
|
104
|
+
const evalCache = new FastestAutoClearingCache(16000000);
|
|
105
|
+
|
|
106
|
+
const results = [];
|
|
107
|
+
|
|
108
|
+
// Evaluate each matchup in the batch
|
|
109
|
+
for (const matchupData of matchups) {
|
|
110
|
+
const matchup = deserializeMatchup(matchupData);
|
|
111
|
+
|
|
112
|
+
// Prepare cache info if available
|
|
113
|
+
const cacheInfo = matchup.heroKey ? {
|
|
114
|
+
heroKey: matchup.heroKey,
|
|
115
|
+
heroHand: matchup.heroHand,
|
|
116
|
+
villainKey: matchup.villainKey,
|
|
117
|
+
villainHand: matchup.villainHand
|
|
118
|
+
} : null;
|
|
119
|
+
|
|
120
|
+
// Evaluate matchup
|
|
121
|
+
const result = await evaluateMatchupInWorker(
|
|
122
|
+
matchup.heroMask,
|
|
123
|
+
matchup.villainMask,
|
|
124
|
+
setup,
|
|
125
|
+
evalCache,
|
|
126
|
+
cacheInfo,
|
|
127
|
+
bitval
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
results.push({
|
|
131
|
+
key: matchup.key,
|
|
132
|
+
validCount: matchup.validCount,
|
|
133
|
+
...result
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Send results back to main thread
|
|
138
|
+
self.postMessage({
|
|
139
|
+
workerId,
|
|
140
|
+
results,
|
|
141
|
+
success: true
|
|
142
|
+
});
|
|
143
|
+
} catch (error) {
|
|
144
|
+
// Send error back to main thread
|
|
145
|
+
self.postMessage({
|
|
146
|
+
workerId: e.data.workerId,
|
|
147
|
+
error: error.message,
|
|
148
|
+
success: false
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "poker-bitvaljs",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "High-performance poker hand evaluator optimized for browser environments, using bitwise operations for rapid poker hand analysis and equity calculations.",
|
|
5
5
|
"main": "bitval.js",
|
|
6
6
|
"scripts": {
|
|
@@ -19,10 +19,11 @@
|
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
|
-
"url": "https://github.com/DarraghGeo/poker-bitvaljs.git"
|
|
22
|
+
"url": "git+https://github.com/DarraghGeo/poker-bitvaljs.git"
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"bitval.js",
|
|
26
|
+
"bitval-worker.js",
|
|
26
27
|
"README.md"
|
|
27
28
|
]
|
|
28
29
|
}
|