Last active
December 19, 2022 11:14
-
-
Save dsetzer/779929913e33a1b3e66724bb843226df to your computer and use it in GitHub Desktop.
Dynamic Pattern System v1.4 work in progress prototype for bustabit/bustadice scripts.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ----------------------- V1.4 ------------------------- | |
// This utility function will check an array of game results for a given pattern and return the most recent occurrence of a | |
// match. The pattern is specified using a regex-style syntax that uses the available tokens defined in the token list. The | |
// token list is an array of objects containing a token letter and a callback function that is used to check if the game results | |
// match the specified condition. It returns an array containing the game result objects for the matched results. | |
function checkPattern(pattern, results, tokens){ | |
let tokenLetters = pattern.match(/\w/g); | |
let filteredTokens = tokens.filter((token) => tokenLetters.includes(token[0])); | |
let res = results.map((r, i) => (`[${i}${filteredTokens.filter((e) => e[1](r)).map((e) => (e[0])).join('')}]`)).reverse().join(''); | |
let seqParser = /(\w)([+*?]|\{[,\d\s]+\})?/g, m, c = 0, steps = []; | |
while (++c < 1000 && (m = seqParser.exec(pattern)) !== null) { | |
if (m.index === seqParser.lastIndex) seqParser.lastIndex++; | |
steps.push([`s${steps.length}`, `(?<s${steps.length}>\\[(\\d+)\\w*(?<t${steps.length}>${m[1]})\\w*\\])${m[2]||''}`]); | |
} | |
let seq = new RegExp(`${steps.map((s) => (s[1])).join('')}`, 'g'); | |
let match = [...seq.exec(res)[0].matchAll(/(\d+)/g)].reverse(); | |
let result = `[${match.map((m)=>([Number(m[0]), JSON.stringify(results[Number(m[0])])])).join()}]`; | |
return JSON.parse(result); | |
} | |
// Tokens can be created to check for any type of condition. Token format is: | |
// [ | |
// token: string, | |
// callback: function(result: {}) | |
// ] | |
// The callback is called with a single argument provided which contains the current game result. | |
// This includes all relevant properties (r.wager, r.cashedAt, r.bust, etc) same as available from engine.history.first() | |
// Here is an example token which matches a winning bet with a profit greater than 5 bits | |
// ['P', (r) => { return (r.wager && r.cashedAt && (r.wager * (r.cashedAt - 1)) > 500); }] | |
// Below is a generalized set of common/useful tokens for pattern finding: | |
// const tokenList = [ | |
// //Token, Callback, Explanation | |
// ['R', (r) => { return (r.bust < 1.98); }], // Result is red (less than the median) | |
// ['G', (r) => { return (r.bust >= 1.98); }], // Result is green (equal/greater than median) | |
// ['W', (r) => { return (r.wager && r.cashedAt); }], // Bet was placed and won | |
// ['L', (r) => { return (r.wager && !r.cashedAt); }], // Bet was placed and lost | |
// ['S', (r) => { return (!r.wager); }], // Game was skipped (no bet placed) | |
// ['B', (r) => { return (r.wager); }] // Game was played (bet placed) | |
// ]; | |
// Pattern sequence follows regex style and is built using the letters | |
// available in the token list. An optional quantifier can be specified | |
// for each token. | |
// Pattern sequence is comprised of one or more: <letter>[quantifier] | |
// Quantifiers available are the same as available in regex: | |
// + : one or more | |
// * : zero or more | |
// ? : zero or one | |
// {3} : exactly three | |
// {1,3} : between one and three | |
// {3,} : three or more | |
// {,3} : three or fewer | |
// Example pattern sequences: | |
// "GGRR" - Finds two consecutive greens followed by two consecutive reds (green is >= 1.98, red is < 1.98) | |
// "R{6}" - Finds 6 consecutive reds (games < 1.98) | |
// "GGR+G*R{1,3}R?G" - Finds two greens, one or more reds, zero or more greens, 1-4 reds, and a final green. | |
// "S{6,}R" - Finds at least 6 skipped games then | |
// Example of using the function: | |
// NOTE: the following function is not required or part of the system, only for demo purposes. | |
// Normally you will have an array of real game results that get stored into an array at the end of each game. | |
function generateResults(count, house = 0.01) { | |
let results = new Array(count); | |
for (let i = 0; i < count; i++){ | |
results[i] = (Math.min(1e6, Math.max(1, (0.99 / Math.random())))).toFixed(2); | |
} | |
let games = results.map((r)=>{ | |
return {bust: r, wager: (Math.random() > 0.5 ? 100 : 0), payout: 2, cashedAt: (r <= 2 ? 2 : 0)} | |
}); | |
return games; | |
} | |
let results = generateResults(5000); // this is our set of imitation game results. | |
// This is the actual example call to the function using the imitation results above and the token list defined up at the top of this file. | |
let match = checkPattern('G+R{3}GGGR*G{1,2}', results, tokenList); | |
// The most recent occurrence found is returned as an array containing the game result objects for the matched results. | |
console.log(match); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment