September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -0,0 +1,73 @@
(() => {
// magicSquare :: Int -> [[Int]]
const magicSquare = n =>
n % 2 !== 0 ? (
compose([transpose, cycled, transpose, cycled, enumSquare])(n)
) : [];
// Size of square -> rows containing integers [1..]
// enumSquare :: Int -> [[Int]]
const enumSquare = n =>
chunksOf(n, enumFromTo(1, n * n));
// Table of integers -> Table with rows rotated by descending deltas
// cycled :: [[Int]] -> [[Int]]
const cycled = rows => {
const d = Math.floor(rows.length / 2);
return zipWith(listCycle, enumFromTo(d, -d), rows)
};
// Number of positions to shift to right -> List -> Wrap-cycled list
// listCycle :: Int -> [a] -> [a]
const listCycle = (n, xs) => {
const d = -(n % xs.length);
return (d !== 0 ? xs.slice(d)
.concat(xs.slice(0, d)) : xs);
};
// GENERIC FUNCTIONS ------------------------------------------------------
// chunksOf :: Int -> [a] -> [[a]]
const chunksOf = (n, xs) =>
xs.reduce((a, _, i, xs) =>
i % n ? a : a.concat([xs.slice(i, i + n)]), []);
// compose :: [(a -> a)] -> (a -> a)
const compose = fs => x => fs.reduceRight((a, f) => f(a), x);
// enumFromTo :: Int -> Int -> Maybe Int -> [Int]
const enumFromTo = (m, n, step) => {
const d = (step || 1) * (n >= m ? 1 : -1);
return Array.from({
length: Math.floor((n - m) / d) + 1
}, (_, i) => m + (i * d));
};
// intercalate :: String -> [a] -> String
const intercalate = (s, xs) => xs.join(s);
// min :: Ord a => a -> a -> a
const min = (a, b) => b < a ? b : a;
// show :: a -> String
const show = JSON.stringify;
// transpose :: [[a]] -> [[a]]
const transpose = xs =>
xs[0].map((_, iCol) => xs.map(row => row[iCol]));
// unlines :: [String] -> String
const unlines = xs => xs.join('\n');
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
const zipWith = (f, xs, ys) =>
Array.from({
length: min(xs.length, ys.length)
}, (_, i) => f(xs[i], ys[i]));
// TEST -------------------------------------------------------------------
return intercalate('\n\n', [3, 5, 7]
.map(magicSquare)
.map(xs => unlines(xs.map(show))));
})();

View file

@ -0,0 +1,167 @@
(() => {
// Number of rows -> n rows of integers
// oddMagicTable :: Int -> [[Int]]
const oddMagicTable = n =>
mapAsTable(n, siamMap(quot(n, 2)));
// Highest index of square -> Siam xys so far -> xy -> next xy coordinate
// nextSiam :: Int -> M.Map (Int, Int) Int -> (Int, Int) -> (Int, Int)
const nextSiam = (uBound, sMap, [x, y]) => {
const [a, b] = [x + 1, y - 1];
return (a > uBound && b < 0) ? (
[uBound, 1] // Move down if obstructed by corner
) : a > uBound ? (
[0, b] // Wrap at right edge
) : b < 0 ? (
[a, uBound] // Wrap at upper edge
) : mapLookup(sMap, [a, b])
.nothing ? ( // Unimpeded default: one up one right
[a, b]
) : [a - 1, b + 2]; // Position occupied: move down
};
// Order of table -> Siamese indices keyed by coordinates
// siamMap :: Int -> M.Map (Int, Int) Int
const siamMap = n => {
const
uBound = 2 * n,
sPath = (uBound, sMap, xy, n) => {
const [x, y] = xy,
newMap = mapInsert(sMap, xy, n);
return (y == uBound && x == quot(uBound, 2) ? (
newMap
) : sPath(
uBound, newMap, nextSiam(uBound, newMap, [x, y]), n + 1));
};
return sPath(uBound, {}, [n, 0], 1);
};
// Size of square -> integers keyed by coordinates -> rows of integers
// mapAsTable :: Int -> M.Map (Int, Int) Int -> [[Int]]
const mapAsTable = (nCols, dct) => {
const axis = enumFromTo(0, nCols - 1);
return map(row => map(k => fromJust(mapLookup(dct, k)), row),
bind(axis, y => [bind(axis, x => [
[x, y]
])]));
};
// GENERIC FUNCTIONS ------------------------------------------------------
// bind :: [a] -> (a -> [b]) -> [b]
const bind = (xs, f) => [].concat.apply([], xs.map(f));
// curry :: Function -> Function
const curry = (f, ...args) => {
const go = xs => xs.length >= f.length ? (f.apply(null, xs)) :
function () {
return go(xs.concat(Array.from(arguments)));
};
return go([].slice.call(args, 1));
};
// enumFromTo :: Int -> Int -> [Int]
const enumFromTo = (m, n) =>
Array.from({
length: Math.floor(n - m) + 1
}, (_, i) => m + i);
// fromJust :: M a -> a
const fromJust = m => m.nothing ? {} : m.just;
// fst :: [a, b] -> a
const fst = pair => pair.length === 2 ? pair[0] : undefined;
// intercalate :: String -> [a] -> String
const intercalate = (s, xs) => xs.join(s);
// justifyRight :: Int -> Char -> Text -> Text
const justifyRight = (n, cFiller, strText) =>
n > strText.length ? (
(cFiller.repeat(n) + strText)
.slice(-n)
) : strText;
// length :: [a] -> Int
const length = xs => xs.length;
// log :: a -> IO ()
const log = (...args) =>
console.log(
args
.map(show)
.join(' -> ')
);
// map :: (a -> b) -> [a] -> [b]
const map = (f, xs) => xs.map(f);
// mapInsert :: Dictionary -> k -> v -> Dictionary
const mapInsert = (dct, k, v) =>
(dct[(typeof k === 'string' && k) || show(k)] = v, dct);
// mapKeys :: Map k a -> [k]
const mapKeys = dct =>
sortBy(mappendComparing([snd, fst]),
map(JSON.parse, Object.keys(dct)));
// mapLookup :: Dictionary -> k -> Maybe v
const mapLookup = (dct, k) => {
const
v = dct[(typeof k === 'string' && k) || show(k)],
blnJust = (typeof v !== 'undefined');
return {
nothing: !blnJust,
just: v
};
};
// mappendComparing :: [(a -> b)] -> (a -> a -> Ordering)
const mappendComparing = fs => (x, y) =>
fs.reduce((ord, f) => {
if (ord !== 0) return ord;
const
a = f(x),
b = f(y);
return a < b ? -1 : a > b ? 1 : 0
}, 0);
// maximum :: [a] -> a
const maximum = xs =>
xs.reduce((a, x) => (x > a || a === undefined ? x : a), undefined);
// Integral a => a -> a -> a
const quot = (n, m) => Math.floor(n / m);
// show :: a -> String
const show = x => JSON.stringify(x);
//
// snd :: (a, b) -> b
const snd = tpl => Array.isArray(tpl) ? tpl[1] : undefined;
//
// sortBy :: (a -> a -> Ordering) -> [a] -> [a]
const sortBy = (f, xs) => xs.slice()
.sort(f);
// table :: String -> [[String]] -> [String]
const table = (delim, rows) =>
map(curry(intercalate)(delim),
transpose(map(col =>
map(curry(justifyRight)(maximum(map(length, col)))(' '), col),
transpose(rows))));
// transpose :: [[a]] -> [[a]]
const transpose = xs =>
xs[0].map((_, col) => xs.map(row => row[col]));
// unlines :: [String] -> String
const unlines = xs => xs.join('\n');
// TEST -------------------------------------------------------------------
return intercalate('\n\n',
bind([3, 5, 7],
n => unlines(table(" ",
map(xs => map(show, xs), oddMagicTable(n))))));
})();