Solve the no connection puzzle: Difference between revisions

Content added Content deleted
m (→‎{{header|Haskell}}: Tidying, and pruned out one import.)
(→‎JS ES6: Updated primitives, tidied.)
Line 1,776: Line 1,776:
'use strict';
'use strict';


// GENERIC FUNCTIONS ------------------------------------------------------
// -------------- NO CONNECTION PUZZLE ---------------

// solvedPuzzle :: () -> [Int]
const solvedPuzzle = () => {

// universe :: [[Int]]
const universe = permutations(enumFromTo(1)(8));

// isSolution :: [Int] -> Bool
const isSolution = ([a, b, c, d, e, f, g, h]) =>
all(x => abs(x) > 1)([
a - d, c - d, g - d, e - d, a - c, c - g,
g - e, e - a, b - e, d - e, h - e, f - e,
b - d, d - h, h - f, f - b
]);

return universe[
until(i => isSolution(universe[i]))(
succ
)(0)
];
}

// ---------------------- TEST -----------------------
const main = () => {
const
firstSolution = solvedPuzzle(),
[a, b, c, d, e, f, g, h] = firstSolution;

return unlines(
zipWith(
a => n => a + ' = ' + n.toString()
)(enumFromTo('A')('H'))(firstSolution)
.concat([
[],
[a, b],
[c, d, e, f],
[g, h]
].map(
xs => unwords(xs.map(show))
.padStart(5, ' ')
))
);
}

// ---------------- GENERIC FUNCTIONS ----------------

// abs :: Num -> Num
const abs =
// Absolute value of a given number - without the sign.
Math.abs;


// abs :: Num a => a -> a
const abs = Math.abs;


// all :: (a -> Bool) -> [a] -> Bool
// all :: (a -> Bool) -> [a] -> Bool
const all = (f, xs) => xs.every(f);
const all = p =>
// True if p(x) holds for every x in xs.
xs => [...xs].every(p);


// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = (f, xs) => [].concat.apply([], xs.map(f));


// delete_ :: Eq a => a -> [a] -> [a]
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
const delete_ = (x, xs) =>
const compose = (...fs) =>
deleteBy((a, b) => a === b, x, xs);
// A function defined by the right-to-left
// composition of all the functions in fs.
fs.reduce(
(f, g) => x => f(g(x)),
x => x
);


// deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]
const deleteBy = (f, x, xs) =>
xs.length > 0 ? (
f(x, xs[0]) ? (
xs.slice(1)
) : [xs[0]].concat(deleteBy(f, x, xs.slice(1)))
) : [];


// enumFromTo :: Enum a => a -> a -> [a]
// enumFromTo :: Enum a => a -> a -> [a]
const enumFromTo = (m, n) => {
const enumFromTo = m => n => {
const [tm, tn] = [typeof m, typeof n];
const [x, y] = [m, n].map(fromEnum),
return tm !== tn ? undefined : (() => {
b = x + (isNaN(m) ? 0 : m - x);
const
return Array.from({
blnS = (tm === 'string'),
length: 1 + (y - x)
[base, end] = [m, n].map(blnS ? (s => s.codePointAt(0)) : id);
}, (_, i) => toEnum(m)(b + i));
return Array.from({
length: Math.floor(end - base) + 1
}, (_, i) => blnS ? String.fromCodePoint(base + i) : m + i);
})();
};
};


// id :: a -> a
const id = x => x;


// justifyRight :: Int -> Char -> Text -> Text
// fromEnum :: Enum a => a -> Int
const justifyRight = (n, cFiller, strText) =>
const fromEnum = x =>
n > strText.length ? (
typeof x !== 'string' ? (
(cFiller.repeat(n) + strText)
x.constructor === Object ? (
.slice(-n)
x.value
) : strText;
) : parseInt(Number(x))
) : x.codePointAt(0);


// justifyRight :: Int -> Char -> String -> String
const justifyRight = n =>
// The string s, preceded by enough padding (with
// the character c) to reach the string length n.
c => s => n > s.length ? (
s.padStart(n, c)
) : s;


// length :: [a] -> Int
const length = xs =>
// 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
'GeneratorFunction' !== xs.constructor
.constructor.name ? (
xs.length
) : Infinity;


// list :: StringOrArrayLike b => b -> [a]
const list = xs =>
// xs itself, if it is an Array,
// or an Array derived from xs.
Array.isArray(xs) ? (
xs
) : Array.from(xs || []);



// permutations :: [a] -> [[a]]
// permutations :: [a] -> [[a]]
const permutations = xs =>
const permutations = xs => (
xs.length ? concatMap(x => concatMap(ys => [
ys => ys.reduceRight(
[x].concat(ys)
(a, y) => a.flatMap(
],
ys => Array.from({
permutations(delete_(x, xs))), xs) : [
length: 1 + ys.length
[]
}, (_, i) => i)
.map(n => ys.slice(0, n)
];
.concat(y)
.concat(ys.slice(n))
)
), [
[]
]
)
)(list(xs));



// show :: a -> String
// show :: a -> String
const show = x => JSON.stringify(x);
const show = x =>
JSON.stringify(x);


// unlines :: [String] -> String
const unlines = xs => xs.join('\n');


// until :: (a -> Bool) -> (a -> a) -> a -> a
// succ :: Enum a => a -> a
const until = (p, f, x) => {
const succ = x =>
let v = x;
1 + x;
while (!p(v)) v = f(v);
return v;
};


// unwords :: [String] -> String
const unwords = xs => xs.join(' ');


// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
// take :: Int -> [a] -> [a]
const zipWith = (f, xs, ys) => {
// take :: Int -> String -> String
const ny = ys.length;
const take = n =>
return (xs.length <= ny ? xs : xs.slice(0, ny))
// The first n elements of a list,
.map((x, i) => f(x, ys[i]));
// string of characters, or stream.
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];
}));




// toEnum :: a -> Int -> a
// CONNECTION PUZZLE ------------------------------------------------------
const toEnum = e =>
// The first argument is a sample of the type
// allowing the function to make the right mapping
x => ({
'number': Number,
'string': String.fromCodePoint,
'boolean': Boolean,
'object': v => e.min + v
} [typeof e])(x);


// universe :: [[Int]]
const universe = permutations(enumFromTo(1, 8));


// isSolution :: [Int] -> Bool
// unlines :: [String] -> String
const isSolution = ([a, b, c, d, e, f, g, h]) =>
const unlines = xs =>
// A single string formed by the intercalation
all(x => abs(x) > 1, [a - d, c - d, g - d, e - d, a - c, c - g, g - e,
// of a list of strings with the newline character.
e - a, b - e, d - e, h - e, f - e, b - d, d - h, h - f, f - b
]);
xs.join('\n');


// firstSolution :: [Int]
const firstSolution = universe[until(
i => isSolution(universe[i]),
i => i + 1,
0
)];


// until :: (a -> Bool) -> (a -> a) -> a -> a
// TEST -------------------------------------------------------------------
const until = p =>
f => x => {
let v = x;
while (!p(v)) v = f(v);
return v;
};


// [Int]
const [a, b, c, d, e, f, g, h] = firstSolution;


// unwords :: [String] -> String
return unlines(
zipWith(
const unwords = xs =>
// A space-separated string derived
(a, n) => a + ' = ' + n.toString(),
enumFromTo('A', 'H'),
// from a list of words.
firstSolution
xs.join(' ');

)

.concat(
[
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
[],
const zipWith = f =>
[a, b],
// Use of `take` and `length` here allows
[c, d, e, f],
// zipping with non-finite lists
[g, h]
// i.e. generators like cycle, repeat, iterate.
].map(xs => justifyRight(5, ' ', unwords(xs.map(show))))
xs => ys => {
const n = Math.min(length(xs), length(ys));
)
return Infinity > n ? (
);
(([as, bs]) => Array.from({
length: n
}, (_, i) => f(as[i])(
bs[i]
)))([xs, ys].map(
compose(take(n), list)
))
) : zipWithGen(f)(xs)(ys);
};

return main();
})();</lang>
})();</lang>
{{Out}}
{{Out}}