I love this answer to that question, it's so creative and robust. I translated it to support 256 values without supporting null arrays, and the tree/array shape
generation seems to work. However, I am stuck on how the encoding radix-like function works, and how to translate that given that now POSSIBLE_SHAPE_LIST
is only 9 elements instead of 16 now. How do I get getPath
to appropriate put the path to the value in the tree structure, given the index? Here is the full code:
const POSSIBLE_SHAPE_LIST = [1, 2, 4, 8, 16, 32, 64, 128, 256]
const CODE_LIST = collect()
console.log(CODE_LIST.join('\n'))
console.log(getPath(28, 21))
function getPath(size, i) {
let code = CODE_LIST[size - 1]
let limit = POSSIBLE_SHAPE_LIST[code % POSSIBLE_SHAPE_LIST.length]
if (i < limit) {
return [i]
}
for (let sub = 1; sub < 6; sub++) {
i -= limit
code /= 9
limit = POSSIBLE_SHAPE_LIST[code % POSSIBLE_SHAPE_LIST.length]
if (i < limit) {
return [sub, i]
}
}
}
function collect() {
let codes = []
for (let n = 1; n <= 256; n++) {
let shapeNumbers = shape(n)
let code = encode(shapeNumbers)
codes.push(code)
}
return codes
}
function encode(shapeNumbers) {
let code = 0
for (let i = shapeNumbers.length - 1; i >= 0; i--) {
code = code * POSSIBLE_SHAPE_LIST.length + POSSIBLE_SHAPE_LIST.indexOf(shapeNumbers[i])
}
return code
}
/**
* Returns number of atomic entries,
* followed by data-size(s) of subarrays
*/
function shape(n) {
let p = greatestPowerOf2(n);
if (p >= n) {
// The only cases where there are no subarrays
return [n];
}
// Try with one subarray
for (let sub = 2; sub < n && sub <= 256; sub *= 2) {
let top = n - sub + 1;
p = greatestPowerOf2(top);
if (p >= top) {
return [p - 1, sub];
}
}
// Try with two subarrays
for (let sub1 = 2; sub1 < n && sub1 <= 256; sub1 *= 2) {
for (let sub2 = 2; sub2 <= sub1; sub2 *= 2) {
let top = n - sub1 - sub2 + 2;
if (top < 0) break;
p = greatestPowerOf2(top);
if (p >= top) {
return [p - 2, sub1, sub2];
}
}
}
// Try with three subarrays
for (let sub1 = 2; sub1 < n && sub1 <= 256; sub1 *= 2) {
for (let sub2 = 2; sub2 <= sub1; sub2 *= 2) {
for (let sub3 = 2; sub3 <= sub2; sub3 *= 2) {
let top = n - sub1 - sub2 - sub3 + 3;
if (top < 0) break;
p = greatestPowerOf2(top);
if (p >= top) {
return [p - 3, sub1, sub2, sub3];
}
}
}
}
// Try with four subarrays
for (let sub1 = 2; sub1 < n && sub1 <= 256; sub1 *= 2) {
for (let sub2 = 2; sub2 <= sub1; sub2 *= 2) {
for (let sub3 = 2; sub3 <= sub2; sub3 *= 2) {
for (let sub4 = 2; sub4 <= sub3; sub4 *= 2) {
let top = n - sub1 - sub2 - sub3 - sub4 + 4;
if (top < 0) break;
p = greatestPowerOf2(top);
if (p >= top) {
return [p - 4, sub1, sub2, sub3, sub4];
}
}
}
}
}
// Try with five subarrays
for (let sub1 = 2; sub1 < n && sub1 <= 256; sub1 *= 2) {
for (let sub2 = 2; sub2 <= sub1; sub2 *= 2) {
for (let sub3 = 2; sub3 <= sub2; sub3 *= 2) {
for (let sub4 = 2; sub4 <= sub3; sub4 *= 2) {
for (let sub5 = 2; sub5 <= sub4; sub5 *= 2) {
let top = n - sub1 - sub2 - sub3 - sub4 - sub5 + 5;
if (top < 0) break;
p = greatestPowerOf2(top);
if (p >= top) {
return [p - 5, sub1, sub2, sub3, sub4, sub5];
}
}
}
}
}
}
// Try with 6 subarrays
for (let sub1 = 2; sub1 < n && sub1 <= 256; sub1 *= 2) {
for (let sub2 = 2; sub2 <= sub1; sub2 *= 2) {
for (let sub3 = 2; sub3 <= sub2; sub3 *= 2) {
for (let sub4 = 2; sub4 <= sub3; sub4 *= 2) {
for (let sub5 = 2; sub5 <= sub4; sub5 *= 2) {
for (let sub6 = 2; sub6 <= sub5; sub6 *= 2) {
let top = n - sub1 - sub2 - sub3 - sub4 - sub5 - sub6 + 6;
if (top < 0) break;
p = greatestPowerOf2(top);
if (p >= top) {
return [p - 6, sub1, sub2, sub3, sub4, sub5, sub6];
}
}
}
}
}
}
}
// Try with 7 subarrays
for (let sub1 = 2; sub1 < n && sub1 <= 256; sub1 *= 2) {
for (let sub2 = 2; sub2 <= sub1; sub2 *= 2) {
for (let sub3 = 2; sub3 <= sub2; sub3 *= 2) {
for (let sub4 = 2; sub4 <= sub3; sub4 *= 2) {
for (let sub5 = 2; sub5 <= sub4; sub5 *= 2) {
for (let sub6 = 2; sub6 <= sub5; sub6 *= 2) {
for (let sub7 = 2; sub7 <= sub6; sub7 *= 2) {
let top = n - sub1 - sub2 - sub3 - sub4 - sub5 - sub6 - sub7 + 7;
if (top < 0) break;
p = greatestPowerOf2(top);
if (p >= top) {
return [p - 7, sub1, sub2, sub3, sub4, sub5, sub6, sub7];
}
}
}
}
}
}
}
}
throw new Error(n)
}
function greatestPowerOf2(n) {
return n >= 256 ? 256 : n >= 128 ? 128 : n >= 64 ? 64 : n >= 32 ? 32 : n >= 16 ? 16 : n >= 8 ? 8 : n >= 4 ? 4 : n >= 2 ? 2 : 1;
}
It should not log (at the end) [21]
, it should log something like [14, 1]
following the pattern laid out here. What am I doing wrong in the translation from the original answer?