refactor fieldStream, handles oscillators
This commit is contained in:
parent
9c52a320eb
commit
32762e6ca8
3 changed files with 180 additions and 30 deletions
|
@ -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) => {
|
||||||
|
|
|
@ -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));
|
||||||
|
// generate seed for next Stream with liveNeighbors
|
||||||
|
const mapWithLiveNeighbors = Object.entries(this.map)
|
||||||
|
.map(makeSeed)
|
||||||
|
.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 });
|
||||||
}
|
}
|
||||||
this.tail = function () {
|
);
|
||||||
// call .next on all Cells on second next call
|
|
||||||
};
|
|
||||||
return this;
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 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({}));
|
||||||
|
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue