Skip to content

Instantly share code, notes, and snippets.

@himanshupal
Created April 23, 2023 02:31
Show Gist options
  • Save himanshupal/d3917eaf09ef19a3aea092c7bd7ab7fd to your computer and use it in GitHub Desktop.
Save himanshupal/d3917eaf09ef19a3aea092c7bd7ab7fd to your computer and use it in GitHub Desktop.
Types & helper function added for bit-meddler
const INT_MAX = ~(1 << (32 - 1))
const ITSAKINDOFMAGIC = [
0x3,
0x6,
0x9,
0x1d,
0x36,
0x69,
0xa6, // 2 to 8
0x17c,
0x32d,
0x4f2,
0xd34,
0x1349,
0x2532,
0x6699,
0xd295, // 9 - 16
0x12933,
0x2c93e,
0x593ca,
0xaff95,
0x12b6bc,
0x2e652e,
0x5373d6,
0x9ccdae, // etc
0x12ba74d,
0x36cd5a7,
0x4e5d793,
0xf5cde95,
0x1a4e6ff2,
0x29d1e9eb,
0x7a5bc2e3,
0xb4bcd35c,
]
/**
* Returns randomish integers in a given range
* https://github.com/alanmacleod/bit-meddler
*/
class BitMeddler {
private maximum: number
private start: number
private mask: number
private cur: number
/**
* @param maximum The maximum value to return
* @param seed should be > 0 and < maximum; if provided
*/
constructor(maximum: number, seed = 1) {
if (maximum < 2 || maximum > INT_MAX) {
throw '`maximum` must be between 2 and ' + INT_MAX + ' inclusive'
}
this.maximum = maximum
this.start = seed % this.maximum
this.cur = this.start
this.mask = ITSAKINDOFMAGIC[this._msb(this.maximum) - 2]
this.next = this._next
}
private _next() {
do {
this.cur = this.cur & 1 ? (this.cur = (this.cur >> 1) ^ this.mask) : (this.cur >>= 1)
} while (this.cur > this.maximum)
this.cur === this.start && (this.next = this._done)
return this.cur
}
private _done() {
return null
}
private _msb(v: number) {
let r = 0
while (v) {
v >>= 1
r++
}
return r
}
public next(): number | null {
return null
}
public reset() {
this.next = this._next
this.cur = this.start
}
public all() {
this.reset()
let o: number[] = [],
v: number | null = null
while ((v = this.next())) o.push(v)
return o
}
}
export function generateRandomWithin(max: number, seed?: number) {
const meddler = new BitMeddler(max, seed)
function* nextRandom(reset?: boolean) {
let next = meddler.next()
if (!next || reset) {
meddler.reset()
next = meddler.next()
}
yield next
}
return function (reset?: boolean) {
// We don't need to check for 'done' here because the generator is handling that for us
return nextRandom(reset).next().value!
}
}
export default BitMeddler
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment