Magic squares of doubly even order: Difference between revisions

Line 325:
 
Magic constant: 260</pre>
 
 
=={{header|JavaScript}}==
 
===ES6===
 
<lang JavaScript>(() => {
'use strict';
 
// doubleEvenMagicSquare :: Int -> [[Int]]
const doubleEvenMagicSquare = n => {
if (n % 4 > 0) return undefined;
 
// truthSeries :: Int -> [Int]
const truthSeries = n => {
if (n <= 1) return [true];
const xs = truthSeries(n - 1);
return xs.concat(xs.map(x => !x));
};
 
const sqr = n * n,
scale = curry(replicate)(n / 4),
power = Math.log2(sqr),
sequence = isInt(power) ? truthSeries(power + 1) : (
flatten(scale(splitEvery(4, truthSeries(5))
.map(scale)))
);
 
return splitEvery(n, sequence
.map((x, i) => x ? i + 1 : sqr - i));
};
 
 
// GENERIC FUNCTIONS ----------------------------------------------------
 
// flatten :: Tree a -> [a]
const flatten = t => (t instanceof Array ? concatMap(flatten, t) : [t]);
 
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = (f, xs) => [].concat.apply([], xs.map(f));
 
// splitEvery :: Int -> [a] -> [][a]]
const splitEvery = (n, xs) => {
if (xs.length <= n) return [xs];
const [h, t] = [xs.slice(0, n), xs.slice(n)];
return [h].concat(splitEvery(n, t));
}
 
// curry :: ((a, b) -> c) -> a -> b -> c
const curry = f => a => b => f(a, b);
 
// replicate :: Int -> a -> [a]
const replicate = (n, a) => {
let v = [a],
o = [];
if (n < 1) return o;
while (n > 1) {
if (n & 1) o = o.concat(v);
n >>= 1;
v = v.concat(v);
}
return o.concat(v);
};
 
// isInt :: Int -> Bool
const isInt = x => x === Math.floor(x);
 
 
// TEST AND DISPLAY FUNCTIONS -------------------------------------------
 
// transpose :: [[a]] -> [[a]]
const transpose = xs =>
xs[0].map((_, iCol) => xs.map((row) => row[iCol]));
 
// diagonals :: [[a]] -> ([a], [a])
const diagonals = xs => {
const nRows = xs.length,
nCols = (nRows > 0 ? xs[0].length : 0);
const cell = (x, y) => xs[y][x];
 
if (nRows === nCols) {
const ns = range(0, nCols - 1);
return [zipWith(cell, ns, ns), zipWith(cell, ns, reverse(ns))];
} else return [
[],
[]
];
};
 
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
const zipWith = (f, xs, ys) => {
const ny = ys.length;
return (xs.length <= ny ? xs : xs.slice(0, ny))
.map((x, i) => f(x, ys[i]));
}
 
// reverse :: [a] -> [a]
const reverse = (xs) => xs.slice(0)
.reverse()
 
// range :: Int -> Int -> [Int]
const range = (m, n) =>
Array.from({
length: Math.floor(n - m) + 1
}, (_, i) => m + i);
 
// all :: (a -> Bool) -> [a] -> Bool
const all = (f, xs) => xs.every(f);
 
// show :: a -> String
const show = x => JSON.stringify(x);
 
// justifyRight :: Int -> Char -> Text -> Text
const justifyRight = (n, cFiller, strText) =>
n > strText.length ? (
(cFiller.repeat(n) + strText)
.slice(-n)
) : strText;
 
// TEST -----------------------------------------------------------------
return [4, 8, 12]
.map(n => {
const lines = doubleEvenMagicSquare(n);
const sums = lines.concat(
transpose(lines)
.concat(diagonals(lines))
)
.map(xs => xs.reduce((a, b) => a + b, 0));
const sum = sums[0];
return [
"Order: " + n.toString(),
"Summing to: " + sum.toString(),
"Row, column and diagonal sums checked: " +
all(x => x === sum, sums)
.toString() + '\n',
lines.map(
xs => xs.map(
x => justifyRight(3, ' ', x.toString())
)
.join(' '))
.join('\n')
].join('\n')
})
.join('\n\n');
})();</lang>
 
{{Out}}
<pre>Order: 4
Summing to: 34
Row, column and diagonal sums checked: true
 
1 15 14 4
12 6 7 9
8 10 11 5
13 3 2 16
 
Order: 8
Summing to: 260
Row, column and diagonal sums checked: true
 
1 63 62 4 60 6 7 57
56 10 11 53 13 51 50 16
48 18 19 45 21 43 42 24
25 39 38 28 36 30 31 33
32 34 35 29 37 27 26 40
41 23 22 44 20 46 47 17
49 15 14 52 12 54 55 9
8 58 59 5 61 3 2 64
 
Order: 12
Summing to: 870
Row, column and diagonal sums checked: true
 
1 143 142 4 5 139 138 8 9 135 134 12
132 14 15 129 128 18 19 125 124 22 23 121
120 26 27 117 116 30 31 113 112 34 35 109
37 107 106 40 41 103 102 44 45 99 98 48
49 95 94 52 53 91 90 56 57 87 86 60
84 62 63 81 80 66 67 77 76 70 71 73
72 74 75 69 68 78 79 65 64 82 83 61
85 59 58 88 89 55 54 92 93 51 50 96
97 47 46 100 101 43 42 104 105 39 38 108
36 110 111 33 32 114 115 29 28 118 119 25
24 122 123 21 20 126 127 17 16 130 131 13
133 11 10 136 137 7 6 140 141 3 2 144</pre>
 
=={{header|PARI/GP}}==
9,659

edits