diff --git a/src/lib/analyzeOscillator.test.ts b/src/lib/analyzeOscillator.test.ts index ad8dd92..3250adb 100644 --- a/src/lib/analyzeOscillator.test.ts +++ b/src/lib/analyzeOscillator.test.ts @@ -34,5 +34,20 @@ describe("analyzeOscillator", () => { [2, 1, 2], [0, 2, 0], ]); + + expect( + result.frequencyMap.data.slice(15, 18).map((row) => row.slice(31, 34)) + ).toEqual([ + [0, 1, 0], + [1, 2, 1], + [0, 1, 0], + ]); + expect( + result.heatMap.data.slice(15, 18).map((row) => row.slice(31, 34)) + ).toEqual([ + [-1, 2, -1], + [2, 0, 2], + [-1, 2, -1], + ]); }); }); diff --git a/src/lib/getMap.ts b/src/lib/getMap.ts index 2284d55..2d6ec99 100644 --- a/src/lib/getMap.ts +++ b/src/lib/getMap.ts @@ -55,34 +55,77 @@ export function getMap({ .map(() => -1) ); - const historiesArray = histories.map((h) => h.getArray()); + const firstBitGrid = histories[0]; + if (firstBitGrid === undefined) { + throw new Error("no history"); + } + const firstBitGridUint32Array = firstBitGrid.asInternalUint32Array(); + const orUint32Array = or.asInternalUint32Array(); - or.forEachAlive((x, y) => { - const states: (0 | 1)[] = []; - let heat = 0; - let prevCell = historiesArray[0]?.[y][x]; - for (const h of historiesArray) { - const cell = h[y][x]; - if (prevCell !== undefined && prevCell !== cell) { - heat++; - } - prevCell = cell; - states.push(cell); - if (cell !== 0) { - frequencyArray[y][x]++; - } + { + function getAlive(array: Uint32Array, offset: number, u: number): 0 | 1 { + const value = array[offset]!; + const alive = (value & (1 << (BITS_MINUS_1 - u))) !== 0 ? 1 : 0; + return alive; } - if ( - historiesArray.length !== 0 && - historiesArray[0][y][x] !== - historiesArray[historiesArray.length - 1][y][x] - ) { - heat++; + const width = firstBitGrid.getWidth32(); + const height = firstBitGrid.getHeight(); + const BITS = 32; + const BITS_MINUS_1 = BITS - 1; + for (let i = 0; i < height; i++) { + const rowIndex = i * width; + for (let j = 0; j < width; j++) { + const offset = rowIndex + j; + // skip if empty + if (orUint32Array[offset] === 0) { + continue; + } + const BITS_J = j * BITS; + for (let u = 0; u < BITS; u++) { + // skip if dead + if (getAlive(orUint32Array, offset, u) === 0) { + continue; + } + + const x = BITS_J + u; + const y = i; + + const states: (0 | 1)[] = []; + let heat = 0; + const firstCell = getAlive(firstBitGridUint32Array, offset, u); + let prevCell = firstCell; + let frequency = 0; + for (const h of histories) { + const array = h.asInternalUint32Array(); + const cell = getAlive(array, offset, u); + if (prevCell !== undefined && prevCell !== cell) { + heat++; + } + prevCell = cell; + states.push(cell); + if (cell !== 0) { + frequency++; + } + } + + if ( + firstCell !== + getAlive( + histories[histories.length - 1]!.asInternalUint32Array(), + offset, + u + ) + ) { + heat++; + } + heatArray[y][x] = heat; + periodArray[y][x] = findPeriod(states); + frequencyArray[y][x] = frequency; + } + } } - heatArray[y][x] = heat; - periodArray[y][x] = findPeriod(states); - }); + } const periodCountMap = getCountMap(periodArray); periodCountMap.delete(0); @@ -96,27 +139,22 @@ export function getMap({ return { periodMap: { data: periodArray, - list: mapUnique(periodArray).filter((x) => x !== 0), + list: [...periodCountMap.keys()].sort((a, b) => a - b), countMap: periodCountMap, }, frequencyMap: { data: frequencyArray, - list: mapUnique(frequencyArray).filter((x) => x !== 0), + list: [...frequencyCountMap.keys()].sort((a, b) => a - b), countMap: frequencyCountMap, }, heatMap: { data: heatArray, - list: mapUnique(heatArray).filter((x) => x !== -1), + list: [...heatCountMap.keys()].sort((a, b) => a - b), countMap: heatCountMap, }, }; } -function mapUnique(map: number[][]): number[] { - const set = new Set(map.flat()); - return [...set].sort((a, b) => a - b); -} - function getCountMap(map: number[][]): Map { const countMap = new Map(); for (const row of map) {