Published
Edited
May 23, 2022
1 fork
3 stars
Insert cell
Insert cell
Insert cell
Insert cell
{
// parameters
const { squaresPerSide, fractionEmpty, moveThreshold } = params;
// simulation
AA.random.seed(seed);
const sim = new AA.Simulation({
width: squaresPerSide * 5,
height: squaresPerSide * 5,
gridStep: 5
});
invalidation.then(() => sim.end());
// initialise each square to land type 0, 1 or 2 (empty)
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);
}
// get unhappy
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);

// each tick, move unhappy to random empty
const rand = AA.random.int(nEmpty);
sim.beforeTick = () => {
for (let sq of AA.shuffle(unhappy())) {
[...sim.withLabel('land', 2)][rand()] // clunky - copying xset to array each step
.label('land', sq.label('land'));
sq.label('land', 2);
}
};
// vis
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,
});
}
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more