125 lines
3.3 KiB
JavaScript
125 lines
3.3 KiB
JavaScript
(() => {
|
|
'use strict';
|
|
|
|
// main :: IO ()
|
|
const main = () =>
|
|
// 10 random heroes drawn from
|
|
// a non-finite series.
|
|
unlines(map(
|
|
xs => show(sum(xs)) +
|
|
' -> [' + show(xs) + ']',
|
|
|
|
take(10, heroes(
|
|
seventyFivePlusWithTwo15s
|
|
))
|
|
));
|
|
|
|
// seventyFivePlusWithTwo15s :: [Int] -> Bool
|
|
const seventyFivePlusWithTwo15s = xs =>
|
|
// Total score over 75,
|
|
// with two or more qualities scoring 15.
|
|
75 < sum(xs) && 1 < length(filter(
|
|
x => 15 === x, xs
|
|
));
|
|
|
|
// heroes :: Gen IO [(Int, Int, Int, Int, Int, Int)]
|
|
function* heroes(p) {
|
|
// Non-finite list of heroes matching
|
|
// the requirements of predicate p.
|
|
while (true) {
|
|
yield hero(p)
|
|
}
|
|
}
|
|
|
|
// hero :: (Int -> Bool) -> IO (Int, Int, Int, Int, Int, Int)
|
|
const hero = p =>
|
|
// A random character matching the
|
|
// requirements of predicate p.
|
|
until(p, character, []);
|
|
|
|
// character :: () -> IO [Int]
|
|
const character = () =>
|
|
// A random character with six
|
|
// integral attributes.
|
|
map(() => sum(tail(sort(map(
|
|
randomRInt(1, 6),
|
|
enumFromTo(1, 4)
|
|
)))),
|
|
enumFromTo(1, 6)
|
|
);
|
|
|
|
|
|
// GENERIC FUNCTIONS ----------------------------------
|
|
|
|
// enumFromTo :: (Int, Int) -> [Int]
|
|
const enumFromTo = (m, n) =>
|
|
Array.from({
|
|
length: 1 + n - m
|
|
}, (_, i) => m + i);
|
|
|
|
// filter :: (a -> Bool) -> [a] -> [a]
|
|
const filter = (f, xs) => xs.filter(f);
|
|
|
|
// Returns Infinity over objects without finite length.
|
|
// This enables zip and zipWith to choose the shorter
|
|
// argument when one is non-finite, like cycle, repeat etc
|
|
|
|
// length :: [a] -> Int
|
|
const length = xs =>
|
|
(Array.isArray(xs) || 'string' === typeof xs) ? (
|
|
xs.length
|
|
) : Infinity;
|
|
|
|
// map :: (a -> b) -> [a] -> [b]
|
|
const map = (f, xs) =>
|
|
(Array.isArray(xs) ? (
|
|
xs
|
|
) : xs.split('')).map(f);
|
|
|
|
// e.g. map(randomRInt(1, 10), enumFromTo(1, 20))
|
|
|
|
// randomRInt :: Int -> Int -> IO () -> Int
|
|
const randomRInt = (low, high) => () =>
|
|
low + Math.floor(
|
|
(Math.random() * ((high - low) + 1))
|
|
);
|
|
|
|
// show :: a -> String
|
|
const show = x => x.toString()
|
|
|
|
// sort :: Ord a => [a] -> [a]
|
|
const sort = xs => xs.slice()
|
|
.sort((a, b) => a < b ? -1 : (a > b ? 1 : 0));
|
|
|
|
// sum :: [Num] -> Num
|
|
const sum = xs => xs.reduce((a, x) => a + x, 0);
|
|
|
|
// tail :: [a] -> [a]
|
|
const tail = xs => 0 < xs.length ? xs.slice(1) : [];
|
|
|
|
// take :: Int -> [a] -> [a]
|
|
// take :: Int -> String -> String
|
|
const take = (n, xs) =>
|
|
'GeneratorFunction' !== xs.constructor.constructor.name ? (
|
|
xs.slice(0, n)
|
|
) : [].concat.apply([], Array.from({
|
|
length: n
|
|
}, () => {
|
|
const x = xs.next();
|
|
return x.done ? [] : [x.value];
|
|
}));
|
|
|
|
// unlines :: [String] -> String
|
|
const unlines = xs => xs.join('\n');
|
|
|
|
// until :: (a -> Bool) -> (a -> a) -> a -> a
|
|
const until = (p, f, x) => {
|
|
let v = x;
|
|
while (!p(v)) v = f(v);
|
|
return v;
|
|
};
|
|
|
|
// MAIN ---
|
|
return main();
|
|
})();
|