61 lines
1.5 KiB
JavaScript
61 lines
1.5 KiB
JavaScript
(n => {
|
|
|
|
// diagonals :: n -> [[n]]
|
|
function diagonals(n) {
|
|
let diags = (xs, iCol, iRow) => {
|
|
if (iCol < xs.length) {
|
|
let xxs = splitAt(iCol, xs);
|
|
|
|
return [xxs[0]].concat(diags(
|
|
xxs[1],
|
|
iCol + (iRow < n ? 1 : -1),
|
|
iRow + 1
|
|
));
|
|
} else return [xs];
|
|
}
|
|
|
|
return diags(range(0, n * n - 1), 1, 1);
|
|
}
|
|
|
|
|
|
// Recursively read off n heads of diagonal lists
|
|
// rowsFromDiagonals :: n -> [[n]] -> [[n]]
|
|
function rowsFromDiagonals(n, lst) {
|
|
if (lst.length) {
|
|
let [edge, rest] = splitAt(n, lst);
|
|
|
|
return [edge.map(x => x[0])]
|
|
.concat(rowsFromDiagonals(n,
|
|
edge.filter(x => x.length > 1)
|
|
.map(x => x.slice(1))
|
|
.concat(rest)
|
|
));
|
|
} else return [];
|
|
}
|
|
|
|
// GENERIC FUNCTIONS
|
|
|
|
// splitAt :: Int -> [a] -> ([a],[a])
|
|
function splitAt(n, xs) {
|
|
return [xs.slice(0, n), xs.slice(n)];
|
|
}
|
|
|
|
// range :: From -> To -> Maybe Step -> [Int]
|
|
// range :: Int -> Int -> Maybe Int -> [Int]
|
|
function range(m, n, step) {
|
|
let d = (step || 1) * (n >= m ? 1 : -1);
|
|
|
|
return Array.from({
|
|
length: Math.floor((n - m) / d) + 1
|
|
}, (_, i) => m + (i * d));
|
|
}
|
|
|
|
// ZIG-ZAG MATRIX
|
|
|
|
return rowsFromDiagonals(n,
|
|
diagonals(n)
|
|
.map((x, i) => (i % 2 || x.reverse()) && x)
|
|
);
|
|
|
|
})(5);
|