Mind boggling card trick: Difference between revisions

Content added Content deleted
(→‎{{header|Haskell}}: (Some tidying of the threeStack function, refreshed sample output))
(→‎{{header|Javascript}}: Added a JS version)
Line 333: Line 333:
BBBBBB = Black cards in the black pile
BBBBBB = Black cards in the black pile
True</pre>
True</pre>

=={{header|Javascript}}==
{{trans|Haskell}}
<lang javascript>(() => {
'use strict';

const main = () => {
const
// DEALT
cards = enumFromTo(1, 52),
[rs_, bs_, discards] = threeStacks(
map(n =>
even(n) ? (
'R'
) : 'B', knuthShuffle(cards)
)
),

// SWAPPED
nSwap = randomRInt(1, min(rs_.length, bs_.length)),
bs = take(nSwap, rs_).concat(drop(nSwap, bs_)),
rs = take(nSwap, bs_).concat(drop(nSwap, rs_)),

// CHECKED
rrs = filter(c => 'R' === c, rs).join(''),
bbs = filter(c => 'B' === c, bs).join('');
return unlines([
'Discarded: ' + discards.join(''),
'Swapped: ' + nSwap,
'Red pile: ' + rs,
'Black pile: ' + bs,
rrs + ' = Red cards in the red pile',
bbs + ' = Black cards in the black pile',
(rrs.length === bbs.length).toString()
]);
};

// THREE STACKS ---------------------------------------

// threeStacks :: [Chars] -> ([Chars], [Chars], [Chars])
const threeStacks = cards => {
const go = ([rs, bs, ds], xs) => {
const lng = xs.length;
return 0 < lng ? (
1 < lng ? (() => {
const
rest = drop(2, xs),
[x, y] = take(2, xs);
return 'R' === x ? (
go([
cons(y, rs), bs, cons(x, ds)
], rest)
) : go([rs, cons(y, bs), cons(x, ds)], rest)
})() : [rs, bs, cons(xs[0], ds)]
) : [rs, bs, ds];
};
return go([
[],
[],
[]
], cards)
};

// SHUFFLE --------------------------------------------

// knuthShuffle :: [a] -> [a]
const knuthShuffle = xs =>
enumFromTo(0, xs.length - 1)
.reduceRight((a, i) => {
const iRand = randomRInt(0, i);
return i !== iRand ? (
swapped(i, iRand, a)
) : a;
}, xs);

// swapped :: Int -> Int -> [a] -> [a]
const swapped = (iFrom, iTo, xs) =>
xs.map(
(x, i) => iFrom !== i ? (
iTo !== i ? (
x
) : xs[iFrom]
) : xs[iTo]
);

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

// cons :: a -> [a] -> [a]
const cons = (x, xs) =>
Array.isArray(xs) ? (
[x].concat(xs)
) : (x + xs);

// drop :: Int -> [a] -> [a]
// drop :: Int -> String -> String
const drop = (n, xs) => xs.slice(n);

// enumFromTo :: Int -> Int -> [Int]
const enumFromTo = (m, n) =>
m <= n ? iterateUntil(
x => n <= x,
x => 1 + x,
m
) : [];

// even :: Int -> Bool
const even = n => 0 === n % 2;

// filter :: (a -> Bool) -> [a] -> [a]
const filter = (f, xs) => xs.filter(f);

// iterateUntil :: (a -> Bool) -> (a -> a) -> a -> [a]
const iterateUntil = (p, f, x) => {
const vs = [x];
let h = x;
while (!p(h))(h = f(h), vs.push(h));
return vs;
};

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

// min :: Ord a => a -> a -> a
const min = (a, b) => b < a ? b : a;

// randomRInt :: Int -> Int -> Int
const randomRInt = (low, high) =>
low + Math.floor(
(Math.random() * ((high - low) + 1))
);

// take :: Int -> [a] -> [a]
const take = (n, xs) => xs.slice(0, n);

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

// MAIN ---
return main();
})();</lang>
{{Out}}
<pre>Discarded: BRRRBBBRRRRBRRRRBRRRBBBBRR
Swapped: 5
Red pile: R,B,B,R,B,R,R,B,R,R,R,B,B,R,B,B
Black pile: B,B,B,B,B,R,B,B,R,B
RRRRRRRR = Red cards in the red pile
BBBBBBBB = Black cards in the black pile
true</pre>


=={{header|Kotlin}}==
=={{header|Kotlin}}==