Skip to content

Instantly share code, notes, and snippets.

@dsetzer
Last active December 19, 2022 11:14
Show Gist options
  • Save dsetzer/779929913e33a1b3e66724bb843226df to your computer and use it in GitHub Desktop.
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.
// ----------------------- 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