Task: Factorial base numbers indexing permutations of a collection




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

    
    factNums, _ := genFactBaseNums(3, false)
    perms := mapToPerms(factNums)
    for i, fn := range factNums {
        fmt.Printf("%v -> %v\n", join(fn, "."), join(perms[i], ""))
    }

    
    _, count := genFactBaseNums(10, true)
    fmt.Println("\nPermutations generated =", count)
    fmt.Println("compared to 11! which  =", factorial(11))
    fmt.Println()

    
    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")
    }

    
    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()
}




Python: 

import math

def apply_perm(omega,fbn):
    
    for m in range(len(fbn)):
        g = fbn[m]
        if g > 0:
            
            
            new_first = omega[m+g]
            
            omega[m+1:m+g+1] = omega[m:m+g]
            
            omega[m] = new_first
            
    return omega
    
def int_to_fbn(i):
    
    current = i
    divisor = 2
    new_fbn = []
    while current > 0:
        remainder = current % divisor
        current = current // divisor
        new_fbn.append(remainder)
        divisor += 1
    
    return list(reversed(new_fbn))
    
def leading_zeros(l,n):
   
   if len(l) < n:
       return(([0] * (n - len(l))) + l)
   else:
       return l

def get_fbn(n):
    
    max = math.factorial(n)
    
    for i in range(max):
        
        current = i
        divisor = 1
        new_fbn = int_to_fbn(i)
        yield leading_zeros(new_fbn,n-1)
        
def print_write(f, line):
    
    print(line)
    f.write(str(line)+'\n')     
    
def dot_format(l):
    
    
    if len(l) < 1:
        return ""
    
    dot_string = str(l[0])
    
    for e in l[1:]:
        dot_string += "."+str(e)
        
    return dot_string
    
def str_format(l):
    
    if len(l) < 1:
        return ""
        
    new_string = ""
        
    for e in l:
        new_string += str(e)
    
    return new_string 
    
with open("output.html", "w", encoding="utf-8") as f:
    f.write("<pre>\n")
    
    
        
    omega=[0,1,2,3]
    
    four_list = get_fbn(4)
    
    for l in four_list:
        print_write(f,dot_format(l)+' -> '+str_format(apply_perm(omega[:],l)))
        
    print_write(f," ")
    
    
    
    
    
    
        
    num_permutations = 0
    
    for p in get_fbn(11):
        num_permutations += 1
        if num_permutations % 1000000 == 0:
            print_write(f,"permutations so far = "+str(num_permutations))
    
    print_write(f," ")
    print_write(f,"Permutations generated = "+str(num_permutations))
    print_write(f,"compared to 11! which  = "+str(math.factorial(11)))
    
    print_write(f," ")
    
       
    
    
    
    shoe = []
    
    for suit in [u"\u2660",u"\u2665",u"\u2666",u"\u2663"]:
        for value in ['A','K','Q','J','10','9','8','7','6','5','4','3','2']:
            shoe.append(value+suit)
                    
    print_write(f,str_format(shoe))
    
    p1 = [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]
    
    p2 = [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]
    
    print_write(f," ")
    print_write(f,dot_format(p1))
    print_write(f," ")
    print_write(f,str_format(apply_perm(shoe[:],p1)))
    
    print_write(f," ")
    print_write(f,dot_format(p2))
    print_write(f," ")
    print_write(f,str_format(apply_perm(shoe[:],p2)))

    
    
    import random
    
    max = math.factorial(52)
    
    random_int = random.randint(0, max-1)

    myperm = leading_zeros(int_to_fbn(random_int),51)
    
    print(len(myperm))
    
    print_write(f," ")
    print_write(f,dot_format(myperm))
    print_write(f," ")
    print_write(f,str_format(apply_perm(shoe[:],myperm)))

    f.write("</pre>\n")