xxxxxxxxxx
212
const EMPTY = -1;
const WATER = 0;
const SAND = 1;
const GRASS = 2;
const FOREST = 3;
const STONE = 4;
const opts = [
WATER,
SAND,
GRASS,
FOREST,
STONE
];
const rules = {};
rules[WATER] = [WATER, SAND];
rules[SAND] = [SAND, WATER, GRASS, STONE];
rules[GRASS] = [GRASS, SAND, FOREST, STONE];
rules[FOREST] = [FOREST, GRASS, STONE];
rules[STONE] = [SAND, FOREST, GRASS];
let colours = {};
const s = 10;
let tiles;
let wave;
let finished = false;
function setup() {
createCanvas(400, 400);
colours[EMPTY] = color(0);
colours[WATER] = color(0, 127, 255);
colours[SAND] = color(255, 255, 0);
colours[GRASS] = color(0, 255, 127);
colours[FOREST] = color(0, 255, 0);
colours[STONE] = color(127);
startWave();
}
function draw() {
if(!finished) {
let curr = smallestEntropy();
let opts = getOpts(curr.x, curr.y);
if(!opts.size) {
console.log("finished");
finished = true;
return;
}
let op = randomOp(opts);
setOpts(curr.x, curr.y, new Set(op));
setTile(curr.x, curr.y, op);
settle(curr.x, curr.y);
}
drawTiles();
}
function smallestEntropy() {
let smallest = Infinity;
let pos = createVector(-1, -1);
for(let j = 0; j < s; j ++) {
for(let i = 0; i < s; i ++) {
let o = getOpts(i, j);
if(o.size > 1 && o.size < smallest) {
smallest = o.size;
pos.x = i;
pos.y = j;
}
}
}
return pos;
}
function settle(i, j) {
let stack = [
createVector(i - 1, j),
createVector(i + 1, j),
createVector(i, j - 1),
createVector(i, j + 1)
];
while(stack.length) {
let curr = stack.pop();
let opts = getOpts(curr.x, curr.y);
if(opts.size > 1) {
nextOpts = optionsForNeighbours(curr.x, curr.y);
if(nextOpts.size != opts.size) {
if(nextOpts.size === 1) {
setTile(curr.x, curr.y, randomOp(nextOpts));
}
setOpts(curr.x, curr.y, nextOpts);
stack.push(createVector(curr.x - 1, curr.y));
stack.push(createVector(curr.x + 1, curr.y));
stack.push(createVector(curr.x, curr.y - 1));
stack.push(createVector(curr.x, curr.y + 1));
}
}
}
}
function randomOp(opts) {
Array.from(opts.entries())[int(random(opts.size))];
}
function getOpts(i, j) {
i = int(i);
j = int(j);
if(i < 0 || i >= s || j < 0 || j >= s) {
return new Set();
}
try {
return wave[j][i];
} catch(e) {
console.log(i, j, e);
return new Set();
}
}
function setOpts(i, j, opts) {
if(i < 0 || i > s || j < 0 || j > s) {
return;
}
wave[j][i] = opts;
}
function getTile(i, j) {
return tiles[j][i];
}
function setTile(i, j, t) {
tiles[j][i] = t;
}
function startWave() {
wave = [];
tiles = [];
for(let j = 0; j < s; j ++) {
let wr = [];
let tr = [];
for(let i = 0; i < s; i ++) {
wr.push(new Set(opts));
tr.push(EMPTY);
}
wave.push(wr);
tiles.push(tr);
}
}
function drawTiles() {
const ts = width/s;
for(let j = 0; j < s; j ++) {
for(let i = 0; i < s; i ++) {
let t = getTile(i, j);
let c = colours[t];
fill(c);
rect(i * ts, j * ts, ts, ts);
}
}
}
function optionsForSet(opts) {
let s = new Set();
let optsArr = Array.from(opts.entries());
for(let o of optsArr) {
let a = rules[o];
if(a) {
s = union(s, a);
}
}
return s;
}
function optionsForNeighbours(i, j) {
let s = new Set(opts);
s = intersection(s, optionsForSet(getOpts(i - 1, j)));
s = intersection(s, optionsForSet(getOpts(i + 1, j)));
s = intersection(s, optionsForSet(getOpts(i, j - 1)));
s = intersection(s, optionsForSet(getOpts(i, j + 1)));
return s;
}
function union(setA, setB) {
let _union = new Set(setA)
for (let elem of setB) {
_union.add(elem)
}
return _union
}
function intersection(setA, setB) {
let _intersection = new Set()
for (let elem of setB) {
if (setA.has(elem)) {
_intersection.add(elem)
}
}
return _intersection
}