Last active
March 27, 2018 19:11
-
-
Save misterussell/ab8aba1580f4bf86ddeb2c2d9f9a30ff to your computer and use it in GitHub Desktop.
Initial versioning for Game Of Life Metrics
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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