Skip to content

Instantly share code, notes, and snippets.

@misterussell
Last active March 27, 2018 19:11
Show Gist options
  • Save misterussell/ab8aba1580f4bf86ddeb2c2d9f9a30ff to your computer and use it in GitHub Desktop.
Save misterussell/ab8aba1580f4bf86ddeb2c2d9f9a30ff to your computer and use it in GitHub Desktop.
Initial versioning for Game Of Life Metrics
// create array of objects to use in testing
function generateExamples() {
const genExample = [
[0, 0, 0, 0, 0],
[0, 1, 1, 0, 0],
[0, 0, 0, 1, 0],
[0, 1, 1, 1, 0],
[1, 0, 0, 0, 0]
];
const _pipe = (a, b) => (...args) => b(a(...args));
const pipe = (...fns) => fns.reduce(_pipe);
// let store = {};
// store.changes = {};
function getNextGeneration(cells, generations) {
const initiateSeed = pipe(generateGenState, generateNextGenState, setNextGenState);
const progressLife = pipe(generateNextGenState, setNextGenState)
const noCells = cells.length === 0 ? true : false;
const areSeedCells = Array.isArray(cells) === true ? true : false;
const live = generations > 0 ? true : false
return noCells
? []
: live
? areSeedCells
? getNextGeneration(initiateSeed(cells), generations - 1)
: getNextGeneration(progressLife(cells), generations - 1)
: cells
}
function generateGenState(rawCells) {
let genState = {};
let arrayPosition = 0;
rawCells.forEach((terrian, i, arr) => {
terrian.forEach((cell, p, arr2) => {
const toroidalLimits = [arr.length, arr2.length];
const cellState = cell;
const cellObj = createCell(i + 1, p + 1, cellState, toroidalLimits, arrayPosition);
arrayPosition += 1;
return genState[cellObj.cellHash] = cellObj;
});
});
return genState;
}
function generateNextGenState(gen) {
// for each Cell in our hashmap see if the value changes
for (let cell in gen) {
gen[cell] = getNextCellState(gen[cell], gen)
}
return gen;
}
function setNextGenState(gen) {
let newGen = {};
for (let cell in gen) {
newGen[cell] = changeCellState(gen[cell])
}
// because of the way this factory works, in order to be able to actively
// track the object changes without implementing some sort of timeout/promise setup we need to return a copy
// of our object at each change pass. I anticipate needing to store some sort of emit
return newGen;
}
function createCell(x, y, cellState, toroidalLimits, arrayPosition) {
// factory settings
const cellHash = (x * 15486047) + (y * 15487429);
// factory
const Cell = () => ({
x,
y,
cellHash,
cellState,
toroidalLimits,
arrayPosition
});
return Cell();
}
function getNextCellState(cell, genState) {
const lowLimit = cell.x === cell.toroidalLimits[0] ? 1 : cell.x + 1;
const highLimit = cell.x === 1 ? cell.toroidalLimits[0] : cell.x - 1;
const rightLimit = cell.y === cell.toroidalLimits[1] ? 1 : cell.y + 1;
const leftLimit = cell.y === 1 ? cell.toroidalLimits[1] : cell.y - 1;
const blockSum = [
[highLimit, leftLimit], [highLimit, cell.y], [highLimit, rightLimit],
[cell.x, leftLimit], [cell.x, cell.y], [cell.x, rightLimit],
[lowLimit, leftLimit], [lowLimit, cell.y], [lowLimit, rightLimit]
].map(xyPosition => {
return genState[(xyPosition[0] * 15486047) + (xyPosition[1] * 15487429)].cellState;
}).reduce((a, b) => a + b);
const sum3 = blockSum === 3 ? true : false;
const sum4 = blockSum === 4 ? true : false;
const nextState = sum3 ? 1 : sum4 ? cell.cellState : 0;
// if (cell.cellState !== nextState) {
// Store.changes[cell.arrayPosition] = nextState;
// }
return { ...cell, nextState };
}
function changeCellState(cell) {
const nextState = cell.nextState;
const cellState = nextState;
// this is what will need to change the visuals if I put this on screen
return { ...cell, cellState, nextState: null}
}
function createCellArray(length) {
let cells = [];
for (var i = 0; i < length; i++) {
cells.push(0);
}
return cells;
}
function createHashableArray(cells, totalBound) {
let hashableArray = [];
for (let i = 0; i < totalBound * totalBound; i += totalBound) {
hashableArray.push(cells.slice(i, i + totalBound));
}
return hashableArray;
}
let generations = [];
let genState = generateGenState(genExample);
let nextGenState = generateNextGenState(genState);
generations.push(nextGenState)
for (var i = 0; i < 14; i++) {
generations.push(setNextGenState(generateNextGenState(generations[i])));
}
return generations;
}
// this function is rather long for doing something simple.
function getSustainedPeriods(arr) {
let life = [];
let lifeCount = 0;
let death = [];
let deathCount = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] === 1) {
life[lifeCount] === undefined ? life[lifeCount] = [1] : life[lifeCount] = [...life[lifeCount], 1];
} else lifeCount += 1;
if (arr[i] === 0 ) {
death[deathCount] === undefined ? death[deathCount] = [1] : death[deathCount] = [...death[deathCount], 1];
} else deathCount += 1;
}
// remove empty values
life = life.filter(n => true)
.map(subArr => {
return subArr.reduce((a, b) => a + b);
});
death = death.filter(n => true)
.map(subArr => {
return subArr.reduce((a, b) => a + b);
});
return { life, death };
}
// generate the test cases
let tests = generateExamples();
// create an object to store all cell information
let cellTracking = {};
let lifeBoardTracking = {
generationLifeSums: [],
generationDeathSums: []
}
// generate stats for each cell and the complete cellTracking of the game
// it may be useful to seperate out these two sets of stats
// minimize the lines here. things can get broken out into more distinct functions
tests.forEach((obj, i, arr) => {
lifeBoardTracking.generationLifeSums[i] === undefined ? lifeBoardTracking.generationLifeSums.push(0) : null;
lifeBoardTracking.generationDeathSums[i] === undefined ? lifeBoardTracking.generationDeathSums.push(0) : null;
Object.keys(obj).forEach((key, p, keys) => {
let cellHistory;
let cellState = obj[key].cellState;
let nextState = obj[key].nextState;
let cellStateSum;
let count;
let births;
let deaths;
let sustainedPeriods;
lifeBoardTracking.generationLifeSums = [...lifeBoardTracking.generationLifeSums];
if (cellTracking[key] === undefined) {
// initiate the history of the cells life
cellHistory = [cellState];
// define defaults if case is new
cellStateSum = cellState;
count = 1;
births = cellState === 0 && nextState === 1 ? 1 : 0;
deaths = cellState === 1 && nextState === 0 ? 1 : 0;
} else {
// keep track of each life of the cell for comparative purposes
cellHistory = [...cellTracking[key].cellHistory, cellState];
// number of births
births = cellTracking[key].births;
// number of death
deaths = cellTracking[key].deaths;
// find total life value of a cell over progression
cellStateSum = cellTracking[key].cellStateSum + cellState;
// find the total number of lifecycles
// this int can be moved onto state during implementation
count = cellTracking[key].count + 1;
// find the total number of births
if (cellState === 0 && nextState === 1 || p === 0 && cellState === 1) {
births += 1;
}
// find the total number of deaths
if (cellState === 1 && nextState === 0) {
deaths += 1;
}
};
// find the total life for each generation
// this can be moved onto state during implementation
if (cellState === 1) {
lifeBoardTracking.generationLifeSums[i] += 1;
}
if (cellState === 0) {
lifeBoardTracking.generationDeathSums[i] += 1;
}
return cellTracking[key] = {
cellHistory,
cellStateSum,
count,
averageLife: cellStateSum/count,
births,
deaths
};
});
});
console.log(tests);
// console.log(generationLifeSums);
// console.log(generationDeathSums);
Object.keys(cellTracking).forEach((key, i, arr) => {
return cellTracking[key].sustainedPeriods = getSustainedPeriods(cellTracking[key].cellHistory);
});
console.log(cellTracking);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment