PachinkoQuadTree = {
class PachinkoQuadTree {
constructor(depth, seed) {
this.depth = depth;
let size = 1;
this.offsets = [0];
for (let i = 1; i <= depth; i++) {
this.offsets[i] = size;
size += 4 ** i;
}
this.pachinkoBitNodes = new Uint8Array(size);
this.valueLeaves = new Uint32Array(4 ** depth);
}
clear() {
this.pachinkoBitNodes.fill(0);
this.valueLeaves.fill(0);
}
idx(x, y, depth) {
return this.offsets[depth] + x + y * 2 ** depth;
}
getBits(x, y, depth) {
return this.pachinkoBitNodes[this.idx(x, y, depth)];
}
setBits(x, y, depth, bits) {
this.pachinkoBitNodes[this.idx(x, y, depth)] = bits;
}
pickChild(x, y, depth) {
const bits = this.getBits(x, y, depth);
const r = ((Math.random() * 12) | 0) * 2;
const picks = this.picks[bits];
const randomPick = (picks >> r) & 0b11;
const xn = randomPick & 1;
const yn = randomPick >> 1;
x = (x << 1) + xn;
y = (y << 1) + yn;
return [x, y];
}
randomWalk() {
let xy = [0, 0];
let depth = 0;
for (let i = 0; i < this.depth; i++) {
xy = this.pickChild(xy[0], xy[1], depth++);
}
return xy;
}
applyPick(x, y, index) {
this.valueLeaves[x + y * 2 ** this.depth] = index;
for (let i = 0; i < this.depth; i++) {
const xi = x >> (this.depth - i);
const yi = y >> (this.depth - i);
const idx = this.idx(xi, yi, i);
const xn = x >> (this.depth - 1 - i);
const yn = y >> (this.depth - 1 - i);
const pick = 0b1000 >> ((xn & 1) + ((yn & 1) << 1));
const bits = this.pachinkoBitNodes[idx];
const updatedBits = bits | pick;
this.pachinkoBitNodes[idx] = updatedBits === 0b1111 ? 0 : updatedBits;
}
}
insert(val) {
const xy = this.randomWalk();
this.applyPick(xy[0], xy[1], val);
return xy;
}
}
const TOP = 0,
BOTTOM = 2,
LEFT = 0,
RIGHT = 1,
TL = TOP + LEFT,
TR = TOP + RIGHT,
BL = BOTTOM + LEFT,
BR = BOTTOM + RIGHT;
const packPicks = (...picks) => {
let out = 0;
for (const pick of picks) {
out = (out << 2) + pick;
}
console.log({ picks, out });
return out;
};
const picks = Uint32Array.from([
packPicks(TL, TL, TL, TR, TR, TR, BL, BL, BL, BR, BR, BR),
packPicks(TL, TL, TL, TL, TR, TR, TR, TR, BL, BL, BL, BL),
packPicks(TL, TL, TL, TL, TR, TR, TR, TR, BR, BR, BR, BR),
packPicks(TL, TL, TL, TL, TL, TL, TR, TR, TR, TR, TR, TR),
packPicks(TL, TL, TL, TL, BL, BL, BL, BL, BR, BR, BR, BR),
packPicks(TL, TL, TL, TL, TL, TL, BL, BL, BL, BL, BL, BL),
packPicks(TL, TL, TL, TL, TL, TL, BR, BR, BR, BR, BR, BR),
packPicks(TL, TL, TL, TL, TL, TL, TL, TL, TL, TL, TL, TL),
packPicks(TR, TR, TR, TR, BL, BL, BL, BL, BR, BR, BR, BR),
packPicks(TR, TR, TR, TR, TR, TR, BL, BL, BL, BL, BL, BL),
packPicks(TR, TR, TR, TR, TR, TR, BR, BR, BR, BR, BR, BR),
packPicks(TR, TR, TR, TR, TR, TR, TR, TR, TR, TR, TR, TR),
packPicks(BL, BL, BL, BR, BR, BR, BL, BL, BL, BR, BR, BR),
packPicks(BL, BL, BL, BL, BL, BL, BL, BL, BL, BL, BL, BL),
packPicks(BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR)
]);
Object.assign(PachinkoQuadTree.prototype, {
TOP,
BOTTOM,
LEFT,
RIGHT,
TL,
TR,
BL,
BR,
picks
});
return PachinkoQuadTree;
}