explorata/src/modules/core.js

152 lines
4.6 KiB
JavaScript

// core functions to generate initial states and evolve them
import { Cell } from "./cell.js";
// get the next evolution of a 1D CA initial state
// buggy BUT produces interesting results
// function evolve1d(state, rules) {
// const sl = state.length - 1;
// return [
// rules[[state[sl - 1], state[sl], state[sl + 1]].join("")],
// ...state.map((_,x) => (rules[[state[x - 1], state[x], state[x + 1]].join("")])).slice(0, sl),
// rules[[state[0], state[1], state[2]].join("")]
// ]
// }
// get the next evolution of a 1D CA initial state
function evolve1d(state, rules) {
const sl = state.length - 1;
const edge1 = [state[sl - 2], state[sl - 1], state[sl]].join("");
const edge2 = [state[0], state[1], state[2]].join("");
// normal case (3 neighbor cells)
const center = state
.map((_, x) => rules[[state[x - 1], state[x], state[x + 1]].join("")])
.slice(1, sl);
return [rules[edge1], ...center, rules[edge2]];
}
// Get the next evolution of a cell according to
// Conway's game of life rules
function conwayRules(cell, neighbors) {
// loneliness rule
if (cell === 1 && neighbors < 2) return 0;
// overpopulation rule
if (cell === 1 && neighbors > 3) return 0;
// born when three live neighbors rule
if (cell === 0 && neighbors === 3) return 1;
// the cell remains the same if none apply
return cell;
}
// Get the next evolution of a cell according to
// Conway's game of life rules
function servietteRules(cell, neighbors) {
// loneliness rule
if (cell === 0 && [2, 3, 4].find((x) => x == neighbors)) return 1;
// the cell remains the same if none apply
return 0;
}
// variation of the game of life where a
// cell comes to live if 6 neigbor cells are alive
function highLifeRules(cell, neighbors) {
// loneliness rule
if (cell === 1 && neighbors < 2) return 0;
// overpopulation rule
if (cell === 1 && neighbors > 3) return 0;
// born when three live neighbors rule
if (cell === 0 && neighbors === 2) return 1;
// highlife rules
if ((cell === 0 && neighbors === 3) || neighbors === 6) return 1;
// the cell remains the same if none apply
return cell;
}
// variation on the game of life's rules,
// where the "three live neighbors" rule is ignored
function threebornRules(cell, neighbors) {
// loneliness rule
if (cell === 1 && neighbors < 2) return 0;
// overpopulation rule
if (cell === 1 && neighbors > 3) return 0;
// born when three live neighbors rule
return cell;
}
// variation on the game of life's rules,
// where the loneliness rule is ignored
function lonelinessRules(cell, neighbors) {
// overpopulation rule
if (cell === 1 && neighbors > 3) return 0;
// born when three live neighbors rule
if (cell === 0 && neighbors === 3) return 1;
// the cell remains the same if none apply
return cell;
}
// variation on the game of life's rules,
// where the overpopulation rule is ignored
function overpopulationRules(cell, neighbors) {
// loneliness rule
if (cell === 1 && neighbors < 2) return 0;
// born when three live neighbors rule
if (cell === 0 && neighbors === 3) return 1;
// the cell remains the same if none apply
return cell;
}
// get the next evolution of a 2D CA initial state
// Rules : Moore neighborhood
function evolve2d(grid, width, rulesFn) {
const bh = grid.length - 1;
const bw = width;
return grid.reduce((acc, cell, y) => {
const sum =
grid[Math.abs((y - 1) % bh)].state +
grid[Math.abs((y + 1) % bh)].state +
grid[Math.abs((y - bw - 1) % bh)].state +
grid[Math.abs((y - bw) % bh)].state +
grid[Math.abs((y - bw + 1) % bh)].state +
grid[Math.abs((y + bw - 1) % bh)].state +
grid[Math.abs((y + bw) % bh)].state +
grid[Math.abs((y + bw + 1) % bh)].state;
acc[y] = new Cell(rulesFn(cell.state, sum));
acc[y].prevState = cell.state;
return acc;
}, []);
}
// Populates the first state with a single living cell in the center
function create1dStateOneCell(width) {
return [...Array(width)].map((cell, index) => {
if (index === Math.floor(width / 2)) return 1;
return 0;
});
}
// Populates the first state of a 1D CA with cells returned
// by initFn
function create1dState(width, initFn, args) {
return [...Array(width)].map(() => initFn(...args));
}
// Populates the first state of a 2D CA with cells returned
// by initFn
function create2dState(width, height, initFn, args) {
return [...Array(height * width)].map(() => new Cell(initFn(...args)));
}
export {
create1dState,
create2dState,
create1dStateOneCell,
conwayRules,
overpopulationRules,
lonelinessRules,
threebornRules,
highLifeRules,
servietteRules,
evolve1d,
evolve2d,
};