Mind boggling card trick: Difference between revisions
m (→{{header|Factor}}: define an entry point for the script/vocab) |
(→{{header|REXX}}: added the REXX computer programming language.) |
||
Line 194: | Line 194: | ||
Swapping 2 |
Swapping 2 |
||
Yeha! The mathematicians assertion is correct.</pre> |
Yeha! The mathematicians assertion is correct.</pre> |
||
=={{header|REXX}}== |
|||
<lang rexx>/*REXX pgm mimics a boggling card trick; separates cards into 3 piles based on color ···*/ |
|||
parse arg trials # seed . /*obtain optional arguments from the CL*/ |
|||
if trials=='' | trials=="," then trials= 500 /*Not specified? Then use the default.*/ |
|||
if #=='' | #=="," then #= 52 /* " " " " " " */ |
|||
if datatype(seed, 'W') then call random ,,seed /*if integer, use this as a RANDOM seed*/ |
|||
ok=0 /*the number of "expected" good trials.*/ |
|||
do trials /*perform a number of trials to be safe*/ |
|||
call create /*odd numbers≡RED, even numbers≡BLACK.*/ |
|||
call shuffle /*shuffle the deck a number of times. */ |
|||
call deal /*put cards into three piles of cards. */ |
|||
call swap /*swap rand # of cards in R & B piles*/ |
|||
call count /*count #blacks in B, #reds in R piles*/ |
|||
end /*trials*/ /*#: is the number of cards in the deck*/ |
|||
pc= (100*ok/trials)'%' /*calculate the % asserted correctly.*/ |
|||
say "Correctness of the mathematician's assertion:" pc ' (out of' trials "trials)." |
|||
exit /*stick a fork in it, we're all done. */ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
?: return random(1, word( arg(1) #, 1) ) /*gen a random number from 1 ──► arg. */ |
|||
create: @.=; do j=1 for #; @.j= j; end /*j*/; return |
|||
isRed: return arg(1) // 2 /*if arg(1) is odd, the card is RED.*/ |
|||
shuffle: do j=1 for #; x=?(); y=?(); parse value @.x @.y with @.y @.x; end; return |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
count: Rn=0; Bn=0; do j=1 for words(R); Rn=Rn+ isRed(word(R,j)) ; end |
|||
do k=1 for words(B); Bn=Bn+ (\isRed(word(B,k))); end |
|||
if Rn==Bn then ok= ok+1; return /*Was it a good trial? Bump OK counter*/ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
deal: R=; B=; D=; do j=1 for #%2 by 2 /*deal all the cards. */ |
|||
next= j+1; card= @.next /*obtain the next card. */ |
|||
if isRed(@.j) then R=R card /*add to the RED pile?*/ |
|||
else B=B card /* " " " BLACK " */ |
|||
D= D @.j /* " " " discard " */ |
|||
end /*j*/ |
|||
return /*discard pile not used.*/ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
swap: $= ?( min( words(R), words(B) ) ); Rc=; Bc= /*ensure we can swap $ cards.*/ |
|||
do $ /*$: is the number of swaps.*/ |
|||
R?= ?( words(R) ) /*a random card in RED pile.*/ |
|||
B?= ?( words(B) ) /*" " " " BLACK " */ |
|||
/* "reds" to be swapped.*/ Rc= Rc word(R, R?); R= delword(R, R?, 1) /*del card*/ |
|||
/*"blacks" " " " */ Bc= Bc word(B, B?); B= delword(B, B?, 1) /* " " */ |
|||
end /*$*/ |
|||
R=R Bc; B=B Rc; return /*add swapped cards to piles.*/</lang> |
|||
{{out|output|text= when using the default inputs:}} |
|||
<pre> |
|||
Correctness of the mathematician's assertion: 100% (out of 500 trials). |
|||
</pre> |
|||
=={{header|zkl}}== |
=={{header|zkl}}== |
Revision as of 04:02, 26 August 2018
Matt Parker of the Stand Up Maths channel on you tube has a video of a card trick that creates a semblance of order from chaos.
The task is to simulate the trick in a way that mimicks the steps shown in the video.
- 1. Cards
- Create a
pack
of 52 cards, half red - half black. - Give the pack a good shuffle.
- 2. Deal from the randomised pack into three stacks
- Assemble the cards face down.
- Turn up the top card,
- if it is black then add the next card, unseen, to the
black-stack
. - If it is red then instead add that next card, unseen, to the
red-stack
.
- if it is black then add the next card, unseen, to the
- Add the card you turned over to see what colour it was above, to the
discard-stack
.
(You might optionally show these discard cards to give an idea of the randomness).
- Turn up the top card,
- Repeat the above for the whole of the assembled pack.
- 3. Swap the same, random, number of cards between the two stacks.
- Randomly choose the number of cards to swap.
- Randomly choose that number of cards out of each stack to swap.
(Without knowing those cards - they could be red or black cards from the stacks, we don't know).
- 4. Order from randomness?
- Check the mathematicians assertion that: The number of black cards in the black pile equals the number of red cards in the red pile.
Show output on this page.
Factor
<lang factor>USING: accessors combinators.extras formatting fry generalizations io kernel math math.ranges random sequences sequences.extras ; IN: rosetta-code.mind-boggling-card-trick
SYMBOLS: R B ;
TUPLE: piles deck red black discard ;
- initialize-deck ( -- seq )
[ R ] [ B ] [ '[ 26 _ V{ } replicate-as ] call ] bi@ append randomize ;
- <piles> ( -- piles )
initialize-deck [ V{ } clone ] thrice piles boa ;
- deal-step ( piles -- piles' )
dup [ deck>> pop dup ] [ discard>> push ] [ deck>> pop ] tri B = [ over black>> ] [ over red>> ] if push ;
- deal ( piles -- piles' ) 26 [ deal-step ] times ;
- choose-sample-size ( piles -- n )
[ red>> ] [ black>> ] bi shorter length [0,b] random ;
! Partition a sequence into n random samples in one sequence and ! the leftovers in another.
- sample-partition ( vec n -- leftovers sample )
[ 3 dupn ] dip sample dup [ [ swap remove-first! drop ] with each ] dip ;
- perform-swaps ( piles -- piles' )
dup dup choose-sample-size dup "Swapping %d\n" printf [ [ red>> ] dip ] [ [ black>> ] dip ] 2bi [ sample-partition ] 2bi@ [ append ] dip rot append [ >>black ] dip >>red ;
- test-assertion ( piles -- )
[ red>> ] [ black>> ] bi [ [ R = ] count ] [ [ B = ] count ] bi* 2dup = [ "Assertion correct!" ] [ "Assertion incorrect!" ] if print "R in red: %d\nB in black: %d\n" printf ;
- main ( -- )
<piles> ! step 1 deal ! step 2 dup "Post-deal state:\n%u\n" printf perform-swaps ! step 3 dup "Post-swap state:\n%u\n" printf test-assertion ; ! step 4
MAIN: main</lang> A run:
- Output:
Post-deal state: T{ piles { deck V{ } } { red V{ B R B R R B B R R R R } } { black V{ R B R B B R B B R R R R R B B } } { discard V{ R B R B R B B B R R R B B B R B R R R R R R B R B R } } } Swapping 11 Post-swap state: T{ piles { deck V{ } } { red V{ B R B B R R B R R R R } } { black V{ B R R B B R B R R R R B R B B } } { discard V{ R B R B R B B B R R R B B B R B R R R R R R B R B R } } } Assertion correct! R in red: 7 B in black: 7
Another run:
- Output:
Post-deal state: T{ piles { deck V{ } } { red V{ R R R B B R B R R B } } { black V{ B R B B R B R B R R R R R R B R } } { discard V{ R R B R B B R B B R B R R B B R R R R R R R B R R B } } } Swapping 7 Post-swap state: T{ piles { deck V{ } } { red V{ B R R R B R B B R B } } { black V{ R R B R R B R B B R R R R R B R } } { discard V{ R R B R B B R B B R B R R B B R R R R R R R B R R B } } } Assertion correct! R in red: 5 B in black: 5
Python
The code is layed out to follow the task decription, leading to some deviations from the PEP8 guidelines <lang python>import random
- 1. Cards
n = 52 Black, Red = 'Black', 'Red' blacks = [Black] * (n // 2) reds = [Red] * (n // 2) pack = blacks + reds
- Give the pack a good shuffle.
random.shuffle(pack)
- 2. Deal from the randomised pack into three stacks
black_stack, red_stack, discard = [], [], [] while pack:
top = pack.pop() if top == Black: black_stack.append(pack.pop()) else: red_stack.append(pack.pop()) discard.append(top)
print('(Discards:', ' '.join(d[0] for d in discard), ')\n')
- 3. Swap the same, random, number of cards between the two stacks.
- We can't swap more than the number of cards in a stack.
max_swaps = min(len(black_stack), len(red_stack))
- Randomly choose the number of cards to swap.
swap_count = random.randint(0, max_swaps) print('Swapping', swap_count)
- Randomly choose that number of cards out of each stack to swap.
def random_partition(stack, count):
"Partition the stack into 'count' randomly selected members and the rest" sample = random.sample(stack, count) rest = stack[::] for card in sample: rest.remove(card) return rest, sample
black_stack, black_swap = random_partition(black_stack, swap_count) red_stack, red_swap = random_partition(red_stack, swap_count)
- Perform the swap.
black_stack += red_swap red_stack += black_swap
- 4. Order from randomness?
if black_stack.count(Black) == red_stack.count(Red):
print('Yeha! The mathematicians assertion is correct.')
else:
print('Whoops - The mathematicians (or my card manipulations) are flakey')</lang>
A run.
- Output:
(Discards: R B R R B B R R R B B B B R R R B R R B B B B R B R ) Swapping 11 Yeha! The mathematicians assertion is correct.
A second run:
- Output:
(Discards: R B B R B B R B R R R B R R B B B B R R B R R B B R ) Swapping 2 Yeha! The mathematicians assertion is correct.
REXX
<lang rexx>/*REXX pgm mimics a boggling card trick; separates cards into 3 piles based on color ···*/ parse arg trials # seed . /*obtain optional arguments from the CL*/ if trials== | trials=="," then trials= 500 /*Not specified? Then use the default.*/ if #== | #=="," then #= 52 /* " " " " " " */ if datatype(seed, 'W') then call random ,,seed /*if integer, use this as a RANDOM seed*/ ok=0 /*the number of "expected" good trials.*/
do trials /*perform a number of trials to be safe*/ call create /*odd numbers≡RED, even numbers≡BLACK.*/ call shuffle /*shuffle the deck a number of times. */ call deal /*put cards into three piles of cards. */ call swap /*swap rand # of cards in R & B piles*/ call count /*count #blacks in B, #reds in R piles*/ end /*trials*/ /*#: is the number of cards in the deck*/
pc= (100*ok/trials)'%' /*calculate the % asserted correctly.*/ say "Correctness of the mathematician's assertion:" pc ' (out of' trials "trials)." exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ ?: return random(1, word( arg(1) #, 1) ) /*gen a random number from 1 ──► arg. */ create: @.=; do j=1 for #; @.j= j; end /*j*/; return isRed: return arg(1) // 2 /*if arg(1) is odd, the card is RED.*/ shuffle: do j=1 for #; x=?(); y=?(); parse value @.x @.y with @.y @.x; end; return /*──────────────────────────────────────────────────────────────────────────────────────*/ count: Rn=0; Bn=0; do j=1 for words(R); Rn=Rn+ isRed(word(R,j)) ; end
do k=1 for words(B); Bn=Bn+ (\isRed(word(B,k))); end if Rn==Bn then ok= ok+1; return /*Was it a good trial? Bump OK counter*/
/*──────────────────────────────────────────────────────────────────────────────────────*/ deal: R=; B=; D=; do j=1 for #%2 by 2 /*deal all the cards. */
next= j+1; card= @.next /*obtain the next card. */ if isRed(@.j) then R=R card /*add to the RED pile?*/ else B=B card /* " " " BLACK " */ D= D @.j /* " " " discard " */ end /*j*/ return /*discard pile not used.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/ swap: $= ?( min( words(R), words(B) ) ); Rc=; Bc= /*ensure we can swap $ cards.*/
do $ /*$: is the number of swaps.*/ R?= ?( words(R) ) /*a random card in RED pile.*/ B?= ?( words(B) ) /*" " " " BLACK " */ /* "reds" to be swapped.*/ Rc= Rc word(R, R?); R= delword(R, R?, 1) /*del card*/ /*"blacks" " " " */ Bc= Bc word(B, B?); B= delword(B, B?, 1) /* " " */ end /*$*/ R=R Bc; B=B Rc; return /*add swapped cards to piles.*/</lang>
- output when using the default inputs:
Correctness of the mathematician's assertion: 100% (out of 500 trials).
zkl
<lang zkl>cards:=[1..52].pump(List,"isEven","toInt").shuffle(); // red==1 stacks:=T(List(),List()); // black stack (0), red stack (1) blkStk,redStk := stacks; foreach card in (cards){ stacks[card].append(__cardWalker.next()) } println("Stacks:\n Black stack: ",blkStk,"\n Red stack: ",redStk);
numSwaps:=(1).random(1000); // do lots of swaps do(numSwaps){ blkStk.append(redStk.pop(0)); redStk.append(blkStk.pop(0)); } println("Post %d swaps:\n Black stack: %s\n Red stack: %s"
.fmt(numSwaps,blkStk,redStk));
numBlack,numRed := blkStk.filter('==(0)).len(), redStk.filter().len(); if(numBlack==numRed)
println("Agreed, black stack has same number of black cards \n " "as red stack has number of red cards: ",numRed);
else println("Boo, differnt stack lenghts");</lang>
- Output:
Stacks: Black stack: L(0,0,1,1,0,0,1,0,0,0,0) Red stack: L(0,1,0,1,0,1,1,1,0,1,0,0,1,1,0) Post 99 swaps: Black stack: L(0,0,1,1,0,0,0,1,1,0,0) Red stack: L(1,0,0,0,0,0,1,0,1,0,1,1,1,0,1) Agreed, black stack has same number of black cards as red stack has number of red cards: 7