Factorial base numbers indexing permutations of a collection

You need a random arrangement of a deck of cards, you are sick of lame ways of doing this. This task is a super-cool way of doing this using factorial base numbers. The first 25 factorial base numbers in increasing order are: 0.0.0, 0.0.1, 0.1.0, 0.1.1, 0.2.0, 0.2.1, 1.0.0, 1.0.1, 1.1.0, 1.1.1,1.2.0, 1.2.1, 2.0.0, 2.0.1, 2.1.0, 2.1.1, 2.2.0, 2.2.1, 3.0.0, 3.0.1, 3.1.0, 3.1.1, 3.2.0, 3.2.1, 1.0.0.0 Observe that the least significant digit is base 2 the next base 3, in general an n-digit factorial base number has digits n..1 in base n+1..2.

Task
Factorial base numbers indexing permutations of a collection
You are encouraged to solve this task according to the task description, using any language you may know.

I want to produce a 1 to 1 mapping between these numbers and permutations:-

       0.0.0 -> 0123
       0.0.1 -> 0132
       0.1.0 -> 0213
       0.1.1 -> 0231
       0.2.0 -> 0312
       0.2.1 -> 0321
       1.0.0 -> 1023
       1.0.1 -> 1032
       1.1.0 -> 1203
       1.1.1 -> 1230
       1.2.0 -> 1302
       1.2.1 -> 1320
       2.0.0 -> 2013
       2.0.1 -> 2031
       2.1.0 -> 2103
       2.1.1 -> 2130
       2.2.0 -> 2301
       2.2.1 -> 2310
       3.0.0 -> 3012
       3.0.1 -> 3021
       3.1.0 -> 3102
       3.1.1 -> 3120
       3.2.0 -> 3201
       3.2.1 -> 3210

The following psudo-code will do this: Starting with m=0 and Ω, an array of elements to be permutated, for each digit g starting with the most significant digit in the factorial base number.

If g is greater than zero, rotate the elements from m to m+g in Ω (see example) Increment m and repeat the first step using the next most significant digit until the factorial base number is exhausted. For example: using the factorial base number 2.0.1 and Ω = 0 1 2 3 where place 0 in both is the most significant (left-most) digit/element.

Step 1: m=0 g=2; Rotate places 0 through 2. 0 1 2 3 becomes 2 0 1 3 Step 2: m=1 g=0; No action. Step 3: m=2 g=1; Rotate places 2 through 3. 2 0 1 3 becomes 2 0 3 1

Let me work 2.0.1 and 0123

    step 1 n=0 g=2 Ω=2013
    step 2 n=1 g=0 so no action
    step 3 n=2 g=1 Ω=2031

The task:

 First use your function to recreate the above table.
 Secondly use your function to generate all permutaions of 11 digits, perhaps count them don't display them, compare this method with
    methods in rc's permutations task.
 Thirdly here following are two ramdom 51 digit factorial base numbers I prepared earlier:
   39.49.7.47.29.30.2.12.10.3.29.37.33.17.12.31.29.34.17.25.2.4.25.4.1.14.20.6.21.18.1.1.1.4.0.5.15.12.4.3.10.10.9.1.6.5.5.3.0.0.0
   51.48.16.22.3.0.19.34.29.1.36.30.12.32.12.29.30.26.14.21.8.12.1.3.10.4.7.17.6.21.8.12.15.15.13.15.7.3.12.11.9.5.5.6.6.3.4.0.3.2.1
   use your function to crate the corresponding permutation of the following shoe of cards:
      A♠K♠Q♠J♠10♠9♠8♠7♠6♠5♠4♠3♠2♠A♥K♥Q♥J♥10♥9♥8♥7♥6♥5♥4♥3♥2♥A♦K♦Q♦J♦10♦9♦8♦7♦6♦5♦4♦3♦2♦A♣K♣Q♣J♣10♣9♣8♣7♣6♣5♣4♣3♣2♣
 Finally create your own 51 digit factorial base number and produce the corresponding permutation of the above shoe

F#

The Functıons

<lang fsharp> // Factorial base numbers indexing permutations of a collection

December 7th., 2018

let lN2p (c:int[]) (Ω:'Ω[])=

 let Ω=Array.copy Ω
 let rec fN i g e l=match l-i with 0->Ω.[i]<-e |_->Ω.[l]<-Ω.[l-1]; fN i g e (l-1)// rotate right
 [0..((Array.length Ω)-2)]|>List.iter(fun n->let i=c.[n] in if i>0 then fN n (i+n) Ω.[i+n] (i+n)); Ω

let lN Ω =

 let    n=Array.zeroCreate Ω
 let fN g=if n.[g]=Ω-g then n.[g]<-0; false else n.[g]<-n.[g]+1; true
 seq{yield n; while [1..Ω]|>List.exists(fun g->fN (Ω-g)) do yield n}

</lang>

Re-create the table

<lang fsharp> lN 3 |> Seq.iter (fun n->printfn "%A -> %A" n (lN2p n [|0;1;2;3|]));; </lang>

Output:
[|0; 0; 0|] -> [|0; 1; 2; 3|]
[|0; 0; 1|] -> [|0; 1; 3; 2|]
[|0; 1; 0|] -> [|0; 2; 1; 3|]
[|0; 1; 1|] -> [|0; 2; 3; 1|]
[|0; 2; 0|] -> [|0; 3; 1; 2|]
[|0; 2; 1|] -> [|0; 3; 2; 1|]
[|1; 0; 0|] -> [|1; 0; 2; 3|]
[|1; 0; 1|] -> [|1; 0; 3; 2|]
[|1; 1; 0|] -> [|1; 2; 0; 3|]
[|1; 1; 1|] -> [|1; 2; 3; 0|]
[|1; 2; 0|] -> [|1; 3; 0; 2|]
[|1; 2; 1|] -> [|1; 3; 2; 0|]
[|2; 0; 0|] -> [|2; 0; 1; 3|]
[|2; 0; 1|] -> [|2; 0; 3; 1|]
[|2; 1; 0|] -> [|2; 1; 0; 3|]
[|2; 1; 1|] -> [|2; 1; 3; 0|]
[|2; 2; 0|] -> [|2; 3; 0; 1|]
[|2; 2; 1|] -> [|2; 3; 1; 0|]
[|3; 0; 0|] -> [|3; 0; 1; 2|]
[|3; 0; 1|] -> [|3; 0; 2; 1|]
[|3; 1; 0|] -> [|3; 1; 0; 2|]
[|3; 1; 1|] -> [|3; 1; 2; 0|]
[|3; 2; 0|] -> [|3; 2; 0; 1|]
[|3; 2; 1|] -> [|3; 2; 1; 0|]
Shuffles

<lang fsharp> let shoe==[|"A♠";"K♠";"Q♠";"J♠";"10♠";"9♠";"8♠";"7♠";"6♠";"5♠";"4♠";"3♠";"2♠";"A♥";"K♥";"Q♥";"J♥";"10♥";"9♥";"8♥";"7♥";"6♥";"5♥";"4♥";"3♥";"2♥";"A♦";"K♦";"Q♦";"J♦";"10♦";"9♦";"8♦";"7♦";"6♦";"5♦";"4♦";"3♦";"2♦";"A♣";"K♣";"Q♣";"J♣";"10♣";"9♣";"8♣";"7♣";"6♣";"5♣";"4♣";"3♣";"2♣";|] //Random Shuffle let N=System.Random() in lc2p [|for n in 52..-1..2 do yield N.Next(n)|] shoe|>Array.iter (printf "%s ");printfn "" //Task Shuffles lN2p [|39;49;7;47;29;30;2;12;10;3;29;37;33;17;12;31;29;34;17;25;2;4;25;4;1;14;20;6;21;18;1;1;1;4;0;5;15;12;4;3;10;10;9;1;6;5;5;3;0;0;0|] shoe|>Array.iter (printf "%s ");printfn "" lN2p [|51;48;16;22;3;0;19;34;29;1;36;30;12;32;12;29;30;26;14;21;8;12;1;3;10;4;7;17;6;21;8;12;15;15;13;15;7;3;12;11;9;5;5;6;6;3;4;0;3;2;1|] shoe|>Array.iter (printf "%s ");printfn "" </lang>

Output:
J♣ Q♦ 10♣ 10♠ 3♥ 7♠ 8♥ 7♥ 8♦ 10♦ 4♥ 9♥ 8♠ K♥ 4♣ 5♥ K♣ Q♥ 9♠ A♦ Q♠ 6♦ K♦ K♠ 2♣ 6♠ 7♦ J♦ 2♥ 5♠ 4♦ 3♦ 6♣ J♥ 9♦ 4♠ 3♣ 2♠ 3♠ 10♥ Q♣ A♥ 2♦ A♠ 7♣ A♣ 9♣ 6♥ 5♦ 5♣ J♠ 8♣

A♣ 3♣ 7♠ 4♣ 10♦ 8♦ Q♠ K♥ 2♠ 10♠ 4♦ 7♣ J♣ 5♥ 10♥ 10♣ K♣ 2♣ 3♥ 5♦ J♠ 6♠ Q♣ 5♠ K♠ A♦ 3♦ Q♥ 8♣ 6♦ 9♠ 8♠ 4♠ 9♥ A♠ 6♥ 5♣ 2♦ 7♥ 8♥ 9♣ 6♣ 7♦ A♥ J♦ Q♦ 9♦ 2♥ 3♠ J♥ 4♥ K♦

2♣ 5♣ J♥ 4♥ J♠ A♠ 5♥ A♣ 6♦ Q♠ 9♣ 3♦ Q♥ J♣ 10♥ K♣ 10♣ 5♦ 7♥ 10♦ 3♠ 8♥ 10♠ 7♠ 6♥ 5♠ K♥ 4♦ A♥ 4♣ 2♥ 9♦ Q♣ 8♣ 7♦ 6♣ 3♥ 6♠ 7♣ 2♦ J♦ 9♥ A♦ Q♦ 8♦ 4♠ K♦ K♠ 3♣ 2♠ 8♠ 9♠
Comparıson wıth [Permutations(F#)]

<lang fsharp> let g=[|0..10|] lC 10 |> Seq.map(fun n->lc2p n g) |> Seq.length </lang>

Output:
Real: 00:01:08.430, CPU: 00:01:08.970, GC gen0: 9086, gen1: 0
val it : int = 39916800

8GB of memory is insufficient for rc's perm task

Go

<lang go>package main

import (

   "fmt"
   "math/rand"
   "strconv"
   "strings"
   "time"

)

func factorial(n int) int {

   fact := 1
   for i := 2; i <= n; i++ {
       fact *= i
   }
   return fact

}

func genFactBaseNums(size int, countOnly bool) ([][]int, int) {

   var results [][]int
   count := 0
   for n := 0; ; n++ {
       radix := 2
       var res []int = nil
       if !countOnly { 
           res = make([]int, size)
       }
       k := n
       for k > 0 {
           div := k / radix
           rem := k % radix
           if !countOnly {
               if radix <= size+1 {
                   res[size-radix+1] = rem
               }
           }
           k = div
           radix++
       }
       if radix > size+2 {
           break
       }
       count++
       if !countOnly {
           results = append(results, res)
       }
   }
   return results, count

}

func mapToPerms(factNums [][]int) [][]int {

   var perms [][]int
   psize := len(factNums[0]) + 1
   start := make([]int, psize)
   for i := 0; i < psize; i++ {
       start[i] = i
   }
   for _, fn := range factNums {
       perm := make([]int, psize)
       copy(perm, start)
       for m := 0; m < len(fn); m++ {
           g := fn[m]
           if g == 0 {
               continue
           }
           first := m
           last := m + g
           for i := 1; i <= g; i++ {
               temp := perm[first]
               for j := first + 1; j <= last; j++ {
                   perm[j-1] = perm[j]
               }
               perm[last] = temp
           }
       }
       perms = append(perms, perm)
   }
   return perms

}

func join(is []int, sep string) string {

   ss := make([]string, len(is))
   for i := 0; i < len(is); i++ {
       ss[i] = strconv.Itoa(is[i])
   }
   return strings.Join(ss, sep)

}

func undot(s string) []int {

   ss := strings.Split(s, ".")
   is := make([]int, len(ss))
   for i := 0; i < len(ss); i++ {
       is[i], _ = strconv.Atoi(ss[i])
   }
   return is

}

func main() {

   rand.Seed(time.Now().UnixNano())
   // Recreate the table.
   factNums, _ := genFactBaseNums(3, false)
   perms := mapToPerms(factNums)
   for i, fn := range factNums {
       fmt.Printf("%v -> %v\n", join(fn, "."), join(perms[i], ""))
   }
   // Check that the number of perms generated is equal to 11! (this takes a while).
   _, count := genFactBaseNums(10, true)
   fmt.Println("\nPermutations generated =", count)
   fmt.Println("compared to 11! which  =", factorial(11))
   fmt.Println()
   // Generate shuffles for the 2 given 51 digit factorial base numbers.
   fbn51s := []string{
       "39.49.7.47.29.30.2.12.10.3.29.37.33.17.12.31.29.34.17.25.2.4.25.4.1.14.20.6.21.18.1.1.1.4.0.5.15.12.4.3.10.10.9.1.6.5.5.3.0.0.0",
       "51.48.16.22.3.0.19.34.29.1.36.30.12.32.12.29.30.26.14.21.8.12.1.3.10.4.7.17.6.21.8.12.15.15.13.15.7.3.12.11.9.5.5.6.6.3.4.0.3.2.1",
   }
   factNums = [][]int{undot(fbn51s[0]), undot(fbn51s[1])}
   perms = mapToPerms(factNums)
   shoe := []rune("A♠K♠Q♠J♠T♠9♠8♠7♠6♠5♠4♠3♠2♠A♥K♥Q♥J♥T♥9♥8♥7♥6♥5♥4♥3♥2♥A♦K♦Q♦J♦T♦9♦8♦7♦6♦5♦4♦3♦2♦A♣K♣Q♣J♣T♣9♣8♣7♣6♣5♣4♣3♣2♣")
   cards := make([]string, 52)
   for i := 0; i < 52; i++ {
       cards[i] = string(shoe[2*i : 2*i+2])
       if cards[i][0] == 'T' {
           cards[i] = "10" + cards[i][1:]
       }
   }
   for i, fbn51 := range fbn51s {
       fmt.Println(fbn51)
       for _, d := range perms[i] {
           fmt.Print(cards[d])
       }
       fmt.Println("\n")
   }
   // Create a random 51 digit factorial base number and produce a shuffle from that.
   fbn51 := make([]int, 51)
   for i := 0; i < 51; i++ {
       fbn51[i] = rand.Intn(52 - i)
   }
   fmt.Println(join(fbn51, "."))
   perms = mapToPerms([][]int{fbn51})
   for _, d := range perms[0] {
       fmt.Print(cards[d])
   }
   fmt.Println()

}</lang>

Output:

Random for Part 4:

0.0.0 -> 0123
0.0.1 -> 0132
0.1.0 -> 0213
0.1.1 -> 0231
0.2.0 -> 0312
0.2.1 -> 0321
1.0.0 -> 1023
1.0.1 -> 1032
1.1.0 -> 1203
1.1.1 -> 1230
1.2.0 -> 1302
1.2.1 -> 1320
2.0.0 -> 2013
2.0.1 -> 2031
2.1.0 -> 2103
2.1.1 -> 2130
2.2.0 -> 2301
2.2.1 -> 2310
3.0.0 -> 3012
3.0.1 -> 3021
3.1.0 -> 3102
3.1.1 -> 3120
3.2.0 -> 3201
3.2.1 -> 3210

Permutations generated = 39916800
compared to 11! which  = 39916800

39.49.7.47.29.30.2.12.10.3.29.37.33.17.12.31.29.34.17.25.2.4.25.4.1.14.20.6.21.18.1.1.1.4.0.5.15.12.4.3.10.10.9.1.6.5.5.3.0.0.0
A♣3♣7♠4♣10♦8♦Q♠K♥2♠10♠4♦7♣J♣5♥10♥10♣K♣2♣3♥5♦J♠6♠Q♣5♠K♠A♦3♦Q♥8♣6♦9♠8♠4♠9♥A♠6♥5♣2♦7♥8♥9♣6♣7♦A♥J♦Q♦9♦2♥3♠J♥4♥K♦

51.48.16.22.3.0.19.34.29.1.36.30.12.32.12.29.30.26.14.21.8.12.1.3.10.4.7.17.6.21.8.12.15.15.13.15.7.3.12.11.9.5.5.6.6.3.4.0.3.2.1
2♣5♣J♥4♥J♠A♠5♥A♣6♦Q♠9♣3♦Q♥J♣10♥K♣10♣5♦7♥10♦3♠8♥10♠7♠6♥5♠K♥4♦A♥4♣2♥9♦Q♣8♣7♦6♣3♥6♠7♣2♦J♦9♥A♦Q♦8♦4♠K♦K♠3♣2♠8♠9♠

18.14.25.48.18.9.1.16.15.11.41.8.26.19.36.11.8.21.20.15.15.14.27.10.5.24.0.11.18.12.6.8.5.14.16.10.13.13.9.7.11.1.1.7.0.2.5.0.3.0.0
9♥K♥K♦2♣7♥5♠K♠6♥8♥A♥3♣4♠4♦J♦5♣J♥3♠6♦7♦A♦Q♦2♥7♣10♥8♠8♣A♠10♦Q♣8♦2♠4♥6♠J♣6♣3♦10♣9♣5♦3♥4♣J♠10♠A♣Q♠Q♥K♣9♠2♦7♠5♥9♦


Julia

<lang julia>function makefactorialbased(N, makelist)

   listlist = Vector{Vector{Int}}()
   count = 0
   while true
       divisor = 2
       makelist && (lis = zeros(Int, N))
       k = count
       while k > 0
           k, r = divrem(k, divisor)
           makelist && (divisor <= N + 1) && (lis[N - divisor + 2] = r)
           divisor += 1
       end
       if divisor > N + 2
           break
       end
       count += 1
       makelist && push!(listlist, lis)
   end
   return count, listlist

end

function facmap(factnumbase)

   perm = [i for i in 0:length(factnumbase)]
   for (n, g) in enumerate(factnumbase)
       if g != 0
           perm[n:n + g] .= circshift(perm[n:n + g], 1)
       end
   end
   perm

end

function factbasenums()

   fcount, factnums = makefactorialbased(3, true)
   perms = map(facmap, factnums)
   for (i, fn) = enumerate(factnums)
       println("$(join(string.(fn), ".")) -> $(join(string(perms[i]), ""))")
   end
   fcount, _ = makefactorialbased(10, false)
   println("\nPermutations generated = $fcount")
   println("compared to 11! which  = $(factorial(11))\n")
   fac51digits = map(s -> [parse(Int, s) for s in split(s, ".")], [
       "39.49.7.47.29.30.2.12.10.3.29.37.33.17.12.31.29.34.17.25.2.4.25.4.1.14.20.6.21.18.1.1.1.4.0.5.15.12.4.3.10.10.9.1.6.5.5.3.0.0.0",
       "51.48.16.22.3.0.19.34.29.1.36.30.12.32.12.29.30.26.14.21.8.12.1.3.10.4.7.17.6.21.8.12.15.15.13.15.7.3.12.11.9.5.5.6.6.3.4.0.3.2.1"])
   perms = map(facmap, fac51digits)
   cardshoe = "A♠K♠Q♠J♠T♠9♠8♠7♠6♠5♠4♠3♠2♠A♥K♥Q♥J♥T♥9♥8♥7♥6♥5♥4♥3♥2♥A♦K♦Q♦J♦T♦9♦8♦7♦6♦5♦4♦3♦2♦A♣K♣Q♣J♣T♣9♣8♣7♣6♣5♣4♣3♣2♣"
   carr = split(cardshoe, "")
   cards = map(x->join(x, ""),[carr[2*i+1] == 'T' ? 
                              ["10", carr[i+1][2]] : [carr[2*i+1], carr[2*i+2]] for i in 0:51])
   
   printcardshuffle(c, o) = (println(o); for i in 1:length(o) print(c[o[i] + 1]) end; println())
   
   println("\nTask shuffles:")
   for ordering in perms
       printcardshuffle(cards, ordering)
   end
   myrandorder = [rand(collect(0:i)) for i in 51:-1:1]
   perm = facmap(myrandorder)
   println("\nMy random shuffle:")
   printcardshuffle(cards, perm)

end

factbasenums()

</lang>

Output:

2.0.0 -> [2, 0, 1, 3]
2.0.1 -> [2, 0, 3, 1]
2.1.0 -> [2, 1, 0, 3]
2.1.1 -> [2, 1, 3, 0]
2.2.0 -> [2, 3, 0, 1]
2.2.1 -> [2, 3, 1, 0]
3.0.0 -> [3, 0, 1, 2]
3.0.1 -> [3, 0, 2, 1]
3.1.0 -> [3, 1, 0, 2]
3.1.1 -> [3, 1, 2, 0]
3.2.0 -> [3, 2, 0, 1]
3.2.1 -> [3, 2, 1, 0]
Permutations generated = 39916800
compared to 11! which  = 39916800


Task shuffles:
[39, 50, 7, 49, 30, 32, 2, 14, 12, 4, 36, 46, 42, 22, 17, 43, 40, 51, 24, 35, 3, 8, 41, 9, 1, 26, 37, 15, 45, 34, 5, 6, 10, 18, 0, 21, 
48, 38, 20, 19, 44, 47, 33, 13, 29, 28, 31, 25, 11, 16, 23, 27]
A♣3♣7♠4♣T♦8♦Q♠K♥2♠T♠4♦7♣J♣5♥T♥T♣K♣2♣3♥5♦J♠6♠Q♣5♠K♠A♦3♦Q♥8♣6♦9♠8♠4♠9♥A♠6♥5♣2♦7♥8♥9♣6♣7♦A♥J♦Q♦9♦2♥3♠J♥4♥K♦
[51, 48, 16, 23, 3, 0, 22, 39, 34, 2, 44, 37, 15, 42, 17, 40, 43, 35, 20, 30, 11, 19, 4, 7, 21, 9, 14, 36, 13, 49, 25, 31, 41, 45, 33, 
47, 24, 8, 46, 38, 29, 18, 26, 28, 32, 10, 27, 1, 50, 12, 6, 5]
2♣5♣J♥4♥J♠A♠5♥A♣6♦Q♠9♣3♦Q♥J♣T♥K♣T♣5♦7♥T♦3♠8♥T♠7♠6♥5♠K♥4♦A♥4♣2♥9♦Q♣8♣7♦6♣3♥6♠7♣2♦J♦9♥A♦Q♦8♦4♠K♦K♠3♣2♠8♠9♠

My random shuffle:
[5, 0, 14, 46, 39, 16, 12, 48, 40, 22, 45, 18, 21, 42, 23, 6, 20, 7, 36, 10, 35, 37, 15, 3, 32, 9, 29, 47, 28, 27, 2, 49, 11, 4, 34, 51, 
8, 41, 13, 31, 43, 38, 1, 44, 24, 17, 25, 26, 30, 50, 19, 33]
9♠A♠K♥7♣A♣J♥2♠5♣K♣5♥8♣9♥6♥J♣4♥8♠7♥7♠4♦4♠5♦3♦Q♥J♠8♦5♠J♦6♣Q♦K♦Q♠4♣3♠T♠6♦2♣6♠Q♣A♥9♦T♣2♦K♠9♣3♥T♥2♥A♦T♦3♣8♥7♦

Perl 6

Works with: Rakudo version 2018.11

Using my interpretation of the task instructions as shown on the discussion page.

<lang perl6>sub postfix:<!> (Int $n) { (flat 1, [\*] 1..*)[$n] }

multi base (Int $n is copy, 'F', $length? is copy) {

   constant @fact = [\*] 1 .. *;
   my $i = $length // @fact.first: * > $n, :k;
   my $f;
   [ @fact[^$i].reverse.map: { ($n, $f) = $n.polymod($_); $f } ]

}

sub fpermute (@a is copy, *@f) { (^@f).map: { @a[$_ .. $_ + @f[$_]].=rotate(-1) }; @a }

put "Part 1: Generate table"; put $_.&base('F', 3).join('.') ~ ' -> ' ~ [0,1,2,3].&fpermute($_.&base('F', 3)).join for ^24;

put "\nPart 2: Compare 11! to 11! " ~ '¯\_(ツ)_/¯';

  1. This is kind of a weird request. Since we don't actually need to _generate_
  2. the permutations, only _count_ them: compare count of 11! vs count of 11!

put "11! === 11! : {11! === 11!}";

put "\nPart 3: Generate the given task shuffles"; my \Ω = <A♠ K♠ Q♠ J♠ 10♠ 9♠ 8♠ 7♠ 6♠ 5♠ 4♠ 3♠ 2♠ A♥ K♥ Q♥ J♥ 10♥ 9♥ 8♥ 7♥ 6♥ 5♥ 4♥ 3♥ 2♥

        A♦ K♦ Q♦ J♦ 10♦ 9♦ 8♦ 7♦ 6♦ 5♦ 4♦ 3♦ 2♦ A♣ K♣ Q♣ J♣ 10♣ 9♣ 8♣ 7♣ 6♣ 5♣ 4♣ 3♣ 2♣

>;

my @books = <

   39.49.7.47.29.30.2.12.10.3.29.37.33.17.12.31.29.34.17.25.2.4.25.4.1.14.20.6.21.18.1.1.1.4.0.5.15.12.4.3.10.10.9.1.6.5.5.3.0.0.0
   51.48.16.22.3.0.19.34.29.1.36.30.12.32.12.29.30.26.14.21.8.12.1.3.10.4.7.17.6.21.8.12.15.15.13.15.7.3.12.11.9.5.5.6.6.3.4.0.3.2.1

>;

put "Original deck:"; put Ω.join;

put "\n$_\n" ~ Ω[(^Ω).&fpermute($_.split: '.')].join for @books;

put "\nPart 4: Generate a random shuffle"; my @shoe = (+Ω … 2).map: { (^$_).pick }; put @shoe.join('.'); put Ω[(^Ω).&fpermute(@shoe)].join;

put "\nSeems to me it would be easier to just say: Ω.pick(*).join"; put Ω.pick(*).join;</lang>

Output:
Part 1: Generate table
0.0.0 -> 0123
0.0.1 -> 0132
0.1.0 -> 0213
0.1.1 -> 0231
0.2.0 -> 0312
0.2.1 -> 0321
1.0.0 -> 1023
1.0.1 -> 1032
1.1.0 -> 1203
1.1.1 -> 1230
1.2.0 -> 1302
1.2.1 -> 1320
2.0.0 -> 2013
2.0.1 -> 2031
2.1.0 -> 2103
2.1.1 -> 2130
2.2.0 -> 2301
2.2.1 -> 2310
3.0.0 -> 3012
3.0.1 -> 3021
3.1.0 -> 3102
3.1.1 -> 3120
3.2.0 -> 3201
3.2.1 -> 3210

Part 2: Compare 11! to 11! ¯\_(ツ)_/¯
11! === 11! : True

Part 3: Generate the given task shuffles
Original deck:
A♠K♠Q♠J♠10♠9♠8♠7♠6♠5♠4♠3♠2♠A♥K♥Q♥J♥10♥9♥8♥7♥6♥5♥4♥3♥2♥A♦K♦Q♦J♦10♦9♦8♦7♦6♦5♦4♦3♦2♦A♣K♣Q♣J♣10♣9♣8♣7♣6♣5♣4♣3♣2♣

39.49.7.47.29.30.2.12.10.3.29.37.33.17.12.31.29.34.17.25.2.4.25.4.1.14.20.6.21.18.1.1.1.4.0.5.15.12.4.3.10.10.9.1.6.5.5.3.0.0.0
A♣3♣7♠4♣10♦8♦Q♠K♥2♠10♠4♦7♣J♣5♥10♥10♣K♣2♣3♥5♦J♠6♠Q♣5♠K♠A♦3♦Q♥8♣6♦9♠8♠4♠9♥A♠6♥5♣2♦7♥8♥9♣6♣7♦A♥J♦Q♦9♦2♥3♠J♥4♥K♦

51.48.16.22.3.0.19.34.29.1.36.30.12.32.12.29.30.26.14.21.8.12.1.3.10.4.7.17.6.21.8.12.15.15.13.15.7.3.12.11.9.5.5.6.6.3.4.0.3.2.1
2♣5♣J♥4♥J♠A♠5♥A♣6♦Q♠9♣3♦Q♥J♣10♥K♣10♣5♦7♥10♦3♠8♥10♠7♠6♥5♠K♥4♦A♥4♣2♥9♦Q♣8♣7♦6♣3♥6♠7♣2♦J♦9♥A♦Q♦8♦4♠K♦K♠3♣2♠8♠9♠

Part 4: Generate a random shuffle
47.9.46.16.28.8.36.27.29.1.9.27.1.16.21.22.28.34.30.8.19.27.18.22.3.25.15.20.12.14.8.9.11.1.4.0.3.5.4.2.2.10.8.1.6.1.2.4.1.2.1
6♣5♠5♣10♥10♦6♠K♣9♦6♦K♠2♠5♦Q♠5♥Q♦8♦J♣2♣8♣A♥K♦9♣A♦2♦9♠4♣3♥A♣7♥2♥Q♥9♥4♥J♠4♠A♠3♠8♥J♥7♠K♥3♣10♣8♠Q♣6♥7♦7♣J♦3♦4♦10♠

Seems to me it would be easier to just say: Ω.pick(*).join
5♦3♠8♦10♦2♥7♠7♦Q♦A♠5♣8♣Q♠4♠2♦K♦5♠Q♥7♣10♠2♠K♠J♣9♣3♣4♥3♥4♦3♦Q♣2♣4♣J♦9♠A♣J♠10♣6♣9♦6♠10♥6♥9♥J♥7♥K♥A♦8♠A♥5♥8♥K♣6♦

Phix

<lang Phix>function fperm(sequence fbn, omega) integer m=0

   for i=1 to length(fbn) do
       integer g = fbn[i]
       if g>0 then
           omega[m+1..m+g+1] = omega[m+g+1]&omega[m+1..m+g]
       end if
       m += 1
   end for
   return omega

end function

function factorial_base_numbers(integer size, bool countOnly) -- translation of Go

   sequence results = {}, res = repeat(0,size)
   integer count = 0, n = 0
   while true do
       integer radix = 2, k = n
       while k>0 do
           if not countOnly
           and radix <= size+1 then
               res[size-radix+2] = mod(k,radix)
           end if
           k = floor(k/radix)
           radix += 1
       end while
       if radix > size+2 then exit end if
       count += 1
       if not countOnly then
           results = append(results, res)
       end if
       n += 1
   end while
   return iff(countOnly?count:results)

end function

sequence fbns = factorial_base_numbers(3,false) for i=1 to length(fbns) do

   printf(1,"%v -> %v\n",{fbns[i],fperm(fbns[i],{0,1,2,3})})

end for printf(1,"\n")

integer count = factorial_base_numbers(10,true) printf(1,"Permutations generated = %d\n", count) printf(1," versus factorial(11) = %d\n", factorial(11))

procedure show_cards(sequence s)

   printf(1,"\n")
   for i=1 to length(s) do
       integer c = s[i]-1
       string sep = iff(mod(i,13)=0 or i=length(s)?"\n":" ")
       puts(1,"AKQJT98765432"[mod(c,13)+1]&"SHDC"[floor(c/13)+1]&sep)
   end for

end procedure

function rand_fbn51()

   sequence fbn51 = repeat(0,51)
   for i=1 to 51 do
       fbn51[i] = rand(52-i)
   end for
   return fbn51

end function

sequence fbn51s = {{39,49, 7,47,29,30, 2,12,10, 3,29,37,33,17,12,31,29,

                   34,17,25, 2, 4,25, 4, 1,14,20, 6,21,18, 1, 1, 1, 4,
                    0, 5,15,12, 4, 3,10,10, 9, 1, 6, 5, 5, 3, 0, 0, 0},
                  {51,48,16,22, 3, 0,19,34,29, 1,36,30,12,32,12,29,30,
                   26,14,21, 8,12, 1, 3,10, 4, 7,17, 6,21, 8,12,15,15,
                   13,15, 7, 3,12,11, 9, 5, 5, 6, 6, 3, 4, 0, 3, 2, 1},
                  rand_fbn51()}

for i=1 to length(fbn51s) do

   show_cards(fperm(fbn51s[i],tagset(52)))

end for</lang>

Output:
{0,0,0} -> {0,1,2,3}
{0,0,1} -> {0,1,3,2}
{0,1,0} -> {0,2,1,3}
{0,1,1} -> {0,2,3,1}
{0,2,0} -> {0,3,1,2}
{0,2,1} -> {0,3,2,1}
{1,0,0} -> {1,0,2,3}
{1,0,1} -> {1,0,3,2}
{1,1,0} -> {1,2,0,3}
{1,1,1} -> {1,2,3,0}
{1,2,0} -> {1,3,0,2}
{1,2,1} -> {1,3,2,0}
{2,0,0} -> {2,0,1,3}
{2,0,1} -> {2,0,3,1}
{2,1,0} -> {2,1,0,3}
{2,1,1} -> {2,1,3,0}
{2,2,0} -> {2,3,0,1}
{2,2,1} -> {2,3,1,0}
{3,0,0} -> {3,0,1,2}
{3,0,1} -> {3,0,2,1}
{3,1,0} -> {3,1,0,2}
{3,1,1} -> {3,1,2,0}
{3,2,0} -> {3,2,0,1}
{3,2,1} -> {3,2,1,0}

Permutations generated = 39916800
  versus factorial(11) = 39916800

AC 3C 7S 4C TD 8D QS KH 2S TS 4D 7C JC
5H TH TC KC 2C 3H 5D JS 6S QC 5S KS AD
3D QH 8C 6D 9S 8S 4S 9H AS 6H 5C 2D 7H
8H 9C 6C 7D AH JD QD 9D 2H 3S JH 4H KD

2C 5C JH 4H JS AS 5H AC 6D QS 9C 3D QH
JC TH KC TC 5D 7H TD 3S 8H TS 7S 6H 5S
KH 4D AH 4C 2H 9D QC 8C 7D 6C 3H 6S 7C
2D JD 9H AD QD 8D 4S KD KS 3C 2S 8S 9S

JS 4H JD 9H 2C 9C 3C KH 9S TH 6D 5S 3H
2H 3S JH 5H QD 4C 7D 4S QC 7C TS 5C 6H
KS 5D QH 2S AD AC 7S QS TC JC 7H 6C 8H
KC 9D 4D 8D KD 6S TD AH 8C 2D 8S 3D AS

zkl

<lang zkl>fcn fpermute(omega,num){ // eg (0,1,2,3), (0,0,0)..(3,2,1)

  omega=omega.copy(); 	  // omega gonna be mutated
  foreach m,g in ([0..].zip(num)){ if(g) omega.insert(m,omega.pop(m+g)) }
  omega

}</lang>

Part 1, Generate permutation table:

<lang zkl>foreach a,b,c in (4,3,2){

  println("%d.%d.%d --> %s".fmt(a,b,c, fpermute(T(0,1,2,3),T(a,b,c)).concat()));

}</lang>

Output:
0.0.0 --> 0123
0.0.1 --> 0132
0.1.0 --> 0213
0.1.1 --> 0231
0.2.0 --> 0312
0.2.1 --> 0321
1.0.0 --> 1023
1.0.1 --> 1032
1.1.0 --> 1203
1.1.1 --> 1230
1.2.0 --> 1302
1.2.1 --> 1320
2.0.0 --> 2013
2.0.1 --> 2031
2.1.0 --> 2103
2.1.1 --> 2130
2.2.0 --> 2301
2.2.1 --> 2310
3.0.0 --> 3012
3.0.1 --> 3021
3.1.0 --> 3102
3.1.1 --> 3120
3.2.0 --> 3201
3.2.1 --> 3210
Part 3, Generate the given task shuffles:

<lang zkl>deck:=List(); foreach s,c in ("\u2660 \u2665 \u2666 \u2663".split(),

               "A K Q J 10 9 8 7 6 5 4 3 2".split()){ deck.append(c+s) }

books:=List(

  "39.49.7.47.29.30.2.12.10.3.29.37.33.17.12.31.29.34.17.25.2.4.25.4.1.14.20.6.21.18.1.1.1.4.0.5.15.12.4.3.10.10.9.1.6.5.5.3.0.0.0",
  "51.48.16.22.3.0.19.34.29.1.36.30.12.32.12.29.30.26.14.21.8.12.1.3.10.4.7.17.6.21.8.12.15.15.13.15.7.3.12.11.9.5.5.6.6.3.4.0.3.2.1")
  .apply(fcn(s){ s.split(".").apply("toInt") });

foreach book in (books){ println(fpermute(deck,book).concat("")); }</lang>

Output:
A♣3♣7♠4♣10♦8♦Q♠K♥2♠10♠4♦7♣J♣5♥10♥10♣K♣2♣3♥5♦J♠6♠Q♣5♠K♠A♦3♦Q♥8♣6♦9♠8♠4♠9♥A♠6♥5♣2♦7♥8♥9♣6♣7♦A♥J♦Q♦9♦2♥3♠J♥4♥K♦
2♣5♣J♥4♥J♠A♠5♥A♣6♦Q♠9♣3♦Q♥J♣10♥K♣10♣5♦7♥10♦3♠8♥10♠7♠6♥5♠K♥4♦A♥4♣2♥9♦Q♣8♣7♦6♣3♥6♠7♣2♦J♦9♥A♦Q♦8♦4♠K♦K♠3♣2♠8♠9♠
Part 4, Generate a random shuffle:

<lang zkl>r:=[52..2,-1].pump(List,(0).random); println(r.concat("."),"\n",fpermute(deck,r).concat(""));</lang>

Output:
36.21.48.31.19.37.16.39.43.1.27.23.30.22.14.32.31.2.27.11.5.24.28.20.23.20.17.19.23.13.11.12.3.12.1.0.11.1.8.10.6.2.8.3.7.1.1.4.2.2.1
4♦6♥3♣8♦8♥Q♣J♥8♣2♣K♠9♦K♦2♦A♦Q♥9♣10♣J♠A♣A♥7♠3♦5♣10♦K♣7♦2♥6♦4♣7♥10♥5♥9♠3♥Q♠A♠J♦8♠4♥J♣K♥5♠7♣3♠6♣6♠4♠5♦9♥Q♦2♠10♠