{
const { squaresPerSide, fractionEmpty, moveThreshold } = params;
AA.random.seed(seed);
const sim = new AA.Simulation({
width: squaresPerSide * 5,
height: squaresPerSide * 5,
gridStep: 5
});
invalidation.then(() => sim.end());
const nEmpty = Math.round(sim.squares.size * fractionEmpty);
for (let [i, sq] of AA.shuffle([...sim.squares]).entries()) {
sq.label('land', i < nEmpty ? 2 : i % 2);
}
const unhappy = () => sim.squares.filter(sq => {
const land = sq.label('land');
if (land === 2) return false;
const layer = sq.layer();
return layer.reduce((count, neb) => count + (neb.label('land') === land), 0) /
layer.reduce((count, neb) => count + (neb.label('land') !== 2), 0)
< moveThreshold;
}, true);
const rand = AA.random.int(nEmpty);
sim.beforeTick = () => {
for (let sq of AA.shuffle(unhappy())) {
[...sim.withLabel('land', 2)][rand()]
.label('land', sq.label('land'));
sq.label('land', 2);
}
};
const tints = [AV.colors.blue, AV.colors.orange, 0xbbbbbb];
sim.squares.forEach(sq => {
sq.zIndex = -Infinity
sq.vis({tint: sq => tints[sq.label('land')]});
});
return AV.visObs(sim, {
stats: true,
backParticles: true,
});
}