Mind boggling card trick


Matt Parker of the "Stand Up Maths channel" has a   YouTube video   of a card trick that creates a semblance of order from chaos.

Task
Mind boggling card trick
You are encouraged to solve this task according to the task description, using any language you may know.

The task is to simulate the trick in a way that mimics the steps shown in the video.

1. Cards.
  1. Create a common deck of cards of 52 cards   (which are half red, half black).
  2. Give the pack a good shuffle.
2. Deal from the shuffled deck, you'll be creating three piles.
  1. Assemble the cards face down.
    1. Turn up the   top card   and hold it in your hand.
      1. if the card is   black,   then add the   next   card (unseen) to the "black" pile.
      2. If the card is     red,    then add the   next   card (unseen) to the   "red"  pile.
    2. Add the   top card   that you're holding to the discard pile.   (You might optionally show these discarded cards to get an idea of the randomness).
  2. Repeat the above for the rest of the shuffled deck.
3. Choose a random number   (call it X)   that will be used to swap cards from the "red" and "black" piles.
  1. Randomly choose   X   cards from the   "red"  pile (unseen), let's call this the   "red"  bunch.
  2. Randomly choose   X   cards from the "black" pile (unseen), let's call this the "black" bunch.
  3. Put the     "red"    bunch into the   "black" pile.
  4. Put the   "black"   bunch into the     "red"  pile.
  5. (The above two steps complete the swap of   X   cards of the "red" and "black" piles.
    (Without knowing what those cards are --- they could be red or black, nobody knows).
4. Order from randomness?
  1. Verify (or not) the mathematician's assertion that:
     The number of black cards in the "black" pile equals the number of red cards in the "red" pile. 


(Optionally, run this simulation a number of times, gathering more evidence of the truthfulness of the assertion.)

Show output on this page.

11l

Translation of: Python
//import random
V n = 52
V Black = ‘Black’
V Red = ‘Red’
V blacks = [Black] * (n I/ 2)
V reds = [Red] * (n I/ 2)
V pack = blacks [+] reds
random:shuffle(&pack)

[String] black_stack, red_stack, discard
L !pack.empty
   V top = pack.pop()
   I top == Black
      black_stack.append(pack.pop())
   E
      red_stack.append(pack.pop())
   discard.append(top)
print(‘(Discards: ’(discard.map(d -> d[0]).join(‘ ’))" )\n")

V max_swaps = min(black_stack.len, red_stack.len)
V swap_count = random:(0 .. max_swaps)
print(‘Swapping ’swap_count)

F random_partition(stack, count)
   V stack_copy = copy(stack)
   random:shuffle(&stack_copy)
   R (stack_copy[count ..], stack_copy[0 .< count])

(black_stack, V black_swap) = random_partition(black_stack, swap_count)
(red_stack, V red_swap) = random_partition(red_stack, swap_count)

black_stack [+]= red_swap
red_stack [+]= black_swap

I black_stack.count(Black) == red_stack.count(Red)
   print(‘Yeha! The mathematicians assertion is correct.’)
E
   print(‘Whoops - The mathematicians (or my card manipulations) are flakey’)
Output:
(Discards: B R B B R B R R R B R R R R B R B B R R B B R B B R )

Swapping 10
Yeha! The mathematicians assertion is correct.

Ada

-- Check the "Mind boggling card trick"
-- J. Carter     2024 May
-- Uses the PragmAda Reusable Components (https://github.com/jrcarter/PragmARC)

with Ada.Text_IO;
with Ada.Numerics.Discrete_Random;
with PragmARC.Cards.Decks.US;
with PragmARC.Cards.US;

procedure Card_Trick is
   package Cards renames PragmARC.Cards.US;
   package Decks renames PragmARC.Cards.Decks.US;
   
   function Is_Red (Card : in Cards.Card_Info) return Boolean is
      (Card.Suit in Cards.Diamond | Cards.Heart);
      
   function Correct return Boolean;
   -- Performs the trick and returns True if the assertion that 'The number of black cards in the "black" pile equals the number
   -- of red cards in the "red" pile' holds; False if it does not
      
   function Correct return Boolean is
      function Num_Red (Deck : in Decks.Deck_52) return Natural;
      -- Returns the number of red cards in Deck
      
      function Num_Black (Deck : in Decks.Deck_52) return Natural;
      -- Returns the number of black cards in Deck
      
      function Num_Red (Deck : in Decks.Deck_52) return Natural is
         Result : Natural := 0;
      begin -- Num_Red
         Count : for I in 1 .. Deck.Size loop
            if Is_Red (Deck.Value (I) ) then
               Result := Result + 1;
            end if;
         end loop Count;
         
         return Result;
      end Num_Red;
      
      function Num_Black (Deck : in Decks.Deck_52) return Natural is
         (Deck.Size - Num_Red (Deck) );
      
      Hand  : Decks.Deck_52;
      Red   : Decks.Deck_52;
      Black : Decks.Deck_52;
      Card  : Cards.Card_Info;
   begin -- Correct
      Decks.Standard_Deck (Item => Hand);
      Hand.Shuffle;
      
      All_Cards : loop
         exit All_Cards when Hand.Is_Empty;
         
         Hand.Deal (To => Card);
         
         if Is_Red (Card) then
            Hand.Deal (To => Card);
            Red.Add (Item => Card);
         else
            Hand.Deal (To => Card);
            Black.Add (Item => Card);
         end if;
      end loop All_Cards;
      
      Swap : declare
         Number : constant Natural := Integer'Min (Red.Size, Black.Size) - 1;
         
         subtype Bunch_Value is Integer range 1 .. Number;
         
         package Random is new Ada.Numerics.Discrete_Random (Result_Subtype => Bunch_Value);
         
         Gen   : Random.Generator;
         Bunch : Bunch_Value;
      begin -- Swap
         Random.Reset (Gen => Gen);
         Bunch := Random.Random (Gen);
         
         One_Bunch : for I in 1 .. Bunch loop
            Red.Deal (To => Card);
            Black.Add (Item => Card);
            Black.Deal (To => Card);
            Red.Add (Item => Card);
         end loop One_Bunch;
         
         return Num_Red (Red) = Num_Black (Black);
      end Swap;
   end Correct;
   
   Total : constant := 10_000;
   
   Good  : Natural := 0;
begin -- Card_Trick
   Check_All : for I in 1 .. Total loop
      if Correct then
         Good := Good + 1;
      end if;
   end loop Check_All;
   
   Ada.Text_IO.Put_Line (Item => Good'Image & " correct out of" & Total'Image & " tries");
end Card_Trick;
Output:
 10000 correct out of 10000 tries

AppleScript

use AppleScript version "2.5" -- OS X 10.11 (El Capitan) or later
use framework "Foundation"
use framework "GameplayKit" -- For randomising functions.

on cardTrick()
    (* Create a pack of "cards" and shuffle it. *)
    set suits to {"♥️", "♣️", "♦️", "♠️"}
    set cards to {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"}
    set deck to {}
    repeat with s from 1 to (count suits)
        set suit to item s of suits
        repeat with c from 1 to (count cards)
            set end of deck to item c of cards & suit
        end repeat
    end repeat
    set deck to (current application's class "GKRandomSource"'s new()'s arrayByShufflingObjectsInArray:(deck)) as list
    
    (* Perform the black pile/red pile/discard stuff. *)
    set {blackPile, redPile, discardPile} to {{}, {}, {}}
    repeat with c from 1 to (count deck) by 2
        set topCard to item c of deck
        if (character -1 of topCard is in "♣️♠️") then
            set end of blackPile to item (c + 1) of deck
        else
            set end of redPile to item (c + 1) of deck
        end if
        set end of discardPile to topCard
    end repeat
    -- When equal numbers of two possibilities are randomly paired, the number of pairs whose members are
    -- both one of the possibilities is the same as the number whose members are both the other. The cards
    -- in the red and black piles have effectively been paired with cards of the eponymous colours, so
    -- the number of reds in the red pile is already the same as the number of blacks in the black.
    
    (* Take a random number of random cards from one pile and swap them with an equal number from the other,
      religiously following the "red bunch"/"black bunch" ritual instead of simply swapping pairs of cards. *)
    -- Where swapped cards are the same colour, this will make no difference at all. Where the colours
    -- are different, both piles will either gain or lose a card of their relevant colour, maintaining
    -- the defining balance either way.
    set {redBunch, blackBunch} to {{}, {}}
    set {redPileCount, blackPileCount} to {(count redPile), (count blackPile)}
    set maxX to blackPileCount
    if (redPileCount < maxX) then set maxX to redPileCount
    set X to (current application's class "GKRandomDistribution"'s distributionForDieWithSideCount:(maxX))'s nextInt()
    set RNG to current application's class "GKShuffledDistribution"'s distributionForDieWithSideCount:(redPileCount)
    repeat X times
        set r to RNG's nextInt()
        set end of redBunch to item r of redPile
        set item r of redPile to missing value
    end repeat
    set RNG to current application's class "GKShuffledDistribution"'s distributionForDieWithSideCount:(blackPileCount)
    repeat X times
        set b to RNG's nextInt()
        set end of blackBunch to item b of blackPile
        set item b of blackPile to missing value
    end repeat
    set blackPile to (blackPile's text) & redBunch
    set redPile to (redPile's text) & blackBunch
    
    (* Count and compare the number of blacks in the black pile and the number of reds in the red. *)
    set blacksInBlackPile to 0
    repeat with card in blackPile
        if (character -1 of card is in "♣️♠️") then set blacksInBlackPile to blacksInBlackPile + 1
    end repeat
    set redsInRedPile to 0
    repeat with card in redPile
        if (character -1 of card is in "♥️♦️") then set redsInRedPile to redsInRedPile + 1
    end repeat
    
    return {truth:(blacksInBlackPile = redsInRedPile), reds:redPile, blacks:blackPile, discards:discardPile}
end cardTrick

on join(lst, delim)
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to delim
    set txt to lst as text
    set AppleScript's text item delimiters to astid
    return txt
end join

on task()
    set output to {}
    repeat with i from 1 to 5
        set {truth:truth, reds:reds, blacks:blacks, discards:discards} to cardTrick()
        set end of output to "Test " & i & ": Assertion is " & truth
        set end of output to "Red pile:   " & join(reds, ", ")
        set end of output to "Black pile: " & join(blacks, ", ")
        set end of output to "Discards:   " & join(items 1 thru 13 of discards, ", ")
        set end of output to "            " & (join(items 14 thru 26 of discards, ", ") & linefeed)
    end repeat
    return text 1 thru -2 of join(output, linefeed)
end task
return task()
Output:
"Test 1: Assertion is true
Red pile:   3♦️, 2♦️, 9♣️, 6♣️, 3♥️, 9♥️, A♠️, 3♠️, 2♥️, Q♠️, 7♥️, K♥️
Black pile: Q♥️, J♣️, 7♦️, 4♦️, 8♦️, 5♥️, K♣️, 10♠️, 10♣️, 7♣️, 2♣️, 9♦️, 5♣️, 6♦️
Discards:   9♠️, Q♦️, 3♣️, 6♠️, 8♠️, 8♥️, Q♣️, 4♠️, J♠️, K♦️, 7♠️, A♦️, 5♦️
            10♥️, J♦️, A♥️, 4♥️, 6♥️, J♥️, K♠️, 5♠️, 10♦️, 4♣️, 2♠️, 8♣️, A♣️

Test 2: Assertion is true
Red pile:   7♣️, Q♠️, 2♦️, K♣️, J♠️, A♠️, J♣️, 5♣️, 6♥️, 7♦️, 5♥️, 9♥️, 8♠️, 3♠️, 6♣️, 4♠️
Black pile: K♠️, J♦️, 4♣️, 10♠️, 4♥️, 3♥️, 6♠️, 4♦️, 10♣️, 9♦️
Discards:   8♦️, J♥️, A♣️, 10♥️, 8♣️, 9♠️, A♦️, 2♣️, K♥️, Q♣️, A♥️, 5♦️, 9♣️
            K♦️, 3♣️, 2♠️, 7♠️, 5♠️, 2♥️, 6♦️, 10♦️, 3♦️, Q♦️, 8♥️, 7♥️, Q♥️

Test 3: Assertion is true
Red pile:   4♥️, 2♠️, Q♦️, 9♣️, 4♣️, 7♥️, A♣️, 6♠️, 3♥️, 8♣️, A♦️, 2♣️, 6♥️, 5♦️
Black pile: K♦️, 2♦️, 5♠️, 10♠️, J♠️, 9♦️, 4♦️, 4♠️, Q♣️, 6♣️, 3♣️, 10♦️
Discards:   J♦️, 9♥️, K♠️, 10♥️, 5♥️, 10♣️, K♣️, 8♠️, 8♥️, A♠️, 7♣️, 7♦️, 8♦️
            Q♠️, 9♠️, 6♦️, 3♠️, 2♥️, J♣️, A♥️, K♥️, Q♥️, 5♣️, 7♠️, 3♦️, J♥️

Test 4: Assertion is true
Red pile:   6♠️, A♣️, 8♥️, 4♣️, 5♥️, J♠️, 9♠️, 7♥️, 7♣️, 4♦️, A♠️, A♥️, 8♠️, 6♦️, 5♣️, Q♣️, 6♥️, K♠️
Black pile: 5♦️, 4♠️, 2♣️, 6♣️, 10♣️, 8♣️, Q♠️, 10♠️
Discards:   J♥️, A♦️, 7♠️, 9♥️, K♦️, 10♥️, Q♦️, 10♦️, 8♦️, 3♥️, 3♠️, 2♦️, J♣️
            9♦️, J♦️, 9♣️, 2♠️, 3♦️, 2♥️, 7♦️, Q♥️, 3♣️, K♥️, K♣️, 5♠️, 4♥️

Test 5: Assertion is true
Red pile:   2♣️, 9♠️, 5♦️, 4♥️, K♥️, 5♥️, 8♦️, 2♠️, 3♦️, 10♥️, 10♦️
Black pile: 2♦️, 2♥️, 8♣️, 9♣️, 7♥️, 3♣️, Q♠️, 10♠️, 8♥️, 10♣️, K♣️, 5♠️, 4♦️, 3♥️, 6♥️
Discards:   7♦️, J♥️, 7♣️, 4♠️, 6♦️, 4♣️, 7♠️, Q♥️, J♠️, Q♦️, 6♠️, J♣️, A♥️
            9♦️, K♦️, J♦️, 3♠️, 5♣️, Q♣️, A♣️, K♠️, 8♠️, 9♥️, A♠️, 6♣️, A♦️"

AutoHotkey

;==========================================================
; create cards
cards := [], suits := ["♠","♥","♦","♣"], num := 0
for i, v in StrSplit("A,2,3,4,5,6,7,8,9,10,J,Q,K",",")
	for i, suit in suits
		cards[++num] := v suit
;==========================================================
; create gui
w := 40
Gui, font, S10
Gui, font, S10 CRed
Gui, add, text, w100 , Face Up Red
loop, 26
	Gui, add, button, % "x+0 w" w " vFR" A_Index
Gui, add, text, xs w100 , Face Down
loop, 26
	Gui, add, button, % "x+0 w" w " vHR" A_Index
Gui, font, S10 CBlack
Gui, add, text, xs w100 , Face Up Black
loop, 26
	Gui, add, button, % "x+0 w" w " vFB" A_Index
Gui, add, text, xs w100 , Face Down
loop, 26
	Gui, add, button, % "x+0 w" w " vHB" A_Index
Gui, add, button, xs gShuffle , Shuffle
Gui, add, button, x+1 Disabled vDeal gDeal , Deal
Gui, add, button, x+1 Disabled vMove gMove, Move
Gui, add, button, x+1 Disabled vShowAll gShowAll , Show All
Gui, add, button, x+1 Disabled vPeak gPeak, Peak
Gui, add, StatusBar
Gui, show
SB_SetParts(200,200)
SB_SetText("0 Face Down Red Cards", 1)
SB_SetText("0 Face Down Black Cards", 2)
return
;==========================================================
Shuffle:
list := "", shuffled := []
Loop, 52
	list .= A_Index ","
list := Trim(list, ",")
Sort, list, Random D,
loop, parse, list, `,
	shuffled[A_Index] := cards[A_LoopField]
loop, 26{
	GuiControl,, % "FR" A_Index
	GuiControl,, % "FB" A_Index
	GuiControl,, % "HR" A_Index
	GuiControl,, % "HB" A_Index
}
GuiControl, Enable, Deal
GuiControl, Disable, Move
GuiControl, Disable, ShowAll
GuiControl, Enable, Peak
return
;==========================================================
peak:
list := ""
for i, v in shuffled
	list .= i ": " v (mod(i,2)?"`t":"`n")
ToolTip , % list, 1000, 0
return
;==========================================================
Deal:
Color := "", 
GuiControl, Disable, Deal
FaceRed:= [], FaceBlack := [], HiddenRed := [], HiddenBlack := [], toggle := 0
for i, card in shuffled
	if toggle:=!toggle	{
		if InStr(card, "♥") || InStr(card, "♦") {
			Color := "Red"
			faceRed.push(card)
			GuiControl,, % "FR" faceRed.Count(), % card
		}
		else if InStr(card, "♠") || InStr(card, "♣") {
			Color := "Black"
			faceBlack.push(card)
			GuiControl,, % "FB" faceBlack.Count(), % card
		}
	}
	else{
		Hidden%Color%.push(card)
		GuiControl,, % (color="red"?"HR":"HB") Hidden%Color%.Count(), % "?"
		Sleep, 50
	}
GuiControl, Enable, Move
GuiControl, Enable, ShowAll
return
;==========================================================
Move:
tempR := [], tempB := []
Random, rndcount, 1, % HiddenRed.Count() < HiddenBlack.Count() ? HiddenRed.Count() : HiddenBlack.Count()
loop, % rndcount{
	Random, rnd, 1, % HiddenRed.Count()
	Random, rnd, 1, % HiddenBlack.Count()
	tempR.push(HiddenRed.RemoveAt(rnd))
	tempB.push(HiddenBlack.RemoveAt(rnd))
}
list := ""
for i, v in tempR
	list .= v "`t" tempB[i] "`n"
MsgBox % "swapping " rndcount " cards between face down Red and face down Black`n" (ShowAll?"Red`tBlack`n" list:"")
for i, v in tempR
	HiddenBlack.Push(v)
for i, v in tempB
	HiddenRed.push(v)
if ShowAll
	gosub, ShowAll
return
;==========================================================
ShowAll:
ShowAll := true, countR := countB := 0
loop, 26{
	GuiControl,, % "HR" A_Index
	GuiControl,, % "HB" A_Index
}
for i, card in HiddenRed
	GuiControl,, % "HR" i, % (card~= "[♥♦]"?"[":"") card (card~= "[♥♦]"?"]":"")
	, countR := (card~= "[♥♦]") ? countR+1 : countR
for i, card in HiddenBlack
	GuiControl,, % "HB" i, % (card~= "[♠♣]"?"[":"") card  (card~= "[♠♣]"?"]":"")
	, countB := (card~= "[♠♣]") ? countB+1 : countB
SB_SetText(countR " Face Down Red Cards", 1)
SB_SetText(countB " Face Down Black Cards", 2)
return
;==========================================================

C

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define SIM_N           5  /* Run 5 simulations */
#define PRINT_DISCARDED 1  /* Whether or not to print the discard pile */

#define min(x,y) ((x<y)?(x):(y))

typedef uint8_t card_t;

/* Return a random number from an uniform distribution (0..n-1) */
unsigned int rand_n(unsigned int n) {
    unsigned int out, mask = 1;
    /* Find how many bits to mask off */
    while (mask < n) mask = mask<<1 | 1;
    /* Generate random number */
    do {
        out = rand() & mask;
    } while (out >= n);
    return out;
}

/* Return a random card (0..51) from an uniform distribution */
card_t rand_card() {
    return rand_n(52);
}

/* Print a card */
void print_card(card_t card) {
    static char *suits = "HCDS"; /* hearts, clubs, diamonds and spades */
    static char *cards[] = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
    printf(" %s%c", cards[card>>2], suits[card&3]);
}

/* Shuffle a pack */
void shuffle(card_t *pack) {
    int card;
    card_t temp, randpos;
    for (card=0; card<52; card++) {
        randpos = rand_card();
        temp = pack[card];
        pack[card] = pack[randpos];
        pack[randpos] = temp;
    }
}

/* Do the card trick, return whether cards match */
int trick() {
    card_t pack[52];
    card_t blacks[52/4], reds[52/4];
    card_t top, x, card;
    int blackn=0, redn=0, blacksw=0, redsw=0, result;
   
    /* Create and shuffle a pack */
    for (card=0; card<52; card++) pack[card] = card;
    shuffle(pack);
    
    /* Deal cards */
#if PRINT_DISCARDED
    printf("Discarded:"); /* Print the discard pile */
#endif
    for (card=0; card<52; card += 2) {
        top = pack[card]; /* Take card */
        if (top & 1) { /* Add next card to black or red pile */
            blacks[blackn++] = pack[card+1];
        } else {
            reds[redn++] = pack[card+1];
        }
#if PRINT_DISCARDED
        print_card(top); /* Show which card is discarded */
#endif
    }
#if PRINT_DISCARDED
    printf("\n");
#endif

    /* Swap an amount of cards */
    x = rand_n(min(blackn, redn));
    for (card=0; card<x; card++) {
        /* Pick a random card from the black and red pile to swap */
        blacksw = rand_n(blackn);
        redsw = rand_n(redn); 
        /* Swap them */
        top = blacks[blacksw];
        blacks[blacksw] = reds[redsw];
        reds[redsw] = top;
    }
    
    /* Verify the assertion */
    result = 0;
    for (card=0; card<blackn; card++)
        result += (blacks[card] & 1) == 1;
    for (card=0; card<redn; card++)
        result -= (reds[card] & 1) == 0;
    result = !result;
    
    printf("The number of black cards in the 'black' pile"
           " %s the number of red cards in the 'red' pile.\n",
           result? "equals" : "does not equal");
    return result;
}

int main() {
    unsigned int seed, i, successes = 0;
    FILE *r;
    
    /* Seed the RNG with bytes from from /dev/urandom */
    if ((r = fopen("/dev/urandom", "r")) == NULL) {
        fprintf(stderr, "cannot open /dev/urandom\n");
        return 255;
    }
    if (fread(&seed, sizeof(unsigned int), 1, r) != 1) {
        fprintf(stderr, "failed to read from /dev/urandom\n");
        return 255;
    }
    fclose(r);
    srand(seed);
    
    /* Do simulations. */
    for (i=1; i<=SIM_N; i++) {
        printf("Simulation %d\n", i);
        successes += trick();
        printf("\n");
    }
    
    printf("Result: %d successes out of %d simulations\n",
        successes, SIM_N);
    
    return 0;
}
Output:
Simulation 1
Discarded: 10D 9S 7S KD 4S JS 6H 2D 2S 7H JH 5S AD AC 7D 5C 7C KH QD 4D 5H 2C 2H QS AH 3H
The number of black cards in the 'black' pile equals the number of red cards in the 'red' pile.

Simulation 2
Discarded: AC 10D QC 4H 2D AD 8D 10C 9D 2C QS 3S JC KS 6S AS 2S 6C 6D 6H 3D 8C 2H QH 7D 5D
The number of black cards in the 'black' pile equals the number of red cards in the 'red' pile.

Simulation 3
Discarded: 5D 2C JC 5C 5H 10D KD 4H KC 4S 8C 9S 6H 4D 2H 9H QS 10C 2S 3C AC 7H QD 7D JD 6S
The number of black cards in the 'black' pile equals the number of red cards in the 'red' pile.

Simulation 4
Discarded: 6S 4C KS AD 4S QS 9C 7D JD AC KH 10S KD QD 3S 5C QH 9D 2H 5S QC KC 7C 3D 9S AH
The number of black cards in the 'black' pile equals the number of red cards in the 'red' pile.

Simulation 5
Discarded: AD KH AC 8C 3C 5S KD QS 4C 2H 10C 2C JC 8D 6D JS 7C 4H 6H 6C 3S QC 6S KS 8H 7H
The number of black cards in the 'black' pile equals the number of red cards in the 'red' pile.

Result: 5 successes out of 5 simulations


C#

Translation of: Java
using System;
using System.Collections.Generic;
using System.Linq;

public class MindBogglingCardTrick
{
    public static void Main(string[] args)
    {
        List<char> cards = new List<char>();
        cards.AddRange(Enumerable.Repeat('R', 26));
        cards.AddRange(Enumerable.Repeat('B', 26));
        Shuffle(cards);

        List<char> redPile = new List<char>();
        List<char> blackPile = new List<char>();
        List<char> discardPile = new List<char>();

        for (int i = 0; i < 52; i += 2)
        {
            if (cards[i] == 'R')
            {
                redPile.Add(cards[i + 1]);
            }
            else
            {
                blackPile.Add(cards[i + 1]);
            }
            discardPile.Add(cards[i]);
        }

        Console.WriteLine("A sample run.\n");
        Console.WriteLine("After dealing the cards the state of the piles is:");
        Console.WriteLine($"    Red    : {redPile.Count} cards -> {string.Join(",", redPile)}");
        Console.WriteLine($"    Black  : {blackPile.Count} cards -> {string.Join(",", blackPile)}");
        Console.WriteLine($"    Discard: {discardPile.Count} cards -> {string.Join(",", discardPile)}");

        Random random = new Random();
        int minimumSize = Math.Min(redPile.Count, blackPile.Count);
        int choice = random.Next(1, minimumSize + 1);

        List<int> redIndexes = Enumerable.Range(0, redPile.Count).ToList();
        List<int> blackIndexes = Enumerable.Range(0, blackPile.Count).ToList();
        Shuffle(redIndexes);
        Shuffle(blackIndexes);
        List<int> redChosenIndexes = redIndexes.Take(choice).ToList();
        List<int> blackChosenIndexes = blackIndexes.Take(choice).ToList();

        Console.WriteLine($"\nNumber of cards are to be swapped: {choice}");
        Console.WriteLine("The respective zero-based indices of the cards to be swapped are:");
        Console.WriteLine($"    Red  : {string.Join(", ", redChosenIndexes)}");
        Console.WriteLine($"    Black: {string.Join(", ", blackChosenIndexes)}");

        for (int i = 0; i < choice; i++)
        {
            char temp = redPile[redChosenIndexes[i]];
            redPile[redChosenIndexes[i]] = blackPile[blackChosenIndexes[i]];
            blackPile[blackChosenIndexes[i]] = temp;
        }

        Console.WriteLine($"\nAfter swapping cards the state of the red and black piles is:");
        Console.WriteLine($"    Red  : {string.Join(", ", redPile)}");
        Console.WriteLine($"    Black: {string.Join(", ", blackPile)}");

        int redCount = redPile.Count(ch => ch == 'R');
        int blackCount = blackPile.Count(ch => ch == 'B');

        Console.WriteLine($"\nThe number of red cards in the red pile: {redCount}");
        Console.WriteLine($"The number of black cards in the black pile: {blackCount}");
        if (redCount == blackCount)
        {
            Console.WriteLine("So the assertion is correct.");
        }
        else
        {
            Console.WriteLine("So the assertion is incorrect.");
        }
    }

    private static void Shuffle<T>(List<T> list)
    {
        Random rng = new Random();
        int n = list.Count;
        while (n > 1)
        {
            n--;
            int k = rng.Next(n + 1);
            T value = list[k];
            list[k] = list[n];
            list[n] = value;
        }
    }
}
Output:
A sample run.

After dealing the cards the state of the piles is:
    Red    : 13 cards -> B,R,R,R,R,B,R,R,R,B,R,R,B
    Black  : 13 cards -> R,R,B,B,R,B,R,B,B,B,B,B,B
    Discard: 26 cards -> R,R,B,R,B,R,R,B,R,B,R,R,B,B,R,B,R,B,B,B,B,B,R,B,R,R

Number of cards are to be swapped: 3
The respective zero-based indices of the cards to be swapped are:
    Red  : 9, 8, 1
    Black: 1, 11, 5

After swapping cards the state of the red and black piles is:
    Red  : B, B, R, R, R, B, R, R, B, R, R, R, B
    Black: R, B, B, B, R, R, R, B, B, B, B, R, B

The number of red cards in the red pile: 8
The number of black cards in the black pile: 8
So the assertion is correct.


C++

#include <algorithm>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <random>
#include <vector>

template <typename T>
void print_vector(const std::vector<T>& list) {
	std::cout << "[";
	for ( uint64_t i = 0; i < list.size() - 1; ++i ) {
		std::cout << list[i] << " ";
	}
	std::cout << list.back() << "]" << std::endl;
}

int main() {
	std::vector<char> cards;
	for ( int32_t i = 0; i < 26; ++i ) {
		cards.emplace_back('R');
		cards.emplace_back('B');
	}

	std::random_device rand;
	std::mt19937 mersenne_twister(rand());
	std::shuffle(cards.begin(), cards.end(), mersenne_twister);

	std::vector<char> red_pile;
	std::vector<char> black_pile;
	std::vector<char> discard_pile;

	for ( int32_t i = 0; i < 52; i += 2 ) {
		if ( cards[i] == 'R' ) {
			red_pile.emplace_back(cards[i + 1]);
		} else {
			black_pile.emplace_back(cards[i + 1]);
		}
		discard_pile.emplace_back(cards[i]);
	}

	std::cout << "A sample run." << "\n" << std::endl;
	std::cout << "After dealing the cards the state of the piles is:" << std::endl;
	std::cout << "    Red    : " << std::setw(2) << red_pile.size() << " cards -> "; print_vector<char>(red_pile);
	std::cout << "    Black  : " << std::setw(2) << black_pile.size() << " cards -> "; print_vector<char>(black_pile);
	std::cout << "    Discard: " << std::setw(2) << discard_pile.size() 
              << " cards -> "; print_vector<char>(discard_pile);

	const int32_t minimum_size = std::min(red_pile.size(), black_pile.size());
	std::uniform_int_distribution<int> uniform_random{ 1, minimum_size };
	const int32_t choice = uniform_random(mersenne_twister);

	std::vector<int32_t> red_indexes(red_pile.size());
	std::iota(red_indexes.begin(), red_indexes.end(), 0);
	std::vector<int32_t> black_indexes(black_pile.size());
	std::iota(black_indexes.begin(), black_indexes.end(), 0);

	std::shuffle(red_indexes.begin(), red_indexes.end(), mersenne_twister);
	std::shuffle(black_indexes.begin(), black_indexes.end(), mersenne_twister);

	std::vector<int32_t> red_chosen_indexes(red_indexes.begin(), red_indexes.begin() + choice);
	std::vector<int32_t> black_chosen_indexes(black_indexes.begin(), black_indexes.begin() + choice);

	std::cout << "\n" << "Number of cards are to be swapped: " << choice << std::endl;
	std::cout << "The respective zero-based indices of the cards to be swapped are:" << std::endl;
	std::cout << "    Red  : "; print_vector<int32_t>(red_chosen_indexes);
	std::cout << "    Black: "; print_vector<int32_t>(black_chosen_indexes);

	for ( int32_t i = 0; i < choice; ++i ) {
		const char temp = red_pile[red_chosen_indexes[i]];
		red_pile[red_chosen_indexes[i]] = black_pile[black_chosen_indexes[i]];
		black_pile[black_chosen_indexes[i]] = temp;
	}

	std::cout << "\n" << "After swapping cards the state of the red and black piles is:" << std::endl;
	std::cout << "    Red  : "; print_vector<char>(red_pile);
	std::cout << "    Black: "; print_vector<char>(black_pile);

	int32_t red_count = 0;
	for ( const char& ch : red_pile ) {
		if ( ch == 'R' ) {
			red_count++;
		}
	}

	int32_t black_count = 0;
	for ( const char& ch : black_pile ) {
		if ( ch == 'B' ) {
			black_count++;
		}
	}

	std::cout << "\n" << "The number of red cards in the red pile: " << red_count << std::endl;
	std::cout << "The number of black cards in the black pile: " << black_count << std::endl;
	if ( red_count == black_count ) {
		std::cout << "So the assertion is correct." << std::endl;
	} else {
		std::cout << "So the assertion is incorrect." << std::endl;
	}
}
Output:
A sample run.

After dealing the cards the state of the piles is:
    Red    : 11 cards -> [R R B R R B R B B B R]
    Black  : 15 cards -> [B R B B R B R R R B B R R R R]
    Discard: 26 cards -> [B B R B B B B R R B R R R R B B B R B R B B R B R B]

Number of cards are to be swapped: 11
The respective zero-based indices of the cards to be swapped are:
    Red  : [6 7 10 2 8 4 1 3 0 5 9]
    Black: [2 9 11 12 0 7 3 6 8 14 10]

After swapping cards the state of the red and black piles is:
    Red  : [R B R R R R B B B B R]
    Black: [B R R R R B R R R B B R B R B]

The number of red cards in the red pile: 6
The number of black cards in the black pile: 6
So the assertion is correct.

Crystal

Translation of: Ruby
deck = ([:black, :red] * 26 ).shuffle
black_pile, red_pile, discard = [] of Symbol, [] of Symbol, [] of Symbol

until deck.empty?
  discard << deck.pop
  discard.last == :black ? black_pile << deck.pop : red_pile << deck.pop
end

x = rand( [black_pile.size, red_pile.size].min )
 
red_bunch   = (0...x).map { red_pile.delete_at( rand( red_pile.size )) }
black_bunch = (0...x).map { black_pile.delete_at( rand( black_pile.size )) }
 
black_pile += red_bunch
red_pile   += black_bunch
 
puts "The magician predicts there will be #{black_pile.count( :black )} red cards in the other pile.
Drumroll...
There were #{red_pile.count( :red )}!"
Output:
The magician predicts there will be 7 red cards in the other pile.
Drumroll...
There were 7!

EasyLang

Translation of: Wren
proc shuffle . a[] .
   for i = len a[] downto 2
      r = random i
      swap a[r] a[i]
   .
.
func$ a2str a[] .
   for v in a[]
      r$ &= strchar v & " "
   .
   return r$
.
R = strcode "R"
B = strcode "B"
for i to 26
   pack[] &= R
   pack[] &= B
.
shuffle pack[]
# 
for i = 1 step 2 to 51
   if pack[i] = B
      black[] &= pack[i + 1]
   else
      red[] &= pack[i + 1]
   .
   discard[] &= pack[i]
.
print "After dealing the cards the state of the stacks is:"
print "  Red    : " & a2str red[]
print "  Black  : " & a2str black[]
print "  Discard: " & a2str discard[]
for i to len red[]
   rp[] &= i
.
for i to len black[]
   bp[] &= i
.
shuffle rp[]
shuffle bp[]
n = random lower len red[] len black[]
len rp[] n
len bp[] n
# 
for i to n
   h = red[rp[i]]
   red[rp[i]] = black[bp[i]]
   black[bp[i]] = h
.
print ""
print "After swapping " & n & " cards the state of the stacks is:"
print "  Red    : " & a2str red[]
print "  Black  : " & a2str black[]
# 
for c in red[]
   red += if c = R
.
for c in black[]
   black += if c = B
.
print ""
print "The number of red cards in the red stack     = " & red
print "The number of black cards in the black stack = " & black
if red = black
   print "So the asssertion is correct!"
.
Output:
After dealing the cards the state of the stacks is:
  Red    : B B B R B B B R R R R R R B 
  Black  : B B B R R B R B B R R B 
  Discard: R B R B B R B R R B B R R R R R R R R B B B B B R B 

After swapping 7 cards the state of the stacks is:
  Red    : R R B R R B B R B R B R R B 
  Black  : B B R B R B B B R B R B 

The number of red cards in the red stack     = 8
The number of black cards in the black stack = 8
So the asssertion is correct!

F#

//Be boggled? Nigel Galloway: September 19th., 2018
let N=System.Random()
let fN=List.unfold(function |(0,0)->None |(n,g)->let ng=N.Next (n+g) in Some (if ng>=n then ("Black",(n,g-1)) else ("Red",(n-1,g))))(26,26)
let fG n=let (n,n')::(g,g')::_=List.countBy(fun (n::g::_)->if n=g then n else g) n in sprintf "%d %s cards and %d %s cards" n' n g' g
printf "A well shuffled deck -> "; List.iter (printf "%s ") fN; printfn ""
fN |> List.chunkBySize 2 |> List.groupBy List.head |> List.iter(fun(n,n')->printfn "The %s pile contains %s" n (fG n'))
Output:
A well shuffled deck -> Black Black Black Black Red Red Black Red Black Black Red Red Red Red Red Black Red Black Black Red Red Black Black Red Black Red Red Red Black Black Red Red Black Red Red Black Red Black Black Black Black Red Red Black Black Red Black Black Red Red Black Red 
The Black pile contains 6 Black cards and 8 Red cards
The Red pile contains 6 Red cards and 6 Black cards

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

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

FreeBASIC

Translation of: XPL0
Randomize Timer
Dim Shared As String Deck(52), BlackPile(52), RedPile(52), DiscardPile(52)
Dim Shared As Integer BlP, ReP, DiP

Sub Show
    Dim As Integer i
    Print "Black pile:     ";
    For i = 0 To BlP-1
        Print BlackPile(i);
    Next i
    Print !"\nRed pile:       ";
    For i = 0 To ReP-1
        Print RedPile(i);
    Next i
    Print !"\nDiscard pile:   ";
    For i = 0 To DiP-1
        Print DiscardPile(i);
    Next i
    Print
End Sub

Dim As String BlackBunch(52), RedBunch(52)
Dim As Integer i, j, m, x, y, BB, RB, BC, RC
Dim As Integer ub = Ubound(Deck)

For i = 0 To (ub/2)-1
    Deck(i) = "r"
    Deck(i+26) = "b"
Next i
For i = 0 To ub-1
    y = Int(Rnd * 51) + 1
    Swap Deck(y), Deck(i)
Next i
BlP = 0
ReP = 0
DiP = 0
For i = 0 To ub-1
    If Deck(i) = "b" Then
        BlackPile(BlP) = Deck(i+1)
        BlP += 1
    Else
        RedPile(ReP) = Deck(i+1)
        ReP += 1
    End If
    DiscardPile(DiP) = Deck(i)
    DiP += 1
    i += 1
Next i

Show
m = BlP
If ReP < m Then m = ReP
x = Int(Rnd * m) + 1
Print "Swap "; x; " cards between the red and black piles."
RB = 0
BB = 0
For i = 0 To x-1
    Do
        y = Int(Rnd * ReP)
    Loop Until RedPile(y) <> "0"
    RedBunch(RB) = RedPile(y)
    RB += 1
    RedPile(y) = "0"
Next i
For i = 0 To x-1
    Do
        y = Int(Rnd * BlP)
    Loop Until BlackPile(y) <> "0"
    BlackBunch(BB) = BlackPile(y)
    BB += 1
    BlackPile(y) = "0"
Next i
RB = 0
For i = 0 To x-1
    j = 0
    While BlackPile(j) <> "0"
        j += 1
    Wend
    BlackPile(j) = RedBunch(RB)
    RB += 1
Next i
BB = 0
For i = 0 To x-1
    j = 0
    While RedPile(j) <> "0"
        j += 1
    Wend
    RedPile(j) = BlackBunch(BB)
    BB += 1
Next i

Show
BC = 0
For i = 0 To BlP-1
    If BlackPile(i) = "b" Then BC += 1
Next i
RC = 0
For i = 0 To ReP-1
    If RedPile(i) = "r" Then RC += 1
Next i
Print "The number of black cards in the black pile is "; BC
Print "The number of red   cards in the red   pile is "; RC
Print Using "The mathematician's assertion is &correct."; Iif(BC <>RC, "not ", "")

Sleep
Output:
Black pile:     rbrbrrrrbrrrrb
Red pile:       bbbbrrbrbbbr
Discard pile:   bbrrbrrbbrbrrrrbrbbrbbrbbb
Swap  11 cards between the red and black piles.
Black pile:     rbbrbrbbbbrbrb
Red pile:       rrrrrrbbrrbr
Discard pile:   bbrrbrrbbrbrrrrbrbbrbbrbbb
The number of black cards in the black pile is  9
The number of red   cards in the red   pile is  9
The mathematician's assertion is correct.

Go

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    // Create pack, half red, half black and shuffle it.
    var pack [52]byte
    for i := 0; i < 26; i++ {
        pack[i] = 'R'
        pack[26+i] = 'B'
    }
    rand.Seed(time.Now().UnixNano())
    rand.Shuffle(52, func(i, j int) {
        pack[i], pack[j] = pack[j], pack[i]
    })

    // Deal from pack into 3 stacks.
    var red, black, discard []byte
    for i := 0; i < 51; i += 2 {
        switch pack[i] {
        case 'B':
            black = append(black, pack[i+1])
        case 'R':
            red = append(red, pack[i+1])
        }
        discard = append(discard, pack[i])
    }
    lr, lb, ld := len(red), len(black), len(discard)
    fmt.Println("After dealing the cards the state of the stacks is:")
    fmt.Printf("  Red    : %2d cards -> %c\n", lr, red)
    fmt.Printf("  Black  : %2d cards -> %c\n", lb, black)
    fmt.Printf("  Discard: %2d cards -> %c\n", ld, discard)

    // Swap the same, random, number of cards between the red and black stacks.
    min := lr
    if lb < min {
        min = lb
    }
    n := 1 + rand.Intn(min)
    rp := rand.Perm(lr)[:n]
    bp := rand.Perm(lb)[:n]
    fmt.Printf("\n%d card(s) are to be swapped.\n\n", n)
    fmt.Println("The respective zero-based indices of the cards(s) to be swapped are:")
    fmt.Printf("  Red    : %2d\n", rp)
    fmt.Printf("  Black  : %2d\n", bp)
    for i := 0; i < n; i++ {
        red[rp[i]], black[bp[i]] = black[bp[i]], red[rp[i]]
    }
    fmt.Println("\nAfter swapping, the state of the red and black stacks is:")
    fmt.Printf("  Red    : %c\n", red)
    fmt.Printf("  Black  : %c\n", black)

    // Check that the number of black cards in the black stack equals
    // the number of red cards in the red stack.
    rcount, bcount := 0, 0
    for _, c := range red {
        if c == 'R' {
            rcount++
        }
    }
    for _, c := range black {
        if c == 'B' {
            bcount++
        }
    }

    fmt.Println("\nThe number of red cards in the red stack     =", rcount)
    fmt.Println("The number of black cards in the black stack =", bcount)
    if rcount == bcount {
        fmt.Println("So the asssertion is correct!")
    } else {
        fmt.Println("So the asssertion is incorrect!")
    }
}
Output:

First sample run:

After dealing the cards the state of the stacks is:
  Red    : 15 cards -> [B R R R R B R B R B B R B B B]
  Black  : 11 cards -> [R B R B B R R B B B B]
  Discard: 26 cards -> [R R R R B B B B B B B R R R B B B R R R R R R B R R]

8 card(s) are to be swapped.

The respective zero-based indices of the cards(s) to be swapped are:
  Red    : [10  2 11 14 12  3  9  5]
  Black  : [ 7 10  3  0  5  8  6  1]

After swapping, the state of the red and black stacks is:
  Red    : [B R B B R B R B R R B B R B R]
  Black  : [B B R R B B B B R B R]

The number of red cards in the red stack     = 7
The number of black cards in the black stack = 7
So the asssertion is correct!

Second sample run:

After dealing the cards the state of the stacks is:
  Red    : 12 cards -> [B B R B R R R B B B R B]
  Black  : 14 cards -> [B R R R B R R B B R R B R R]
  Discard: 26 cards -> [R R B B B R R B B B R R R B B B R B B B R B R R R B]

2 card(s) are to be swapped.

The respective zero-based indices of the cards(s) to be swapped are:
  Red    : [ 1  6]
  Black  : [11 12]

After swapping, the state of the red and black stacks is:
  Red    : [B B R B R R R B B B R B]
  Black  : [B R R R B R R B B R R B R R]

The number of red cards in the red stack     = 5
The number of black cards in the black stack = 5
So the asssertion is correct!

Haskell

import System.Random (randomRIO)
import Data.List (partition)
import Data.Monoid ((<>))
 
main :: IO [Int]
main = do
 
  -- DEALT
  ns <- knuthShuffle [1 .. 52]
  let (rs_, bs_, discards) = threeStacks (rb <$> ns)
 
  -- SWAPPED
  nSwap <- randomRIO (1, min (length rs_) (length bs_))
  let (rs, bs) = exchange nSwap rs_ bs_
 
  -- CHECKED
  let rrs = filter ('R' ==) rs
  let bbs = filter ('B' ==) bs
  putStrLn $
    unlines
      [ "Discarded: " <> discards
      , "Swapped: " <> show nSwap
      , "Red pile: " <> rs
      , "Black pile: " <> bs
      , rrs <> " = Red cards in the red pile"
      , bbs <> " = Black cards in the black pile"
      , show $ length rrs == length bbs
      ]
  return ns
 
-- RED vs BLACK ----------------------------------------
rb :: Int -> Char
rb n
  | even n = 'R'
  | otherwise = 'B'
 
-- THREE STACKS ----------------------------------------
threeStacks :: String -> (String, String, String)
threeStacks = go ([], [], [])
  where
    go tpl [] = tpl
    go (rs, bs, ds) [x] = (rs, bs, x : ds)
    go (rs, bs, ds) (x:y:xs)
      | 'R' == x = go (y : rs, bs, x : ds) xs
      | otherwise = go (rs, y : bs, x : ds) xs
 
exchange :: Int -> [a] -> [a] -> ([a], [a])
exchange n xs ys =
  let [xs_, ys_] = splitAt n <$> [xs, ys]
  in (fst ys_ <> snd xs_, fst xs_ <> snd ys_)
 
-- SHUFFLE -----------------------------------------------
-- (See Knuth Shuffle task)
knuthShuffle :: [a] -> IO [a]
knuthShuffle xs = (foldr swapElems xs . zip [1 ..]) <$> randoms (length xs)
 
randoms :: Int -> IO [Int]
randoms x = traverse (randomRIO . (,) 0) [1 .. (pred x)]
 
swapElems :: (Int, Int) -> [a] -> [a]
swapElems (i, j) xs
  | i == j = xs
  | otherwise = replaceAt j (xs !! i) $ replaceAt i (xs !! j) xs
 
replaceAt :: Int -> a -> [a] -> [a]
replaceAt i c l =
  let (a, b) = splitAt i l
  in a ++ c : drop 1 b
Output:
Discarded: RRRRRBBBBBRBBBRBBRBRRBRRRB
Swapped: 7
Red pile: BBBRRBRBRBBRR
Black pile: BRRRRRBBRBBRB
RRRRRR = Red cards in the red pile
BBBBBB = Black cards in the black pile
True

J

The trick verb returns 0 if the magician's proposition fails, otherwise 1.

  NB. A failed assertion looks like this
   assert 0
|assertion failure: assert
|       assert 0

We find that in three runs the trick works.

shuffle =: {~ ?~@:#
f =: (,&.> {:)~
g =: ({.@],(f {:))`((f {.),{:@])@.({.@[)

trick =: 3 :0
 DECK =: shuffle 2 | i. 52
 'B R' =: shuffle L:_1 > g&.>/(_2 <\ DECK) , < 2 # a:
 NB. although I swap the first N cards of each pile,
 NB. the piles were shuffled following placement
 N =: ? R <.&# B
 echo 'prior to swap of ',(":N),' cards'
 echo 'black pile ',B{'rB'
 echo 'red pile   ',R{'rB'
 BR =: N {. B
 RB =: N {. R
 B =: RB , N }. B
 R =: BR , N }. R
 echo 'after swap'
 echo 'black pile ',B{'rB'
 echo 'red pile   ',R{'rB'
 B (-:&(+/) -.) R
)


   assert trick''
prior to swap of 10 cards
black pile rBrrrrrBBrrrBrr
red pile   BBrBrBBrBBr
after swap
black pile BBrBrBBrBBrrBrr
red pile   rBrrrrrBBrr

   assert trick''
prior to swap of 6 cards
black pile rBBBBrBBr
red pile   rrBBBBrBrBBBBrrBB
after swap
black pile rrBBBBBBr
red pile   rBBBBrrBrBBBBrrBB

   assert trick''
prior to swap of 3 cards
black pile rBrBrrrBBrr
red pile   BrrBrBBrBBBBBBB
after swap
black pile BrrBrrrBBrr
red pile   rBrBrBBrBBBBBBB

Java

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public final class MindBogglingCardTrick {

	public static void main(String[] aArgs) {		
		List<Character> cards = new ArrayList<Character>(52);
		cards.addAll(Collections.nCopies(26, 'R'));
		cards.addAll(Collections.nCopies(26, 'B'));
		Collections.shuffle(cards);
		
		List<Character> redPile = new ArrayList<Character>();
		List<Character> blackPile = new ArrayList<Character>();
		List<Character> discardPile = new ArrayList<Character>();	
	
		for ( int i = 0; i < 52; i += 2 ) {
			if ( cards.get(i) == 'R' ) {
				redPile.add(cards.get(i + 1));
			} else {
				blackPile.add(cards.get(i + 1));
			}	        
	        discardPile.add(cards.get(i));
	    }
		
		System.out.println("A sample run." + System.lineSeparator());
		System.out.println("After dealing the cards the state of the piles is:");
		System.out.println(String.format("    Red    : %2d cards -> %s", redPile.size(), redPile));
		System.out.println(String.format("    Black  : %2d cards -> %s", blackPile.size(), blackPile));
		System.out.println(String.format("    Discard: %2d cards -> %s", discardPile.size(), discardPile));
		
		ThreadLocalRandom random = ThreadLocalRandom.current();
	    final int minimumSize = Math.min(redPile.size(), blackPile.size());
	    final int choice = random.nextInt(1, minimumSize + 1);
	    
	    List<Integer> redIndexes = IntStream.range(0, redPile.size()).boxed().collect(Collectors.toList()); 
	    List<Integer> blackIndexes = IntStream.range(0, blackPile.size()).boxed().collect(Collectors.toList());
	    Collections.shuffle(redIndexes);
	    Collections.shuffle(blackIndexes);
	    List<Integer> redChosenIndexes = redIndexes.subList(0, choice);
	    List<Integer> blackChosenIndexes = blackIndexes.subList(0, choice);

	    System.out.println(System.lineSeparator() + "Number of cards are to be swapped: " + choice);
	    System.out.println("The respective zero-based indices of the cards to be swapped are:");
	    System.out.println("    Red  : " + redChosenIndexes);
	    System.out.println("    Black: " + blackChosenIndexes);
		
	    for ( int i = 0; i < choice; i++ ) {
	        final char temp = redPile.get(redChosenIndexes.get(i));
	        redPile.set(redChosenIndexes.get(i), blackPile.get(blackChosenIndexes.get(i)));
	        blackPile.set(blackChosenIndexes.get(i), temp);
	    }
	    
	    System.out.println(System.lineSeparator() + "After swapping cards the state of the red and black piles is:");
	    System.out.println("    Red  : " + redPile);
	    System.out.println("    Black: " + blackPile);
	    
	    int redCount = 0;
	    for ( char ch : redPile ) {
	    	if ( ch == 'R' ) {
	    		redCount += 1;
	    	}
	    }
	    
	    int blackCount = 0;
	    for ( char ch : blackPile ) {
	    	if ( ch == 'B' ) {
	    		blackCount += 1;
	    	}
	    }
	    
	    System.out.println(System.lineSeparator() + "The number of red cards in the red pile: " + redCount);
	    System.out.println("The number of black cards in the black pile: " + blackCount);
	    if ( redCount == blackCount ) {
	    	System.out.println("So the assertion is correct.");
	    } else {
	    	System.out.println("So the assertion is incorrect.");
	    }		
	}

}
Output:
A sample run.

After dealing the cards the state of the piles is:
    Red    : 11 cards -> [B, R, R, R, B, B, R, R, B, R, B]
    Black  : 15 cards -> [R, R, R, R, R, R, B, R, R, B, B, R, B, B, B]
    Discard: 26 cards -> [R, B, B, B, R, B, R, R, R, B, B, B, B, B, R, B, B, B, R, R, R, R, R, B, B, B]

Number of cards are to be swapped: 6
The respective zero-based indices of the cards to be swapped are:
    Red  : [4, 5, 6, 9, 0, 2]
    Black: [1, 4, 10, 7, 3, 0]

After swapping cards the state of the red and black piles is:
    Red  : [R, R, R, R, R, R, B, R, B, R, B]
    Black: [R, B, R, B, B, R, B, R, R, B, R, R, B, B, B]

The number of red cards in the red pile: 8
The number of black cards in the black pile: 8
So the assertion is correct.

JavaScript

Translation of: Haskell
(() => {
    'use strict';

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

            // SWAPPED
            nSwap = randomRInt(1, min(rs_.length, bs_.length)),
            [rs, bs] = exchange(nSwap, rs_, bs_),

            // 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.join(''),
            'Black pile: ' + bs.join(''),
            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 [x, y] = take(2, xs),
                        ds_ = cons(x, ds);
                    return (
                        'R' === x ? (
                            go([cons(y, rs), bs, ds_])
                        ) : go([rs, cons(y, bs), ds_])
                    )(drop(2, xs));
                })() : [rs, bs, ds_]
            ) : [rs, bs, ds];
        };
        return go([
            [],
            [],
            []
        ])(cards);
    };

    // exchange :: Int -> [a] -> [a] -> ([a], [a])
    const exchange = (n, xs, ys) => {
        const [xs_, ys_] = map(splitAt(n), [xs, ys]);
        return [
            fst(ys_).concat(snd(xs_)),
            fst(xs_).concat(snd(ys_))
        ];
    };

    // 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);

    // fst :: (a, b) -> a
    const fst = tpl => tpl[0];

    // 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))
        );

    // snd :: (a, b) -> b
    const snd = tpl => tpl[1];

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

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

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = (a, b) => ({
        type: 'Tuple',
        '0': a,
        '1': b,
        length: 2
    });

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

    // MAIN ---
    return main();
})();
Output:
Discarded: BRBRBRRRRBBBRBBBRBBBBBRRBR
Swapped: 7
Red pile: RBRRRRRRBRB
Black pile: BBBRRBRBBBRRBRR
RRRRRRRR = Red cards in the red pile
BBBBBBBB = Black cards in the black pile
true

jq

Adapted from Wren

Works with jq, the C implementation of jq

Works with gojq, the Go implementation of jq

Since jq does not include a PRN generator, an external source of entropy such as /dev/urandom is assumed. A suitable invocation of jq would be along the lines of:

< /dev/urandom tr -cd '0-9' | fold -w 1 | jq -nr trick.jq
### Generic utilities
def count(s): reduce s as $x (0; . + 1);

def lpad($len): tostring | ($len - length) as $l | (" " * $l) + .;


### Pseuo-random numbers

# Output: a prn in range(0;$n) where $n is `.`
def prn:
  if . == 1 then 0
  else . as $n
  | ([1, (($n-1)|tostring|length)]|max) as $w
  | [limit($w; inputs)] | join("") | tonumber
  | if . < $n then . else ($n | prn) end
  end;

def sample:
  if length == 0 # e.g. null or []
  then null
  else .[length|prn]
  end;

def knuthShuffle:
  length as $n
  | if $n <= 1 then .
    else {i: $n, a: .}
    | until(.i ==  0;
        .i += -1
        | (.i + 1 | prn) as $j
        | .a[.i] as $t
        | .a[.i] = .a[$j]
        | .a[$j] = $t)
    | .a 
    end;


### Cards

def R: "R"; # 82 ASCII
def B: "B"; # 66 ASCII

# Create deck, half red, half black and shuffle it.
def deck:
  ([range(0;26)|R] + [range(0;26)|B]) | knuthShuffle;

# Deal from `deck` into three stacks: {black, red, discard}
def deal:
  deck as $deck
  | reduce range(0; 51; 2) as $i (.;
      if $deck[$i] == B
      then .black += [$deck[$i+1]]
      else .red   += [$deck[$i+1]]
      end
      | .discard  += [$deck[$i]] );

def proceed:
  def p: join(" ");
  
  (.red|length) as $lr
  | (.black|length) as $lb
  | (.discard|length) as $ld

  | def displayStacks($discard):
    "  Red    : \($lr|lpad(2)) cards -> \(.red|p)",
    "  Black  : \($lb|lpad(2)) cards -> \(.black|p)",
    (select($discard) 
    | "  Discard: \($ld) cards -> \(.discard|p)") ;

  # Input: {red, black}
  def swap($n):
    . + { rp: ([range(0; $lr)] | knuthShuffle[0:$n] ),
          bp: ([range(0; $lb)] | knuthShuffle[0:$n]) }
    | reduce range(0;$n) as $i (.;
          .red[.rp[$i]] as $t
        | .red[.rp[$i]] = .black[.bp[$i]]
        | .black[.bp[$i]] = $t);

   def epilog:
     # Check that the number of black cards in the black stack equals
     # the number of red cards in the red stack:
       count(select(.red[] == R)) as $rcount
     | count(select(.black[] == B)) as $bcount
     | "\nThe number of red cards in the red stack     = \($rcount)",
         "The number of black cards in the black stack = \($bcount)",
        if $rcount == $bcount 
        then "So the assertion is correct!"
        else "So the assertion is incorrect!"
        end;

  "After dealing the cards, the stacks are as follows:",
  displayStacks(true),
  # Swap the same, random, number of cards between the red and black stacks.
  ( (if $lr < $lb then $lr else $lb end) as $min
   | (($min - 1|prn) + 1) as $n
   | swap($n)
   | "\n\($n) card(s) are to be swapped.",
     "The respective zero-based indices of the cards to be swapped are:",
     "  Red    : \(.rp|map(lpad(3))|p)",
     "  Black  : \(.bp|map(lpad(3))|p)",
     "\nAfter swapping, the red and black stacks are as follows:",
     displayStacks(false),
     epilog ) ;

deal | proceed
Output:
After dealing the cards, the stacks are as follows:
  Red    : 12 cards -> R B R R B B B R R B R B
  Black  : 14 cards -> R B B R B R R R B R B R B R
  Discard: 26 cards -> R R B B B R B R B R R B B B R B R B R B B B R B R R

1 card(s) are to be swapped.
The respective zero-based indices of the cards to be swapped are:
  Red    :   6
  Black  :   5

After swapping, the red and black stacks are as follows:
  Red    : 12 cards -> R B R R B B R R R B R B
  Black  : 14 cards -> R B B R B B R R B R B R B R

The number of red cards in the red stack     = 7
The number of black cards in the black stack = 7
So the assertion is correct!

Julia

Translation of: Raku
using Random

const rbdeck = split(repeat('R', 26) * repeat('B', 26), "")
shuffledeck() = shuffle(rbdeck)

function deal!(deck, dpile, bpile, rpile)
    while !isempty(deck)
        if (topcard = pop!(deck)) == "R"
            push!(rpile, pop!(deck))
        else
            push!(bpile, pop!(deck))
        end
        push!(dpile, topcard)
    end
end

function swap!(rpile, bpile, nswapping)
    rpick = sort(randperm(length(rpile))[1:nswapping])
    bpick = sort(randperm(length(bpile))[1:nswapping])
    rrm = rpile[rpick]; brm = bpile[bpick]
    deleteat!(rpile, rpick); deleteat!(bpile, bpick)
    append!(rpile, brm); append!(bpile, rrm)
end

function mindbogglingcardtrick(verbose=true)
    prif(cond, txt) = (if(cond) println(txt) end)
    deck = shuffledeck()
    prif(verbose, "Shuffled deck is: $deck")

    dpile, rpile, bpile = [], [], []
    deal!(deck, dpile, bpile, rpile)

    prif(verbose, "Before swap:")
    prif(verbose, "Discard pile:    $dpile")
    prif(verbose, "Red card pile:   $rpile")
    prif(verbose, "Black card pile: $bpile")
 
    amount = rand(1:min(length(rpile), length(bpile)))
    prif(verbose, "Swapping a random number of cards: $amount will be swapped.")
    swap!(rpile, bpile, amount)
 
    prif(verbose, "Red pile after swaps:   $rpile")
    prif(verbose, "Black pile after swaps: $bpile")
    println("There are $(sum(map(x->x=="B", bpile))) black cards in the black card pile:")
    println("there are $(sum(map(x->x=="R", rpile))) red cards in the red card pile.")
    prif(verbose, "")
end

mindbogglingcardtrick()

for _ in 1:10 
    mindbogglingcardtrick(false)
end
Output:

Shuffled deck is: SubString{String}["B", "B", "R", "B", "B", "R", "B", "R", "B", "R", "B", "B", "B", "R", "B", "R", "R", "B", "R", "R", 
"R", "R", "R", "R", "B", "R", "B", "B", "B", "R", "R", "B", "B", "R", "B", "B", "R", "R", "B", "R", "R", "R", "R", "B", "B", "R", "B", 
"B", "B", "B", "R", "R"]
Before swap:
Discard pile:    Any["R", "B", "B", "R", "B", "R", "R", "R", "B", "R", "B", "R", "B", "R", "R", "R", "R", "B", "R", "R", "B", "R", "R", 
"R", "B", "B"]
Red card pile:   Any["R", "B", "R", "B", "R", "B", "B", "B", "R", "R", "R", "B", "B", "B", "B", "B"]
Black card pile: Any["B", "B", "R", "B", "R", "B", "R", "B", "R", "B"]
Swapping a random number of cards: 8 will be swapped.
Red pile after swaps:   Any["R", "B", "B", "B", "R", "B", "B", "B", "R", "B", "R", "B", "R", "B", "R", "B"]
Black pile after swaps: Any["B", "B", "R", "R", "B", "B", "R", "R", "B", "B"]
There are 6 black cards in the black card pile:
there are 6 red cards in the red card pile.
There are 5 black cards in the black card pile:
there are 5 red cards in the red card pile.
There are 6 black cards in the black card pile:
there are 6 red cards in the red card pile.
There are 7 black cards in the black card pile:
there are 7 red cards in the red card pile.
There are 8 black cards in the black card pile:
there are 8 red cards in the red card pile.
There are 7 black cards in the black card pile:
there are 7 red cards in the red card pile.
There are 5 black cards in the black card pile:
there are 5 red cards in the red card pile.
There are 6 black cards in the black card pile:
there are 6 red cards in the red card pile.
There are 8 black cards in the black card pile:
there are 8 red cards in the red card pile.
There are 6 black cards in the black card pile:
there are 6 red cards in the red card pile.
There are 8 black cards in the black card pile:
there are 8 red cards in the red card pile.

Kotlin

Translation of: Go
// Version 1.2.61

import java.util.Random

fun main(args: Array<String>) {
    // Create pack, half red, half black and shuffle it.
    val pack = MutableList(52) { if (it < 26) 'R' else 'B' }
    pack.shuffle()

    // Deal from pack into 3 stacks.
    val red = mutableListOf<Char>()
    val black = mutableListOf<Char>()
    val discard = mutableListOf<Char>()
    for (i in 0 until 52 step 2) {
        when (pack[i]) {
            'B' -> black.add(pack[i + 1])
            'R' -> red.add(pack[i + 1])
        }
        discard.add(pack[i])
    }
    val sr = red.size
    val sb = black.size
    val sd = discard.size
    println("After dealing the cards the state of the stacks is:")
    System.out.printf("  Red    : %2d cards -> %s\n", sr, red)
    System.out.printf("  Black  : %2d cards -> %s\n", sb, black)
    System.out.printf("  Discard: %2d cards -> %s\n", sd, discard)

    // Swap the same, random, number of cards between the red and black stacks.
    val rand = Random()
    val min = minOf(sr, sb)
    val n = 1 + rand.nextInt(min)
    var rp = MutableList(sr) { it }.shuffled().subList(0, n)
    var bp = MutableList(sb) { it }.shuffled().subList(0, n)
    println("\n$n card(s) are to be swapped\n")
    println("The respective zero-based indices of the cards(s) to be swapped are:")
    println("  Red    : $rp")
    println("  Black  : $bp")
    for (i in 0 until n) {
        val temp = red[rp[i]]
        red[rp[i]] = black[bp[i]]
        black[bp[i]] = temp
    }
    println("\nAfter swapping, the state of the red and black stacks is:")
    println("  Red    : $red")
    println("  Black  : $black")

    // Check that the number of black cards in the black stack equals
    // the number of red cards in the red stack.
    var rcount = 0
    var bcount = 0
    for (c in red) if (c == 'R') rcount++
    for (c in black) if (c == 'B') bcount++
    println("\nThe number of red cards in the red stack     = $rcount")
    println("The number of black cards in the black stack = $bcount")
    if (rcount == bcount) {
        println("So the asssertion is correct!")
    }
    else {
        println("So the asssertion is incorrect!")
    }
}
Output:

First sample run:

After dealing the cards the state of the stacks is:
  Red    : 10 cards -> [R, R, B, R, R, B, B, R, R, R]
  Black  : 16 cards -> [B, B, R, R, R, R, B, R, R, B, R, B, B, R, R, B]
  Discard: 26 cards -> [R, B, B, B, R, R, B, B, B, R, B, B, B, B, R, B, R, B, R, R, R, R, B, B, B, B]

7 card(s) are to be swapped

The respective zero-based indices of the cards(s) to be swapped are:
  Red    : [3, 5, 6, 1, 4, 9, 7]
  Black  : [2, 0, 3, 15, 14, 12, 7]

After swapping, the state of the red and black stacks is:
  Red    : [R, B, B, R, R, B, R, R, R, B]
  Black  : [B, B, R, B, R, R, B, R, R, B, R, B, R, R, R, R]

The number of red cards in the red stack     = 6
The number of black cards in the black stack = 6
So the asssertion is correct!

Second sample run:

After dealing the cards the state of the stacks is:
  Red    : 11 cards -> [B, R, R, B, R, B, R, B, B, B, R]
  Black  : 15 cards -> [B, R, R, R, B, R, R, R, B, R, R, R, B, R, B]
  Discard: 26 cards -> [B, R, R, B, B, R, R, B, B, R, R, B, B, B, B, R, R, B, B, B, R, R, B, B, B, R]

3 card(s) are to be swapped

The respective zero-based indices of the cards(s) to be swapped are:
  Red    : [4, 2, 3]
  Black  : [0, 14, 2]

After swapping, the state of the red and black stacks is:
  Red    : [B, R, B, R, B, B, R, B, B, B, R]
  Black  : [R, R, B, R, B, R, R, R, B, R, R, R, B, R, R]

The number of red cards in the red stack     = 4
The number of black cards in the black stack = 4
So the asssertion is correct!

Lua

-- support:
function T(t) return setmetatable(t, {__index=table}) end
table.range = function(t,n) local s=T{} for i=1,n do s[i]=i end return s end
table.map = function(t,f) local s=T{} for i=1,#t do s[i]=f(t[i]) end return s end
table.filter = function(t,f) local s=T{} for i=1,#t do if f(t[i]) then s[#s+1]=t[i] end end return s end
table.clone = function(t) local s=T{} for k,v in ipairs(t) do s[k]=v end return s end
table.head = function(t,n) local s=T{} n=n>#t and #t or n for i = 1,n do s[i]=t[i] end return s end
table.tail = function(t,n) local s=T{} n=n>#t and #t or n for i = 1,n do s[i]=t[#t-n+i] end return s end
table.append = function(t,v) local s=t:clone() for i=1,#v do s[#s+1]=v[i] end return s end
table.shuffle = function(t) for i=#t,2,-1 do local j=math.random(i) t[i],t[j]=t[j],t[i] end return t end -- inplace!

-- task:
function cardtrick()
  -- 1.
  local deck = T{}:range(52):map(function(v) return v%2==0 and "B" or "R" end):shuffle()
  print("1. DECK      : " .. deck:concat())
  -- 2. (which guarantees the outcome)
  local bpile, rpile, discs = T{}, T{}, T{}
  local xpile = {B=bpile, R=rpile}
  while #deck>0 do
    local card, next = deck:remove(), deck:remove()
    xpile[card]:insert(next)
    discs:insert(card)
  end
  print("2. BLACK PILE: " .. bpile:concat())
  print("2. RED PILE  : " .. rpile:concat())
  print("2. DISCARDS  : " .. discs:concat())
  -- 3. (which cannot change the outcome)
  local x = math.random(0, math.min(#bpile, #rpile))
  local btake, rtake = T{}, T{}
  for i = 1, x do
    btake:insert((bpile:remove(math.random(#bpile))))
    rtake:insert((rpile:remove(math.random(#rpile))))
  end
  print("3. SWAPPING X: " .. x)
  print("3. BLACK SWAP: keep:" .. bpile:concat() .. "  take:" .. btake:concat())
  print("3. RED SWAP  : keep:" .. rpile:concat() .. "  take:" .. rtake:concat())
  bpile, rpile = bpile:append(rtake), rpile:append(btake)
  print("3. BLACK PILE: " .. bpile:concat())
  print("3. RED PILE  : " .. rpile:concat())
  -- 4. ("proving" that which was guaranteed earlier)
  local binb, rinr = bpile:filter(function(v) return v=="B" end), rpile:filter(function(v) return v=="R" end)
  print("4. BLACK PILE: contains " .. #binb .. " B's")
  print("4. RED PILE  : contains " .. #rinr .. " R's")
  print(#binb==#rinr and "VERIFIED" or "NOT VERIFIED")
  print()
end

-- demo:
math.randomseed(os.time())
for i = 1,3 do cardtrick() end
Output:
1. DECK      : RBBBRBRBRBBBBRRRRBRBBBRRBRRBRRBRBBRRBBRRBBRRRBBRBRBR
2. BLACK PILE: RBBBRBRRBRRRBR
2. RED PILE  : BBBRRRBRBRRB
2. DISCARDS  : RRRBRBRBRBRRBRRBBBRRBBBBBB
3. SWAPPING X: 3
3. BLACK SWAP: keep:RBBRBRRRRBR  take:BBR
3. RED SWAP  : keep:BBRRBRBRR  take:RBB
3. BLACK PILE: RBBRBRRRRBRRBB
3. RED PILE  : BBRRBRBRRBBR
4. BLACK PILE: contains 6 B's
4. RED PILE  : contains 6 R's
VERIFIED

1. DECK      : BRBBRRRRRBRBBRRBRRRRRBRBRBBBBBBRRRRBBRBBRBBRRBBBRBBR
2. BLACK PILE: RBRRBRBBRRRRRRB
2. RED PILE  : BBBRBRRBRRB
2. DISCARDS  : RBBBRBBRBRRBBBBBRRBRBBRRBR
3. SWAPPING X: 1
3. BLACK SWAP: keep:RRRBRBBRRRRRRB  take:B
3. RED SWAP  : keep:BBBRBRBRRB  take:R
3. BLACK PILE: RRRBRBBRRRRRRBR
3. RED PILE  : BBBRBRBRRBB
4. BLACK PILE: contains 4 B's
4. RED PILE  : contains 4 R's
VERIFIED

1. DECK      : BBRRRBBBBRBBRBBBRBRRRRRRBBRRRBRRBRRRRBRBBBRBBBBRBRBR
2. BLACK PILE: BRBRRRBRBRBBRB
2. RED PILE  : BBBRBRRRRRBR
2. DISCARDS  : RRRBBBBBRRRBRBRRRBBBBRBBRB
3. SWAPPING X: 5
3. BLACK SWAP: keep:BBRBRBBRB  take:RBRRR
3. RED SWAP  : keep:BRBRRBR  take:BRRBR
3. BLACK PILE: BBRBRBBRBBRRBR
3. RED PILE  : BRBRRBRRBRRR
4. BLACK PILE: contains 8 B's
4. RED PILE  : contains 8 R's
VERIFIED

Mathematica /Wolfram Language

s = RandomSample@Flatten[{Table[0, 26], Table[1, 26]}]
g = Take[s, {1, -1, 2}]
d = Take[s, {2, -1, 2}]
a = b = {};
Table[If[g[[i]] == 1, AppendTo[a, d[[i]]], AppendTo[b, d[[i]]]], {i, 
   Length@g}];
a
b
dice = RandomInteger[{1, 6}]
ra = Sort@RandomSample[Range@Length@a, dice]
a = {Delete[a, List /@ ra], a[[ra]]}
rb = Sort@RandomSample[Range@Length@b, dice]
b = {Delete[b, List /@ rb], b[[rb]]}
finala = Join[a[[1]], b[[2]]]
finalb = Join[b[[1]], a[[2]]]
Count[finala, 1] == Count[finalb, 0]
Output:
{0,1,0,1,0,1,0,0,0,1,0,0,0,1,1,0,0,0,1,1,1,1,0,1,0,0,1,1,1,0,0,0,0,1,0,1,0,0,1,0,1,1,1,1,1,0,1,1,1,0,0,1}   //shuffled deck
{0,0,0,0,0,0,0,1,0,1,1,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0}             // those are the key-cards
{1,1,1,0,1,0,1,0,0,1,1,1,0,1,0,0,1,1,0,0,1,1,0,1,0,1}             //those are the cards that will form the 2 piles based on keys
{0,1,1,1,0,0,1,1,0,1,0}                   //this is pile A
{1,1,1,0,1,0,1,0,1,0,0,1,1,0,1}          // this is pile B
4                                   //we throw a dice
{2,7,10,11}                         // we remove this 4 cards from pile A
{{0,1,1,0,0,1,0},{1,1,1,0}}         // this is pile A split
{3,8,10,11}                         // we remove 4 cards from different positions of pile B 
{{1,1,0,1,0,1,1,1,1,0,1},{1,0,0,0}}  //here is pile B split
{0,1,1,0,0,1,0,1,0,0,0}               //this is final A pile
{1,1,0,1,0,1,1,1,1,0,1,1,1,1,0}        //this is final B pile
True                                  // the result is TRUE

Nim

Translation of: Kotlin
import random, sequtils, strformat, strutils

type Color {.pure.} = enum Red = "R", Black = "B"

proc `$`(s: seq[Color]): string = s.join(" ")

# Create pack, half red, half black and shuffle it.
var pack = newSeq[Color](52)
for i in 0..51: pack[i] = Color(i < 26)
pack.shuffle()

# Deal from pack into 3 stacks.
var red, black, others: seq[Color]
for i in countup(0, 51, 2):
  case pack[i]
    of Red: red.add pack[i + 1]
    of Black: black.add pack[i + 1]
  others.add pack[i]
echo "After dealing the cards the state of the stacks is:"
echo &"  Red:     {red.len:>2} cards -> {red}"
echo &"  Black:   {black.len:>2} cards -> {black}"
echo &"  Discard: {others.len:>2} cards -> {others}"

# Swap the same, random, number of cards between the red and black stacks.
let m = min(red.len, black.len)
let n = rand(1..m)
var rp = toSeq(0..red.high)
rp.shuffle()
rp.setLen(n)
var bp = toSeq(0..black.high)
bp.shuffle()
bp.setLen(n)
echo &"\n{n} card(s) are to be swapped.\n"
echo "The respective zero-based indices of the cards(s) to be swapped are:"
echo "  Red    : ", rp.join(" ")
echo "  Black  : ", bp.join(" ")
for i in 0..<n:
  swap red[rp[i]], black[bp[i]]
echo "\nAfter swapping, the state of the red and black stacks is:"
echo "  Red    : ", red
echo "  Black  : ", black

# Check that the number of black cards in the black stack equals
# the number of red cards in the red stack.
let rcount = red.count(Red)
let bcount = black.count(Black)
echo ""
echo "The number of red cards in the red stack is ", rcount
echo "The number of black cards in the black stack is ", bcount
if rcount == bcount:
  echo "So the asssertion is correct."
else:
  echo "So the asssertion is incorrect."
Output:
After dealing the cards the state of the stacks is:
  Red:     14 cards -> B B B B R R B B R B R R R B
  Black:   12 cards -> R R R B R B B R B B R B
  Discard: 26 cards -> B B R R R R B B B R R R R R B B B R R B R B R B B R

6 card(s) are to be swapped.

The respective zero-based indices of the cards(s) to be swapped are:
  Red    : 6 9 10 5 13 3
  Black  : 7 4 5 8 2 11

After swapping, the state of the red and black stacks is:
  Red    : B B B B R B R B R R B R R R
  Black  : R R B B B R B B R B R B

The number of red cards in the red stack is 7
The number of black cards in the black stack is 7
So the asssertion is correct.

Perl

Trying several non-random deck orderings, in addition to a shuffled one. Predictably, the trick always works.

Translation of: Raku
sub trick {
    my(@deck) = @_;
    my $result .= sprintf "%-28s @deck\n", 'Starting deck:';

    my(@discard, @red, @black);
    deal(\@deck, \@discard, \@red, \@black);

    $result .= sprintf "%-28s @red\n", 'Red     pile:';
    $result .= sprintf "%-28s @black\n", 'Black   pile:';

    my $n = int rand(+@red < +@black ? +@red : +@black);
    swap(\@red, \@black, $n);

    $result .= sprintf "Red pile   after %2d swapped: @red\n", $n;
    $result .= sprintf "Black pile after %2d swapped: @black\n", $n;

    $result .= sprintf "Red in Red, Black in Black:  %d = %d\n", (scalar grep {/R/} @red), scalar grep {/B/} @black;
    return "$result\n";
}

sub deal {
    my($c, $d, $r, $b) = @_;
    while (@$c) {
        my $top = shift @$c;
        if ($top eq 'R') { push @$r, shift @$c }
        else             { push @$b, shift @$c }
        push @$d, $top;
    }
}

sub swap {
    my($r, $b, $n) = @_;
    push @$r, splice @$b, 0, $n;
    push @$b, splice @$r, 0, $n;
}

@deck = split '', 'RB' x 26;               # alternating red and black
print trick(@deck);
@deck = split '', 'RRBB' x 13;             # alternating pairs of reds and blacks
print trick(@deck);
@deck = sort @deck;                        # all blacks precede reds
print trick(@deck);
@deck = sort { -1 + 2*int(rand 2) } @deck; # poor man's shuffle
print trick(@deck);
Output:
Starting deck:               R B R B R B R B R B R B R B R B R B R B R B R B R B R B R B R B R B R B R B R B R B R B R B R B R B R B
Red     pile:                B B B B B B B B B B B B B B B B B B B B B B B B B B
Black   pile:
Red pile   after  0 swapped: B B B B B B B B B B B B B B B B B B B B B B B B B B
Black pile after  0 swapped:
Red in Red, Black in Black:  0 = 0

Starting deck:               R R B B R R B B R R B B R R B B R R B B R R B B R R B B R R B B R R B B R R B B R R B B R R B B R R B B
Red     pile:                R R R R R R R R R R R R R
Black   pile:                B B B B B B B B B B B B B
Red pile   after  8 swapped: R R R R R B B B B B B B B
Black pile after  8 swapped: B B B B B R R R R R R R R
Red in Red, Black in Black:  5 = 5

Starting deck:               B B B B B B B B B B B B B B B B B B B B B B B B B B R R R R R R R R R R R R R R R R R R R R R R R R R R
Red     pile:                R R R R R R R R R R R R R
Black   pile:                B B B B B B B B B B B B B
Red pile   after  8 swapped: R R R R R B B B B B B B B
Black pile after  8 swapped: B B B B B R R R R R R R R
Red in Red, Black in Black:  5 = 5

Starting deck:               B B R R B R B B B R R B R R B B B B R B R R B B B B B B R B R B R R R R B R B B B R B R B R R R R R R R
Red     pile:                R B R B R B B R R R R R
Black   pile:                B R B R B B B B B R B R R R
Red pile   after  6 swapped: B R R R R R B R B R B B
Black pile after  6 swapped: B B B R B R R R R B R B R B
Red in Red, Black in Black:  7 = 7

Phix

with javascript_semantics
constant n = 52,
         pack = shuffle(repeat('r',n/2)&repeat('b',n/2))
 
string black = "", red = "", discard = ""
for i=1 to length(pack) by 2 do
    integer top = pack[i],
            next = pack[i+1]
    if top=='b' then
        black &= next
    else
        red &= next
    end if
    discard &= top
end for
black = shuffle(black); red = shuffle(red) -- (optional)
--printf(1,"Discards : %s\n",{discard})
 
printf(1,"Reds   : %s\nBlacks : %s\n\n",{red,black})
 
integer lb = length(black), lr = length(red),
        ns = rand(min(lb,lr))
printf(1,"Swap %d cards:\n\n", ns)
string b1ns = black[1..ns],
       r1ns = red[1..ns]
black[1..ns] = r1ns
red[1..ns] = b1ns
 
printf(1,"Reds   : %s\nBlacks : %s\n\n",{red,black})
 
integer nb = sum(sq_eq(black,'b')),
        nr = sum(sq_eq(red,'r'))
string correct = iff(nr==nb?"correct":"**INCORRECT**")
printf(1,"%d r in red, %d b in black - assertion %s\n",{nr,nb,correct})
Output:
Reds   : brrbrrrrbrbr
Blacks : brrrbbbrbbbbrr

Swap 5 cards:

Reds   : brrrbrrrbrbr
Blacks : brrbrbbrbbbbrr

8 r in red, 8 b in black - assertion correct

Python

The code is layed out to follow the task decription, leading to some deviations from the PEP8 guidelines

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')

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.

Quackery

  [ stack ]                         is discards   (     --> s )
  [ stack ]                         is red-card   (     --> s )
  [ stack ]                         is black-card (     --> s )

  [ dup take rot join swap put ]    is to-pile    ( n s -->   )

  [ $ "" discards put
    $ "" red-card put
    $ "" black-card put
    char R 26 of
    char B 26 of join shuffle
    26 times
     [ behead tuck discards to-pile
       behead rot char R =
       iff red-card else black-card
      to-pile ]
    drop
    discards take witheach
      [ emit sp ] cr
    red-card take shuffle
    black-card take shuffle
    over size over size min random
    say "Swapping " dup echo
    say " cards." cr
    dup dip [ split rot ] split
    dip join rot join
    0 swap witheach
      [ char R = + ]
    0 rot witheach
      [ char B = + ]
    say "The assertion is "
    = iff [ say "true." ]
    else [ say "false." ] cr cr ]   is task       (     -->   )

   5 times task
Output:
B R R R B B R B B B R R B R R B B B R B B R B R R B 
Swapping 2 cards.
The assertion is true.

B R B R B B B B R B B B R R R R B B R R B R B B B B 
Swapping 4 cards.
The assertion is true.

B B R R R B R B B R B R R B R B R B B B R B R R B R 
Swapping 3 cards.
The assertion is true.

B B B R R R R R B R B B R B R B B R R R R R R R B B 
Swapping 8 cards.
The assertion is true.

B R B B B R R R R R B R B B R R B B B R R R R R B R 
Swapping 5 cards.
The assertion is true.

R

magictrick<-function(){
  deck=c(rep("B",26),rep("R",26))
  deck=sample(deck,52)
  blackpile=character(0)
  redpile=character(0)
  discardpile=character(0)
  while(length(deck)>0){
    if(deck[1]=="B"){
      blackpile=c(blackpile,deck[2])
      deck=deck[-2]
    }else{
      redpile=c(redpile,deck[2])
      deck=deck[-2]
    }
    discardpile=c(discardpile,deck[1])
    deck=deck[-1]
  }
  cat("After the deal the state of the piles is:","\n",
      "Black pile:",blackpile,"\n","Red pile:",redpile,"\n",
      "Discard pile:",discardpile,"\n","\n")
  X=sample(1:min(length(redpile),length(blackpile)),1)
  if(X==1){s=" is"}else{s="s are"}
  cat(X," card",s," being swapped.","\n","\n",sep="")
  redindex=sample(1:length(redpile),X)
  blackindex=sample(1:length(blackpile),X)
  redbunch=redpile[redindex]
  redpile=redpile[-redindex]
  blackbunch=blackpile[blackindex]
  blackpile=blackpile[-blackindex]
  redpile=c(redpile,blackbunch)
  blackpile=c(blackpile,redbunch)
  cat("After the swap the state of the piles is:","\n",
      "Black pile:",blackpile,"\n","Red pile:",redpile,"\n","\n")
  cat("There are ", length(which(blackpile=="B")), " black cards in the black pile.","\n",
      "There are ", length(which(redpile=="R")), " red cards in the red pile.","\n",sep="")
  if(length(which(blackpile=="B"))==length(which(redpile=="R"))){
    cat("The assertion is true!")
  }
}
Output:
After the deal the state of the piles is: 
 Black pile: B B R R B R B R R B B 
 Red pile: R B B B B B R B R R R B R B B 
 Discard pile: R R R R B R R R B R R B R B R R B R B R B B B R B B 
 
10 cards are being swapped.

After the swap the state of the piles is: 
 Black pile: R B B B B R R R R B R 
 Red pile: B B R B B B R B B B B R B R R 
 
There are 5 black cards in the black pile.
There are 5 red cards in the red pile.
The assertion is true!

Raku

(formerly Perl 6)

Works with: Rakudo version 2018.08
# Generate a shuffled deck
my @deck = shuffle;
put 'Shuffled deck:          ', @deck;

my (@discard, @red, @black);
# Deal cards following task description
deal(@deck, @discard, @red, @black);

put 'Discard pile:           ', @discard;
put '"Red"   pile:           ', @red;
put '"Black" pile:           ', @black;

# swap the same random number of random
# cards between the red and black piles
my $amount = ^(+@red min +@black) .roll;
put 'Number of cards to swap: ', $amount;
swap(@red, @black, $amount);

put 'Red pile after swaps:   ', @red;
put 'Black pile after swaps: ', @black;

say 'Number of Red   cards in the Red   pile: ', +@red.grep('R');
say 'Number of Black cards in the Black pile: ', +@black.grep('B');

sub shuffle { (flat 'R' xx 26, 'B' xx 26).pick: * }

sub deal (@deck, @d, @r, @b) {
    while @deck.elems {
        my $top = @deck.shift;
        if $top eq 'R' {
            @r.push: @deck.shift;
        }
        else {
            @b.push: @deck.shift;
        }
        @d.push: $top;
    }
}

sub swap (@r, @b, $a) {
    my @ri  = ^@r .pick($a);
    my @bi  = ^@b .pick($a);
    my @rs  = @r[@ri];
    my @bs  = @b[@bi];
    @r[@ri] = @bs;
    @b[@bi] = @rs;
}
Sample output:
Shuffled deck:          B B B R B R R R B B R R R B R B R B R R R B R B B R R B B R R B R B R R R R B R R B B B B B B R R B B B
Discard pile:           B B B R B R R R R R R R B R B R R R R B R B B B R B
"Red"   pile:           R R B B B R B B B B B R R B B
"Black" pile:           B R R B R R R B B R B
Number of cards to swap: 6
Red pile after swaps:   R R B B R R R R B B B R B B B
Black pile after swaps: B R B R R B B B B R B
Number of Red   cards in the Red   pile: 7
Number of Black cards in the Black pile: 7

REXX

Programming notes:   This REXX version uses a neat trick that the Python entry uses:   instead of using a deck of
cards,   it just uses a "deck" of numbers that correspond to the order of playing cards that came out of a new box of
cards.   Odd numbers represent red cards, even numbers represent black cards.

This could've been possibly simplified by using negative and positive numbers,   or   more accurately,   the suits and
a pip, but it would've taken more program logic to determine the color of the suits in a very succinct and efficient way.

Also, code was added to perform any number of trials.   Code was also added to allow repeatability by specifying a
seed   value for the   random   BIF.

A new deck of cards is always created     as if the playing cards were manufactured and put into a box,     that is,
13 spades () in a row   (A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K),     13 hearts (),     13 clubs (),     and 13 diamonds ().
(Various card playing manufacturers would arrange a new playing deck differently, but that isn't a concern.)

The number of cards in the deck and also the number of shuffles can be specified.   One shuffle swaps two random
cards, two shuffles swaps four random cards ···

Extra coding was added to keep singularities   (opposite of a plural)   to keep the English gooder (sic),   as well as
adding commas to larger numbers.

/*REXX pgm mimics a boggling card trick; separates cards into 3 piles based on color ···*/
parse arg trials # shuffs seed .                 /*obtain optional arguments from the CL*/
if trials=='' | trials==","  then trials= 1000   /*Not specified?  Then use the default.*/
if      #=='' |      #==","  then      #=   52   /* "      "         "   "   "     "    */
if shuffs=='' | shuffs==","  then shuffs=  #%4   /* "      "         "   "   "     "    */
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'    commas(trials),
    "trial"s(trials)')  using a deck of '     commas(#)                                  ,
    " card"s(#)',  and doing '                commas(shuffs)         ' shuffle's(shuffs).
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
?:       return random(1, word( arg(1) #, 1) )   /*gen a random number from  1 ──► arg. */
commas:  parse arg _;  do j=length(_)-3  to 1  by -3; _=insert(',', _, j); end;   return _
create:  @.=; k=0; do j=1  by 4  for #; k=k+1; @.k= j; if k//13==0 then j=j+1; end; return
isRed:   return    arg(1) // 2                   /*if  arg(1)  is odd,  the card is RED.*/
s:       if arg(1)==1  then return arg(3);  return word( arg(2) 's', 1)    /*pluralizer.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
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.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
shuffle:   do j=1  for shuffs;  x=?();    do until y\==x | #==1;   y=?();   end  /*until*/
         parse value   @.x  @.y     with     @.y  @.x;  end  /*j*/;                 return
/*──────────────────────────────────────────────────────────────────────────────────────*/
swap:    $= min( words(R), words(B) );          Rc=;   Bc= /*ensure we can swap $ cards.*/
         if $==0  then return                              /*A pile has no cards? return*/
                                   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.*/
output   when using the default inputs:
Correctness of the mathematician's assertion: 100%   (out of 10,000 trials)  using a deck of  52  cards,  and doing  13  shuffles.

Ruby

deck = ([:black, :red] * 26 ).shuffle
black_pile, red_pile, discard = [], [], []

until deck.empty? do
  discard << deck.pop
  discard.last == :black ? black_pile << deck.pop : red_pile << deck.pop
end

x = rand( [black_pile.size, red_pile.size].min )

red_bunch   = x.times.map{ red_pile.delete_at( rand( red_pile.size )) }
black_bunch = x.times.map{ black_pile.delete_at( rand( black_pile.size )) }

black_pile += red_bunch
red_pile   += black_bunch

puts "The magician predicts there will be #{black_pile.count( :black )} red cards in the other pile.
Drumroll...
There were #{red_pile.count( :red )}!"
Output:
The magician predicts there will be 5 red cards in the other pile.
Drumroll...
There were 5!

Rust

Library: rand
extern crate rand; // 0.5.5
use rand::Rng;
use std::iter::repeat;

#[derive(Debug, Eq, PartialEq, Clone)]
enum Colour {
    Black,
    Red,
}
use Colour::*;

fn main() {
    let mut rng = rand::thread_rng();
    
    //Create our deck.
    let mut deck: Vec<_> = repeat(Black).take(26)
        .chain(repeat(Red).take(26))
        .collect();
    
    rng.shuffle(&mut deck);
    
    let mut black_stack = vec![];
    let mut red_stack = vec![];
    let mut discarded = vec![];
    
    //Deal our cards.
    print!("Discarding:");
    while let (Some(card), Some(next)) = (deck.pop(), deck.pop()) {
        print!(" {}", if card == Black { "B" } else { "R" });
        match card {
            Red => red_stack.push(next),
            Black => black_stack.push(next),
        }
        discarded.push(card);
    }
    println!();
    
    // Choose how many to swap.
    let max = red_stack.len().min(black_stack.len());
    let num = rng.gen_range(1, max);
    println!("Exchanging {} cards", num);
    
    // Actually swap our cards.
    for _ in 0..num {
        let red = rng.choose_mut(&mut red_stack).unwrap();
        let black = rng.choose_mut(&mut black_stack).unwrap();
        std::mem::swap(red, black);
    }
    
    //Count how many are red and black.
    let num_black = black_stack.iter()
        .filter(|&c| c == &Black)
        .count();
    let num_red = red_stack.iter()
        .filter(|&c| c == &Red)
        .count();
        
    println!("Number of black cards in black stack: {}", num_black);
    println!("Number of red cards in red stack: {}", num_red);
}
Output:
Discarding: R R B B R R B R R B B B B B R R R B B B R R R B R R
Exchanging 5 cards
Number of black cards in black stack: 4
Number of red cards in red stack: 4

Wren

Translation of: Go
Library: Wren-fmt
import "random" for Random
import "./fmt" for Fmt

var R = 82 // ASCII 'R'
var B = 66 // ASCII 'B'

// Create pack, half red, half black and shuffle it.
var pack = [0] * 52
for (i in 0..25) {
    pack[i] = R
    pack[26+i] = B
}
var rand = Random.new()
rand.shuffle(pack)

// Deal from pack into 3 stacks.
var red = []
var black = []
var discard = []
var i = 0
while (i < 51) {
    if (pack[i] == B) {
        black.add(pack[i+1])
    } else {
        red.add(pack[i+1])
    }
    discard.add(pack[i])
    i = i + 2
}
var lr = red.count
var lb = black.count
var ld = discard.count
System.print("After dealing the cards the state of the stacks is:")
Fmt.print("  Red    : $2d cards -> $c", lr, red)
Fmt.print("  Black  : $2d cards -> $c", lb, black)
Fmt.print("  Discard: $2d cards -> $c", ld, discard)

// Swap the same, random, number of cards between the red and black stacks.
var min = (lr < lb) ? lr : lb
var n = rand.int(1, min + 1)
var rp = [0] * lr
var bp = [0] * lb
for (i in 0...lr) rp[i] = i
for (i in 0...lb) bp[i] = i
rand.shuffle(rp)
rand.shuffle(bp)
rp = rp[0...n]
bp = bp[0...n]
System.print("\n%(n) card(s) are to be swapped.\n")
System.print("The respective zero-based indices of the cards(s) to be swapped are:")
Fmt.print("  Red    : $2d", rp)
Fmt.print("  Black  : $2d", bp)
for (i in 0...n) {
    var t = red[rp[i]]
    red[rp[i]] = black[bp[i]]
    black[bp[i]] = t
}
System.print("\nAfter swapping, the state of the red and black stacks is:")
Fmt.print("  Red    : $c", red)
Fmt.print("  Black  : $c", black)

// Check that the number of black cards in the black stack equals
// the number of red cards in the red stack.
var rcount = red.count   { |c| c == R }
var bcount = black.count { |c| c == B }
System.print("\nThe number of red cards in the red stack     = %(rcount)")
System.print("The number of black cards in the black stack = %(bcount)")
if (rcount == bcount) {
    System.print("So the asssertion is correct!")
} else {
    System.print("So the asssertion is incorrect!")
}
Output:
After dealing the cards the state of the stacks is:
  Red    : 12 cards -> B R R B R R R R R R R B
  Black  : 14 cards -> B R B B B R B B R R B B R B
  Discard: 26 cards -> R R R B B B B R B R R R R B R B B B R B B B B R R B

11 card(s) are to be swapped.

The respective zero-based indices of the cards(s) to be swapped are:
  Red    :  0 11  6  8  3  9  1  7 10  5  2
  Black  :  2  3  0  4  5 10 12  6 13  8 11

After swapping, the state of the red and black stacks is:
  Red    : B R B R R R B B B B B B
  Black  : R R B B R B R B R R R R R R

The number of red cards in the red stack     = 4
The number of black cards in the black stack = 4
So the asssertion is correct!

XPL0

include xpllib; \for Print

char Deck(52), BlackPile(52), RedPile(52), DiscardPile(52),
     BlackBunch(52),  RedBunch(52);
int  I, J, T, M, X, Y, BP, RP, DP, BB, RB, BC, RC;

proc Show;
[Print("Black pile:     ");
for I:= 0 to BP-1 do ChOut(0, BlackPile(I));
Print("\nRed pile:       ");
for I:= 0 to RP-1 do ChOut(0, RedPile(I));
Print("\nDiscard pile:   ");
for I:= 0 to DP-1 do ChOut(0, DiscardPile(I));
Print("\n");
];

[for I:= 0 to 26-1 do
    [Deck(I):= ^r;  Deck(I+26):= ^b];
for I:= 0 to 52-1 do
    [Y:= Ran(52);       \0..51
    T:= Deck(I);  Deck(I):= Deck(Y);  Deck(Y):= T;
    ];
BP:= 0;  RP:= 0;  DP:= 0;
for I:= 0 to 52-1 do
    [if Deck(I) = ^b then
        [BlackPile(BP):= Deck(I+1);  BP:= BP+1]
    else
        [RedPile  (RP):= Deck(I+1);  RP:= RP+1];
    DiscardPile(DP):= Deck(I);  DP:= DP+1;
    I:= I+1;
    ];
Show;
M:= BP;
if RP < M then M:= RP;
X:= Ran(M) + 1;
Print("Swap %d cards between the red and black piles.\n", X);
RB:= 0;  BB:= 0;
for I:= 0 to X-1 do
    [repeat Y:= Ran(RP);  until RedPile(Y) # 0;
    RedBunch(RB):= RedPile(Y);  RB:= RB+1;  RedPile(Y):= 0;
    ];
for I:= 0 to X-1 do
    [repeat Y:= Ran(BP);  until BlackPile(Y) # 0;
    BlackBunch(BB):= BlackPile(Y);  BB:= BB+1;  BlackPile(Y):= 0;
    ];
RB:= 0;
for I:= 0 to X-1 do
    [J:= 0;
    while BlackPile(J) # 0 do J:= J+1;
    BlackPile(J):= RedBunch(RB);  RB:= RB+1;
    ];
BB:= 0;
for I:= 0 to X-1 do
    [J:= 0;
    while RedPile(J) # 0 do J:= J+1;
    RedPile(J):= BlackBunch(BB);  BB:= BB+1;
    ];
Show;
BC:= 0;
for I:= 0 to BP-1 do
    if BlackPile(I) = ^b then BC:= BC+1;
RC:= 0;
for I:= 0 to RP-1 do
    if RedPile(I) = ^r then RC:= RC+1;
Print("The number of black cards in the black pile is %d.\n", BC);
Print("The number of red   cards in the red   pile is %d.\n", RC);
Print("The mathematician's assertion is%s correct.\n",
    if BC#RC then " not" else "");
]
Output:
Black pile:     rrrrrbbbrbbbr
Red pile:       brrrbbbrrrbbb
Discard pile:   brrrrrbbbbrbrrbrbbrbbrbrbr
Swap 11 cards between the red and black piles.
Black pile:     bbrrbbbbrbrbr
Red pile:       brbrrrrrbrbbr
Discard pile:   brrrrrbbbbrbrrbrbbrbbrbrbr
The number of black cards in the black pile is 8.
The number of red   cards in the red   pile is 8.
The mathematician's assertion is correct.

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: ",redBlack(blkStk),"\n  Red stack:   ",redBlack(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,redBlack(blkStk),redBlack(redStk)));

numBlack,numRed := blkStk.filter('==(0)).len(), redStk.sum(0);
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, different stack lenghts");

fcn redBlack(cards){ cards.pump(String,fcn(c){ c and "R " or "B " }) }
Output:
Stacks:
  Black stack: B B R R R R R R R R R B B B R B 
  Red stack:   B B R R B B R R R R 
Post 360 swaps:
  Black stack: R R R R B B R R R R R R R R R B 
  Red stack:   B B R B B B R R B B 
Agreed, black stack has same number of black cards
  as red stack has number of red cards: 3