Dyota's blog

Pile shuffle

Pile shuffling! If you don't know what that is, the examples below will illustrate.

I wrote this because I wanted to make a function to spread out colours for Power BI. I first wrote it in PowerShell and then I wrote it again in Power Query M for a challenge. Turns out that was a very good exercise, because M is a lot less forgiving than PowerShell in some respects, and forced me to tighten up the code.

Here they are.

$stack = @(
    '♠A','♠2','♠3','♠4','♠5','♠6','♠7','♠8','♠9','♠10','♠J','♠Q','♠K',
    '♥A','♥2','♥3','♥4','♥5','♥6','♥7','♥8','♥9','♥10','♥J','♥Q','♥K',
    '♣A','♣2','♣3','♣4','♣5','♣6','♣7','♣8','♣9','♣10','♣J','♣Q','♣K',
    '♦A','♦2','♦3','♦4','♦5','♦6','♦7','♦8','♦9','♦10','♦J','♦Q','♦K'
  )

function pileShuffle ([PSCustomObject[]] $stack, [int] $piles ) {
    # check if it is an even split. abandon if not
    $evensplit = ($stack.length % $piles) -eq 0
    
    if ( $evensplit ) {
        $n = $stack.length
    
        # the height of each small stack after dividing
        $h = $stack.length / $piles
    
        $a = @(0..$($h - 1))
    
        # indeces of the stack
        $b = @(0..$($piles - 1))
        
        return $a.ForEach({
            $step = $_
            $b.ForEach({ 
                $i = $($_ * $h) + $step
                
                # pick off the i-th element off the stack
                $stack[$i]
            }) 
        })
    
    } else {
        Write-Host stack will not be divided into an even split - choose a different number of piles
    }
}

pileShuffle $stack 4

<# 
result:
"♠A", "♥A", "♣A", "♦A", 
"♠2", "♥2", "♣2", "♦2", 
"♠3", "♥3", "♣3", "♦3", 
"♠4", "♥4", "♣4", "♦4", 
"♠5", "♥5", "♣5", "♦5", 
"♠6", "♥6", "♣6", "♦6", 
"♠7", "♥7", "♣7", "♦7", 
"♠8", "♥8", "♣8", "♦8", 
"♠9", "♥9", "♣9", "♦9", 
"♠10", "♥10", "♣10", "♦10", 
"♠J", "♥J", "♣J", "♦J", 
"♠Q", "♥Q", "♣Q", "♦Q", 
"♠K", "♥K", "♣K", "♦K"
#>
(stack as list, piles as number ) as list =>
    let
        // number of elements in the stack
        n = List.Count(stack),

        // the "height" of each pile
        h = n / piles,

        // indices the outer loop
        a = {0..(h-1)},

        // indices the inner loop
        b = {0..(piles-1)},
        
        // e.g. stack of 20, and divided into 4 piles
        // the outer loop goes 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1...
        // the inner loop goes 0, 1, 2, 3, 0, 1, 2, 3, 0, 1...
        // put these two together with the formula below, and you get
        // 0, 4, 8, 12, 1, 5, 9, 13, 2, 6...
        // from this shuffle, we get the element at the i-th position in the stack
        
        outer = List.Transform(
            a, 
            each 
                let
                    step = _, 
                    inner = List.Transform(
                        b, 
                        each let i = _ * h + step in stack{i}
                    )
                in
                    inner
        ),
        combined = List.Combine(outer)
    in
        combined

#powerquery #powershell