Riffle Shuffle Golf Time

-1

Anyone who has spent any time around a deck of playing cards will recognize the riffle shuffle. The deck is cut in half and the two stacks are riffled simultaneously into the same pile before being tidied up in a sometimes visually appealing way.

This code-golf challenge is to write a function/method/(language equivalent) that performs the riffle shuffle on an array/stack/(language equivalent) of any size in the language of your choice.

As input, your function will except an array (language equivalent), plus how many times to run the shuffle. When done, it will return the shuffled array.

Your riffle shuffle function must implement the following algorithm:

  1. Divide the deck into two stacks

    A stack must have a minimum of 40% of the total cards in the deck and a maximum of 60%

  2. Choose a random stack to start with

  3. Drop 1 - 7 cards from the bottom of the starting stack to the top of the newly shuffled deck

  4. Drop 1 - 7 cards from the bottom of the other stack to the top of the newly shuffled deck

  5. Repeat #3 and #4 until only one stack remains

  6. Drop the remaining cards from the remaining stack on top of the newly shuffled deck

Smallest character count will be chosen as the answer in 1 week (May 29th).

This is the sample deck of cards to use:

[
'AH', '2H', '3H', '4H', '5H', '6H', '7H', '8H', '9H', '10H', 'JH', 'QH', 'KH',
'AC', '2C', '3C', '4C', '5C', '6C', '7C', '8C', '9C', '10C', 'JC', 'QC', 'KC',
'KD', 'QD', 'JD', '10D', '9D', '8D', '7D', '6D', '5D', '4D', '3D', '2D', 'AD',
'KS', 'QS', 'JS', '10S', '9S', '8S', '7S', '6S', '5S', '4S', '3S', '2S', 'AS'
]

Your answer should contain:

  • Code-golfed code
  • What the sample deck looks like after being shuffled twice
  • Un-golfed code

user1886419

Posted 2014-05-22T19:45:49.613

Reputation: 1 015

3I've removed the extraneous [popularity-contest] here as it's not part of the scoring. Also, I've removed the langauge restrictions - we usually like to let everyone play instead of discouraging some from submitting an answer in a language they prefer. – Doorknob – 2014-05-22T19:48:11.517

3Two things: Firstly, you should explicitly specify that steps 1, 3 and 4 are subject to randomness (and possibly a uniform distribution, if you want to enforce that). Secondly, I don't think requesting the output of a random process helps much here, because it doesn't really prove the implementation is correct and will just clutter this post. – Martin Ender – 2014-05-22T19:58:26.723

Can I expect the deck to always have an even number of cards, or not? – Οurous – 2014-05-22T23:45:10.417

1This challenge would be interesting if it didn't give the step-by-step algorithm the code must implement. As is, the only competition is in how well you golf the operations (and what language you use). – xnor – 2014-05-23T03:14:11.330

@Ourous even or odd number of cards – user1886419 – 2014-05-23T13:45:44.033

Answers

1

Python (131)

Waaaay too long, even for something that came to be after a "careful" reading of the rules:

Drop 1 - 7 cards from the bottom of the starting stack to the top of the newly shuffled deck

Doens't actually say this should be random, so I'll just always drop 1 card.

Divide the deck into two stacks

A stack must have a minimum of 40% of the total cards in the deck and a maximum of 60%

Sure. I'll just always do about 50%.

Anyways, the code:

def s(d):
 b=[d.pop()for _ in range(len(d)/2)];r=[];b,d=(b,d)if id(4)%2 else(d,b)
 while b and d:r+=[b.pop(),d.pop()]
 return r+b+d

Sample output:

In [17]: s(s([
    ...: 'AH', '2H', '3H', '4H', '5H', '6H', '7H', '8H', '9H', '10H', 'JH', 'QH', 'KH',
    ...: 'AC', '2C', '3C', '4C', '5C', '6C', '7C', '8C', '9C', '10C', 'JC', 'QC', 'KC',
    ...: 'KD', 'QD', 'JD', '10D', '9D', '8D', '7D', '6D', '5D', '4D', '3D', '2D', 'AD',
    ...: 'KS', 'QS', 'JS', '10S', '9S', '8S', '7S', '6S', '5S', '4S', '3S', '2S', 'AS'
    ...: ]))
Out[17]: 
['AD',
 'KH',
 'AC',
 'KS',
 '2D',
 'QH',
 '2C',
 'QS',
 '3D',
 'JH',
 '3C',
 'JS',
 '4D',
 '10H',
 '4C',
 '10S',
 '5D',
 '9H',
 '5C',
 '9S',
 '6D',
 '8H',
 '6C',
 '8S',
 '7D',
 '7H',
 '7C',
 '7S',
 '8D',
 '6H',
 '8C',
 '6S',
 '9D',
 '5H',
 '9C',
 '5S',
 '10D',
 '4H',
 '10C',
 '4S',
 'JD',
 '3H',
 'JC',
 '3S',
 'QD',
 '2H',
 'QC',
 '2S',
 'KD',
 'AH',
 'KC',
 'AS']

This is actually the code as I wrote it, I didn't specifically golfed any code. If you just want an explanation, please say so.

ɐɔıʇǝɥʇuʎs

Posted 2014-05-22T19:45:49.613

Reputation: 4 449

1Golfed it down to 84 chars: s=lambda d:sum(map(list,zip(*([d.pop()for _ in d[:len(d)/2]],d)[::id(4)%2*2-1])),[]). You basically want to get your two lists, zip them, then flatten them; that is what I implemented. – Justin – 2014-05-22T23:48:20.903

Golfed it down to 77 chars: s=lambda d:sum(map(list,zip(*[d[:len(d)/2],d[len(d)/2:]][::id(4)%2*2-1])),[]) – Justin – 2014-05-23T04:20:49.870

1Actually, we missed something: "As input, your function will except [sic] ... how many times to run the shuffle" – Justin – 2014-05-23T04:23:59.380

id(x)%2 will always be 0 because memory addresses are aligned on 4-byte boundaries. – Claudiu – 2014-05-23T04:51:06.963

0

Cobra - 307

Don't have access to a compiler atm, so this should work, but I'll be able to check later.

def f(d,n) as List<of int>
    r=Random()
    x=d.count
    for m in n
        p=q=[]
        for c in x
            if c%2>0,p.add(d.pop)
            else,q.add(d.pop)
        if r.next(0,2)>0,a,b=p,q
        else,a,b=q,p
        for c in x
            for z in r.next(0,7),if a.count>0,d.add(a.pop)
            for z in r.next(0,7),if b.count>0,d.add(b.pop)
    return d

Οurous

Posted 2014-05-22T19:45:49.613

Reputation: 7 916

0

Python 84

Golfed:

def s(d):
 e=len(d)/2;B=d[:e];C=d[e:];D=[]
 for x in range(e):D+=B[x],C[x]
 return D

Output Deck:

['AH', 'AC', 'KD', 'KS', '2H', '2C', 'QD', 'QS', '3H', '3C', 'JD', 'JS', '4H', '4C', '10D', '10S', '5H', '5C', '9D', '9S', '6H', '6C', '8D', '8S', '7H', '7C', '7D', '7S', '8H', '8C', '6D', '6S', '9H', '9C', '5D', '5S', '10H', '10C', '4D', '4S', 'JH', 'JC', '3D', '3S', 'QH', 'QC', '2D', '2S', 'KH', 'KC', 'AD', 'AS']

Un-golfed:

def Shuffle(Deck):
    Stack1 = Deck[:len(Deck)/2]            # 2nd Half of Deck
    Stack2 = Deck[len(Deck)/2:]            # 1st Half of Deck
    Output = []                            # Initialize Output List
    for index in range(len(Deck)/2):
        Output.append(Stack1[index])       # Append Output List with element from Stack1
        Output.append(Stack2[index])       # Append Output List with element from Stack2
    return Output                          # Return Output

Uses the same loopholes as @synthetica.

Harry Beadle

Posted 2014-05-22T19:45:49.613

Reputation: 787

1You missed one thing: "Choose a random stack to start with" – Justin – 2014-05-23T04:13:43.417

1Actually, we missed something else: "As input, your function will except [sic] ... how many times to run the shuffle" – Justin – 2014-05-23T04:25:29.013

@Quincunx Oh, that wasn't in the list but I see it now, I'll work on this later... – Harry Beadle – 2014-05-23T07:45:57.510

0

Python, 69 chars (actually takes number of times to shuffle as input)

If one follows the algorithm, always picking 1 card at each step of 1-7 cards (as it wasn't explicitly said to have to be random), then with an array like:

[1, 2, 3, 4, 5, 6]

We have one of two results depending on which stack is picked first:

[1, 2, 3] [4, 5, 6] ==> [1, 4, 2, 5, 3, 6]
[4, 5, 6] [1, 2, 3] ==> [4, 1, 5, 2, 6, 3]

The following algorithm accomplishes this n times, using id(b)%9>4 as a source of binary randomness[1]:

def s(d,n):
 for i in range(n):b=d[:];F=id(b)%9>4;d[F::2]=b[26:];d[1-F::2]=b[:26]

Sample output:

>>> o = ['AH', '2H', '3H', '4H', '5H', '6H', '7H', '8H', '9H', '10H', 'JH', 
 'QH', 'KH', 'AC', '2C', '3C', '4C', '5C', '6C', '7C', '8C', '9C', '10C', 'JC',
 'QC', 'KC', 'KD', 'QD', 'JD', '10D', '9D', '8D', '7D', '6D', '5D', '4D', '3D', 
 '2D', 'AD', 'KS', 'QS', 'JS', '10S', '9S', '8S', '7S', '6S', '5S', '4S', '3S',
 '2S', 'AS']
>>> d = o[:]; s(d, 2); d
['KD', 'KS', 'AH', 'AC', 'QD', 'QS', '2H', '2C', 'JD', 'JS', '3H', '3C', '10D', '10S', '4H', '4C', '9D', '9S', '5H', '5C', '8D', '8S', '6H', '6C', '7D', '7S', '7H', '7C', '6D', '6S', '8H', '8C', '5D', '5S', '9H', '9C', '4D', '4S', '10H', '10C', '3D', '3S', 'JH', 'JC', '2D', '2S', 'QH', 'QC', 'AD', 'AS', 'KH', 'KC']
>>> d = o[:]; s(d, 2); d
['AC', 'AH', 'KS', 'KD', '2C', '2H', 'QS', 'QD', '3C', '3H', 'JS', 'JD', '4C', '4H', '10S', '10D', '5C', '5H', '9S', '9D', '6C', '6H', '8S', '8D', '7C', '7H', '7S', '7D', '8C', '8H', '6S', '6D', '9C', '9H', '5S', '5D', '10C', '10H', '4S', '4D', 'JC', 'JH', '3S', '3D', 'QC', 'QH', '2S', '2D', 'KC', 'KH', 'AS', 'AD']

[1] This gives about a 44.4%/55.5% skew:

>>> r = {0: 0, 1: 0}
>>> for i in range(1000000):
        r[int(id(i)%9>4)]+=1
>>> r
{0: 555517, 1: 444483}

For two extra characters we can get a much better 50.5%/49.5% result:

>>> r = {0: 0, 1: 0}
>>> for i in range(1000000):
        r[int(id(i)%99>49)]+=1
>>> r
{0: 505050, 1: 494950}

Claudiu

Posted 2014-05-22T19:45:49.613

Reputation: 3 870