refactor fieldStream, handles oscillators

This commit is contained in:
Sorrel Bri 2020-05-24 15:54:41 -07:00
parent 9c52a320eb
commit 32762e6ca8
3 changed files with 180 additions and 30 deletions

View file

@ -40,6 +40,9 @@ class CellStream extends Stream {
addLiveNeighbor() { addLiveNeighbor() {
this.head.addLiveNeighbor(); this.head.addLiveNeighbor();
} }
setLiving() {
this.head.setLiving();
}
} }
const cellStream = (living = false, liveNeighbors = 0) => { const cellStream = (living = false, liveNeighbors = 0) => {

View file

@ -12,9 +12,10 @@ class GameField {
} }
}) })
); );
for (let key in fieldMap) { Object.entries(fieldMap).forEach(
this.map[key] = cellStream(true, 0); ([key, [live, neighbors]]) =>
} (this.map[key] = cellStream(live, neighbors))
);
// instead of implementing multiple GameFields, clear irrelevant keys and expand Game Field as needed // instead of implementing multiple GameFields, clear irrelevant keys and expand Game Field as needed
// discrete Field expansion should only happen in View (to keep view fields centered) // discrete Field expansion should only happen in View (to keep view fields centered)
} }
@ -35,19 +36,43 @@ class FieldStream extends Stream {
} }
} }
const seedMap = (map, [key, seed]) => {
map[key] = seed;
return map;
};
const isLiving = ([key, cell]) => cell.living === true;
const incrementLiveNeighbors = (field) => ([key]) =>
getNeighbors(key).forEach((neighbor) => field.addLiveNeighbor(neighbor));
const makeSeed = ([key, cell]) => [key, [cell.living, cell.liveNeighbors]];
const makeSeedNextGen = ([key, cell]) => {
cell.setLiving();
return [key, [cell.living, 0]];
};
const fieldStream = ({ fieldArray, fieldMap }) => { const fieldStream = ({ fieldArray, fieldMap }) => {
return new FieldStream(new GameField({ fieldArray, fieldMap }), function () { return new FieldStream(new GameField({ fieldArray, fieldMap }), function () {
// calculate liveNeighbors for all cells on first next call // calculate liveNeighbors for all cells on first next call
for (const key in this.map) { Object.entries(this.map)
getNeighbors(key).forEach((neighbor) => this.addLiveNeighbor(neighbor)); .filter(isLiving)
} .forEach(incrementLiveNeighbors(this));
this.tail = function () { // generate seed for next Stream with liveNeighbors
// call .next on all Cells on second next call const mapWithLiveNeighbors = Object.entries(this.map)
}; .map(makeSeed)
return this; .reduce(seedMap, {});
// return next stream
return new FieldStream(
new GameField({ fieldMap: mapWithLiveNeighbors }),
function () {
// determine living cells for next generation
const nextGeneration = Object.entries(this.map)
.map(makeSeedNextGen)
.reduce(seedMap, {});
// seed next Stream
return fieldStream({ fieldMap: nextGeneration });
}
);
}); });
}; };
// as a stream -> fieldStream => Stream(GameField, () => Stream(fieldStream.computeNeighbors(), () => Stream(fieldStream.setLiving()))
// instantiate table (orientation of major and minor axis dependent on viewport) // instantiate table (orientation of major and minor axis dependent on viewport)
// const gameFields = new Array(1).fill(new GameField({})); // const gameFields = new Array(1).fill(new GameField({}));

View file

@ -7,9 +7,9 @@ describe("Game Field seeds living Cells with array", () => {
]; ];
const fieldMap = { const fieldMap = {
"0,0": true, "0,0": [true, 0],
"0,2": true, "0,2": [true, 0],
"1,1": true, "1,1": [true, 0],
}; };
const gameArraySeed = new GameField({ fieldArray }); const gameArraySeed = new GameField({ fieldArray });
const gameMapSeed = new GameField({ fieldMap }); const gameMapSeed = new GameField({ fieldMap });
@ -85,13 +85,13 @@ describe("fieldStream.next calculates liveNeighbors", () => {
}); });
const fieldMap = { const fieldMap = {
"0,1": true, "0,1": [true, 0],
"0,2": true, "0,2": [true, 0],
"1,0": true, "1,0": [true, 0],
"1,1": true, "1,1": [true, 0],
"1,3": true, "1,3": [true, 0],
"2,1": true, "2,1": [true, 0],
"2,2": true, "2,2": [true, 0],
}; };
const testStream2 = fieldStream({ fieldMap }); const testStream2 = fieldStream({ fieldMap });
[ [
@ -128,27 +128,149 @@ describe("fieldStream.next calculates liveNeighbors", () => {
}); });
}); });
describe.skip("fieldStream.next tests still lifes", () => { describe("fieldStream.next tests still lifes", () => {
const blockArray = [ const blockArray = [
[1, 1], [1, 1],
[1, 1], [1, 1],
]; ];
streamBlock = fieldStream({ fieldArray: blockArray }); const streamBlock = fieldStream({ fieldArray: blockArray });
["0,0", "0,1", "1,0", "1,1"].forEach((key) => {}); [
["-1,-1", false],
["-1,0", false],
["-1,1", false],
["-1,2", false],
["0,-1", false],
["0,0", true],
["0,1", true],
["0,2", false],
["1,-1", false],
["1,0", true],
["1,1", true],
["1,2", false],
["2,-1", false],
["2,0", false],
["2,1", false],
["2,2", false],
].forEach(([key, live]) => {
test(`after one generation of Block, ${key} alive: ${live}`, () => {
expect(streamBlock.next.next.map[key].living).toEqual(live);
});
});
const beehiveMap = { const beehiveMap = {
"0,1": true, "0,1": [true, 0],
"0,2": true, "0,2": [true, 0],
"1,0": true, "1,0": [true, 0],
"1,3": true, "1,3": [true, 0],
"2,1": true, "2,1": [true, 0],
"2,2": true, "2,2": [true, 0],
}; };
const streamBeehive = fieldStream({ fieldMap: beehiveMap });
[
["-1,0", false],
["-1,1", false],
["-1,2", false],
["-1,3", false],
["0,-1", false],
["0,0", false],
["0,1", true],
["0,2", true],
["0,3", false],
["0,4", false],
["1,-1", false],
["1,0", true],
["1,1", false],
["1,2", false],
["1,3", true],
["1,4", false],
["2,-1", false],
["2,0", false],
["2,1", true],
["2,2", true],
["2,3", false],
["2,4", false],
["3,0", false],
["3,1", false],
["3,2", false],
["3,3", false],
].forEach(([key, live]) => {
test(`after one generation of Beehive, ${key} alive: ${live}`, () => {
expect(streamBeehive.next.next.map[key].living).toEqual(live);
});
});
const boatArray = [ const boatArray = [
[1, 1, 0], [1, 1, 0],
[1, 0, 1], [1, 0, 1],
[0, 1, 0], [0, 1, 0],
]; ];
const streamBoat = fieldStream({ fieldArray: boatArray });
[
["-1,-1", false],
["-1,0", false],
["-1,1", false],
["-1,2", false],
["0,-1", false],
["0,0", true],
["0,1", true],
["0,2", false],
["1,-1", false],
["1,0", true],
["1,1", false],
["1,2", true],
["1,3", false],
["2,-1", false],
["2,0", false],
["2,1", true],
["2,2", false],
["2,3", false],
["3,0", false],
["3,1", false],
["3,2", false],
].forEach(([key, live]) => {
test(`after one generation of Beehive, ${key} alive: ${live}`, () => {
expect(streamBoat.next.next.map[key].living).toEqual(live);
});
});
});
describe("fieldStream.next tests oscillators", () => {
const blinkerArray = [
[0, 1, 0],
[0, 1, 0],
[0, 1, 0],
];
const streamBlinker = fieldStream({ fieldArray: blinkerArray });
[
["0,0", false],
["0,1", false],
["0,2", false],
["1,0", true],
["1,1", true],
["1,2", true],
["2,0", false],
["2,1", false],
["2,2", false],
].forEach(([key, live]) => {
test(`after one generation of blinker, ${key} alive: ${live}`, () => {
expect(streamBlinker.next.next.map[key].living).toEqual(live);
});
});
[
["0,0", false],
["0,1", true],
["0,2", false],
["1,0", false],
["1,1", true],
["1,2", false],
["2,0", false],
["2,1", true],
["2,2", false],
].forEach(([key, live]) => {
test(`after two generations of blinker, ${key} alive: ${live}`, () => {
console.log(streamBlinker.next.next.map);
expect(streamBlinker.next.next.next.next.map[key].living).toEqual(live);
});
});
}); });