If you like cryptography and playing cards, have also a look at the kata [Card-Chameleon, a Cipher with Playing cards](http://www.codewars.com/kata/card-chameleon-a-cipher-with-playing-cards).



As a secret agent, you need a method to transmit a message to another secret agent. But an encrypted text written on a notebook will be suspicious if you get caught. A simple deck of playing cards, however, is everything but suspicious...

With a deck of 52 playing cards, there are `52!` different possible permutations to order it. And `52!` is equal to `80658175170943878571660636856403766975289505440883277824000000000000`. That's a number with [68 digits](https://www.wolframalpha.com/input/?i=52!)!

There are so many different possible permutations, we can affirm that if you shuffle the cards well and put them back together to form a deck, you are the first one in history to get this particular order. The number of possible permutations in a deck of cards is higher than the estimated number of atoms in planet Earth (which is a number with about [50 digits](https://www.wolframalpha.com/input/?i=number+of+atoms+in+earth)).

With a way to associate a permutation of the cards to a sequence of characters, we can hide a message in the deck by ordering it correctly.

---

# Correspondence between message and permutation

## Message

To compose our message, we will use an alphabet containing 27 characters: the space and the letters from A to Z. We give them the following values:

`" " = 0, A = 1, B = 2, ..., Z = 26`

We now have a [numeral system](https://en.wikipedia.org/wiki/Numeral_system) with a base equal to 27. We can compute a numeric value corresponding to any message:

`"A " = 27`
`"AA" = 28`
`"AB" = 29`
`"ABC" = 786`
etc.

## Permutation

Now we need a way to attribute a unique number to each of the possible [permutations](https://en.wikipedia.org/wiki/Permutation) of our deck of playing cards.

There are few methods to [enumerate permutations](https://en.wikipedia.org/wiki/Permutation#Algorithms_to_generate_permutations) and [assign a number](https://en.wikipedia.org/wiki/Permutation#Numbering_permutations) to each of them, we will use the [lexicographical order](https://en.wikipedia.org/wiki/Lexicographical_order). With three cards, A, B, and C, as an example, it gives:

`ABC = 0`
`ACB = 1`
`BAC = 2`
`BCA = 3`
`CAB = 4`
`CBA = 5`

So the first arrangement is ABC, and the last one is CBA. With our 52 playing cards – ranks sorted from the Ace to the King, and suits in alphabetical order (Clubs, Diamonds, Hearts, Spades) – the first arrangement (number `0`) is:



and the last one (number `52! - 1`) is:



To transmit a message, we will compute the permutation for which the unique number is the numeric value of the message.

---

# Your task

Write two functions:

* ```python
encode(message)
```
```if:java
Which takes a message as argument and returns a deck of playing cards ordered to hide the message (or `null` if the message contains invalid characters or has a numeric value greater than or equal to `52!`).
```
```if:python
Which takes a String containing a message, and returns an array of Strings representing a deck of playing cards ordered to hide the message (or `None` if the message contains invalid characters or has a numeric value greater than or equal to `52!`).
```
```if:elixir
Which takes a string containing a message, and returns a list of strings representing a deck of playing cards ordered to hide the message (or `nil` if the message contains invalid characters or has a numeric value greater than or equal to `52!`).
```

* ```python
decode(deck)
```
```if:java
Which takes a deck of playing cards as argument and returns the message hidden inside (or `null` if the deck contains invalid cards, more than one time a single card, or doesn't contain 52 cards).
```
```if:python
Which takes an array of Strings representing a deck of playing cards, and returns the message that is hidden inside (or `None` if the deck contains invalid cards, more than one time a single card, or doesn't contain 52 cards).
```
```if:elixir
Which takes a list of strings representing a deck of playing cards, and returns the message that is hidden inside (or `nil` if the deck contains invalid cards, more than one time a single card, or doesn't contain 52 cards).
```

Each card name, in a deck, is written with a two characters String: the rank followed by the suit. So the first arrangement of the deck is represented like:

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

For your convenience, a preloaded method allows you to easily print a deck to the output:

```python
printDeck(deck, unicode)
```

The first argument is the deck to print, the second one is a boolean value allowing you to choose between simple text or Unicode display. (For Unicode, you need to have a font, on your system, that contains the playing cards Unicode characters.)

---

# Examples

## Encoding

```python
playingCards.encode("ATTACK TONIGHT ON CODEWARS")
```

should return an array of 52 Strings containing:

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

## Decoding

```python
playingCards.decode([
    "AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "TC", "JC", "QC", "KC",
    "AD", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D", "TD", "JD", "QD", "KD",
    "AH", "2H", "3H", "4H", "8H", "9S", "3S", "2S", "8S", "TS", "QS", "9H", "7H",
    "KH", "AS", "JH", "4S", "KS", "JS", "5S", "TH", "7S", "6S", "5H", "QH", "6H"
])
```

should return a String containing:

```python
"ATTACK APPROVED"
```

---

# Further readings

## Logarithm

With the logarithm function, we can know how many digits, in a numeral system of a certain base, are needed to represent a number. For example, `log base 2 of 52! = 225.58`, so we can store 225 bits of information in a deck of cards (and 226 bits are needed to represent the value of `52!`). Also, `log base 27 of 52! = 47.44`, so we can store [47](https://www.wolframalpha.com/input/?i=log+base+27+of+52!) characters of our alphabet in a deck of cards (and some message with 48 characters, but not all of them).

Difficulty: interview

Starter code:

def encode(self, message):
	

Solutions:
from math import factorial as fac
cards = [
    "AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "TC", "JC", "QC", "KC",
    "AD", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D", "TD", "JD", "QD", "KD",
    "AH", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H", "TH", "JH", "QH", "KH",
    "AS", "2S", "3S", "4S", "5S", "6S", "7S", "8S", "9S", "TS", "JS", "QS", "KS"
]
chars = ' ABCDEFGHIJKLMNOPQRSTUVWXYZ'
chars_len = len(chars)
facs = [1]
for x in range(1, 53, 1): facs.append(facs[-1] * x)

class PlayingCards:
    # Takes a String containing a message, and returns an array of Strings representing
    # a deck of playing cards ordered to hide the message, or None if the message is invalid.
    def encode(self, message):
        mlen = len(message)
        rem = 0
        for i in range(mlen):
            if message[i] not in chars: return None
            rem = rem + chars_len ** (mlen - i - 1) * chars.index(message[i])
        if rem >= facs[-1]: return None
        for i in range(1, 53):
            if rem < facs[i]: break
        remaining_cards = cards[53 - i - 1:]
        output_cards = cards[:53 - i - 1]
        for j in range(i - 1, -1, -1):
            idx = rem // facs[j]
            output_cards.append(remaining_cards.pop(idx))
            rem = rem % facs[j]
        return output_cards

    # Takes an array of Strings representing a deck of playing cards, and returns
    # the message that is hidden inside, or None if the deck is invalid.
    def decode(self, deck):
        if len(deck) != 52: return None
        remaining_cards = cards.copy()
        rem = 0
        for i in range(len(deck)):
            if deck[i] not in remaining_cards: return None
            idx = remaining_cards.index(deck[i])
            rem = rem + facs[51 - i] * idx
            remaining_cards.pop(idx)
        output_message = []
        if rem == 0 : return ''
        while rem > 0:
            output_message.insert(0, chars[rem % chars_len])
            rem = rem // chars_len
        return ''.join(output_message)

import math
class PlayingCards:
    # Takes a String containing a message, and returns an array of Strings representing
    # a deck of playing cards ordered to hide the message, or None if the message is invalid.
    def encode(self, message):
        list_char = list(' ABCDEFGHIJKLMNOPQRSTUVWXYZ')
        list_card_val = list('A23456789TJQK')
        list_card_col = list('CDHS')
        list_card0 = [val+col for col in list_card_col for val in list_card_val ]
        
        for c in message:
            if c not in list_char:
                return None
        sort_list_message = list(message)
        sort_list_message.sort()
        
        n = 0
        list_ind = []
        for ii, c in enumerate(message):
            ind = list_char.index(c)
            n += ind*(27**(len(message)-1-ii))
        #print(n)
        
        if n>= math.factorial(52):
            return None
        dec = []
        n2 = n
        for ii in range(51,0,-1):
            n_i, n2 = n2//math.factorial(ii), n2%math.factorial(ii)
            dec.append(n_i)
        dec.append(0)
        
        list_card = list_card0.copy()
        deck_code = []
        for ii in dec:
            deck_code.append(list_card[ii])
            list_card.remove(list_card[ii])
        return deck_code

    # Takes an array of Strings representing a deck of playing cards, and returns
    # the message that is hidden inside, or None if the deck is invalid.
    def decode(self, deck):
        list_char = list(' ABCDEFGHIJKLMNOPQRSTUVWXYZ')
        list_card_val = list('A23456789TJQK')
        list_card_col = list('CDHS')
        list_card0 = [val+col for col in list_card_col for val in list_card_val ]
        
        #printDeck(deck, False)
        
        test_deck = list(set(deck))
        test_deck.sort()
        test_list_card0 = list_card0.copy()
        test_list_card0.sort()
        if test_deck != test_list_card0:
            return None
            
        list_card = list_card0.copy()
        n = 0
        for ii, c in enumerate(deck[:-1]):
            ind = list_card.index(c)
            if ind > 0:
                n += (ind)*math.factorial(len(deck)-1-ii)
            list_card.remove(c)
        #print(n)
        
        n2 = n
        if n == 0:
            return ''
        dec = []
        nchar = math.floor(math.log10(n)/math.log10(27))
        for ii in range(nchar,0,-1):
            n_i, n2 = n2//27**ii, n2%27**ii
            dec.append(n_i)
        dec.append(n2)
        
        message = "".join([list_char[ii] for ii in dec])
        return message


import string


class PlayingCards:
    CHARSET = " " + string.ascii_uppercase
    DECK = [card + suit for suit in "CDHS" for card in "A23456789TJQK"]
    DECKSIZE = len(DECK)
    MAX_FACT = 80658175170943878571660636856403766975289505440883277824000000000000 # 52!

    def encode(self, msg: string):
        # validate input
        if any(c not in self.CHARSET for c in msg):
            return None

        # calculate desired permutation index from input message
        perm_index = sum(self.CHARSET.index(c) * pow(27, i) for i, c in enumerate(reversed(msg)))
        if perm_index >= self.MAX_FACT:
            # index too large, invalid input
            return None

        # calculate factoradic (factorial representation)
        frep = []
        i = 0
        while perm_index:
            i += 1
            frep.append(perm_index % i)
            perm_index = perm_index // i
        frep.reverse()

        # return deck permutation 
        left_part = self.DECK[: self.DECKSIZE - len(frep)]
        right_part = self.DECK[self.DECKSIZE - len(frep) :]
        return left_part + [right_part.pop(pos) for pos in frep]


    def decode(self, input_deck: list):
        # validate input
        if any(card not in self.DECK for card in input_deck) or len(set(input_deck)) != self.DECKSIZE:
            return None
        
        # find permutation index of input deck
        j = 0
        perm_index = 0
        while j < self.DECKSIZE:
            i = 1
            factor = 1
            while i < self.DECKSIZE - j:
                factor *= i
                i += 1
            i = 0
            index = self.DECK.index(input_deck[j])
            while i < j:
                if self.DECK.index(input_deck[i]) < self.DECK.index(input_deck[j]):
                    index -= 1
                i += 1
            perm_index += index * factor
            j += 1

        # convert deck permutation index to message
        message = ''
        i = 0
        while perm_index:
            i += 1
            message = self.CHARSET[perm_index % 27] + message
            perm_index = perm_index // 27
        return message


import math
import numpy as np
d = {
            " ":0,
            "A":1,
            "B":2,
            "C":3,
            "D":4,
            "E":5,
            "F":6,
            "G":7,
            "H":8,
            "I":9,
            "J":"A",
            "K":"B",
            "L":"C",
            "M":"D",
            "N":"E",
            "O":"F",
            "P":"G",
            "Q":"H",
            "R":"I",
            "S":"J",
            "T":"K",
            "U":"L",
            "V":"M",
            "W":"N",
            "X":"O",
            "Y":"P",
            "Z":"Q"

            }

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

class PlayingCards:

        def encode(self, message):

            if message == "":
                message = " "
                
            if len(message) > 52:
                return None
            
            meslis = [str(x) for x in message]
            for i in range(len(meslis)):
                if meslis[i] in d:
                    None
                else:
                    return None   
            
            bnum = "".join([str(d[x]) for x in message])
            num = int(bnum,27)
            if num >= math.factorial(52):
                return None

            
            fact = []
            for j in range(1,53):
                fact.insert(0,num%j)
                num = int(num // j)
            
            
            final = ["#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#"
            ,"#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#"
            ,"#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#"
            ,"#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#"]
            
    
            s_deckc = s_deck.copy()
    
    
            for v in range(0,52):
                final[v]=s_deckc[fact[v]]
                del s_deckc[fact[v]]


            return final
    

        def decode(self,deck):
            
            
            s_deckc = s_deck.copy()
            
            
            if len(deck)!=52:
                return None

            dfact = []
            numb=0           
            for i in range(52):
                if deck[i] in s_deckc:
                    None
                else:
                    return None  
                fact = int(s_deckc.index(deck[i]))
                del s_deckc[fact]
                numb += fact * math.factorial(51-i)
            
            if numb == 0:
                return ""
            
            basetws = np.base_repr(numb, base=27) 
            btws_list = [str(x) for x in basetws]
            r_d = {str(value) : str(key) for (key, value) in d.items()}

            word = []
    
            for i in range(len(btws_list)):
                word.append(r_d[btws_list[i]])
            return "".join(word)     

class PlayingCards:
    
    def __init__(self):
        self.alphabet = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        self.factorials = [1]
        self.deck = ["AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "TC", "JC", "QC", "KC",
                     "AD", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D", "TD", "JD", "QD", "KD",
                     "AH", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H", "TH", "JH", "QH", "KH",
                     "AS", "2S", "3S", "4S", "5S", "6S", "7S", "8S", "9S", "TS", "JS", "QS", "KS"]
        
        for i in range(1, 52): self.factorials.append(self.factorials[-1] * i)
    
    def encode(self, message):
        code = self.numeral(message)
        copy = self.deck.copy()
        facts = self.factorials.copy()
        encrypted = []
        
        for letter in message:
            if letter not in self.alphabet: return None
            else: pass

        if code > (self.factorials[-1] * 52) - 1: return None
        
        for i in range(len(self.deck)):
            x, code = divmod(code, facts.pop())
            encrypted.append(copy[x])
            copy.remove(copy[x])
            
        return encrypted

    def decode(self, deck):
        copy = self.deck.copy()
        facts = self.factorials.copy()
        row = 0
        
        for i in range(len(self.deck)):
            try:
                if deck[i] in copy:
                    x = copy.index(deck[i])
                    row += facts.pop()*x
                    copy.remove(deck[i])
                else: return None
            except: return None
            
        message = self.string(int(row), 27)
        if message == " ": return ''
        else: return message 
    
    @staticmethod
    def numeral(string):
        return sum([((27**i)*(ord(char)-64)) for i,char in enumerate(string.replace(" ", "@")[::-1])])
    
    def string(self, n, base):
        if n < base:
            return self.alphabet[n]
        else:
            return self.string(n//base,base) + self.alphabet[n%base]

import itertools as it
import math
import string

class PlayingCards:

    def __init__(self):
        self.cards = ['AC', '2C', '3C', '4C', '5C', '6C', '7C', '8C', '9C', 'TC', 'JC', 'QC', 'KC', 'AD', '2D', '3D', '4D', '5D', '6D', '7D', '8D', '9D', 'TD', 'JD', 'QD', 'KD', 'AH', '2H', '3H', '4H', '5H', '6H', '7H', '8H', '9H', 'TH', 'JH', 'QH', 'KH', 'AS', '2S', '3S', '4S', '5S', '6S', '7S', '8S', '9S', 'TS', 'JS', 'QS', 'KS']
        self.alphabet = [' '] + [letter for letter in string.ascii_uppercase]

    def message_to_cypher_value(self, clear_string):
        alphabet_size = len(self.alphabet)
        output = 0
        for letter in clear_string:
            output = output * alphabet_size + self.alphabet.index(letter)
        return output
    
    # Takes a String containing a message, and returns an array of Strings representing
    # a deck of playing cards ordered to hide the message, or None if the message is invalid.
    def encode(self, message):
        for letter in message:
            if letter not in self.alphabet:
                return None
        remaining_cards = list(self.cards)
        n = self.message_to_cypher_value(message)
        if n > math.factorial(52)-1:
            return None
        output = []
        while remaining_cards:
            permutations_per_card = math.factorial(len(remaining_cards)) // len(remaining_cards)
            current_index = n // permutations_per_card
            output.append(remaining_cards.pop(current_index))
            n -= current_index * permutations_per_card
        return output

    
    def deck_to_cypher_value(self, deck):
        remaining_cards = list(self.cards)
        output = 0
        for card in deck:
            permutations_per_card = math.factorial(len(remaining_cards)) // len(remaining_cards)
            current_index = remaining_cards.index(card)
            output += current_index * permutations_per_card
            remaining_cards.pop(current_index)
        return output
    
    # Takes an array of Strings representing a deck of playing cards, and returns
    # the message that is hidden inside, or None if the deck is invalid.
    def decode(self, deck):
        printDeck(deck, False)
        if len(deck) > len(self.cards):
            return None
        if len(set(deck)) < len(self.cards):
            return None
        for card in deck:
            if not card in self.cards:
                return None
        n = self.deck_to_cypher_value(deck)
        alphabet_size = len(self.alphabet)
        output = []
        while n > 0:
            output.append(n % alphabet_size)
            n = (n - output[-1])//alphabet_size
        return ''.join([self.alphabet[x] for x in output[::-1]])


from math import factorial
stack = [
    "AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "TC", "JC", "QC", "KC",
    "AD", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D", "TD", "JD", "QD", "KD",
    "AH", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H", "TH", "JH", "QH", "KH",
    "AS", "2S", "3S", "4S", "5S", "6S", "7S", "8S", "9S", "TS", "JS", "QS", "KS"
]
numeral = ' ABCDEFGHIJKLMNOPQRSTUVWXYZ'
class PlayingCards:
    def encode(self, message):
        tom,tim,s,deck,new = [],1,0, stack.copy(),[]
        try: 
            for i,x in enumerate(message): s += numeral.index(x) * len(numeral) ** (len(message)-i-1)
        except ValueError: return None
        while s>=1:
            tom.insert(0,s%tim)
            s = s//tim
            tim += 1
        if len(tom) >52: return None
        while len(tom)!= 52:tom.insert(0,0)
        for x in tom:
            new.append(deck[x])
            deck.remove(deck[x])
        return new

    def decode(self, new):
        yo,haha,plus,deck = [],0,[],stack.copy()
        if len(new) != 52: return None
        try:
            while new:
                if yo or deck.index(new[0]) != 0: yo.append(deck.index(new[0]))
                deck.remove(new[0])
                new.remove(new[0])
        except ValueError: return None
        for i,x in enumerate(yo): haha += x * factorial(len(yo) - i - 1)
        for x in range(100000000):
            if (27**x) > haha: break    
        for e in reversed(range(x)):
            for b in range(27):
                if (b + 1) * (27**e) > haha:
                    haha -= b*(27**e)
                    plus.append(b)
                    break
        return ''.join([numeral[x] for x in plus])

from math import factorial

class PlayingCards:    
    
    def __init__(self):
        
        self.chars = ' ABCDEFGHIJKLMNOPQRSTUVWXYZ'
        
        self.ranks = 'A23456789TJQK'
        self.suits = 'CDHS'
        self.cards = [rank + suit for suit in self.suits for rank in self.ranks]

    def encode(self, message):

        if any(ch not in self.chars for ch in message):
            return None
        
        char_vals = {v: i for i, v in enumerate(self.chars)}
        perm_ind = sum(int(self.n_to_base_27(char_vals[ch])*27**(len(message) - i - 1)) for i, ch in enumerate(message))
        
        if perm_ind >= factorial(52):
            return None
        
        return self.card_permutation(perm_ind)
    
    def decode(self, deck):
      
        if not all(card in self.cards for card in deck) or len(set(deck)) != 52:
            return None
        
        val_chars = {i: v for i, v in enumerate(self.chars)}
        lex_index = 0

        for i in range(len(deck)):
            s = 0
            for j, v in enumerate(deck[i + 1:]):
                if self.cards.index(v) < self.cards.index(deck[i]):
                    s += 1 
            lex_index += s*factorial(len(deck) - i - 1) 
            
        char_arr = []
        while lex_index:
            lex_index, i = divmod(lex_index, 27)
            char_arr.append(val_chars[i])
            
        return ''.join(char_arr[::-1])
    
    @staticmethod
    def n_to_base_27(n):
        
        if n == 0:
            return 0
        d = []
        while n:
            d.append(n%27)
            n //= 27
        return int(''.join(map(str, d[::-1])))

    def card_permutation(self, k):
        
        factorial_arr = [1]
        for i in range(2, 52):
            factorial_arr.append(factorial_arr[-1] * i)

        permutation = []
        res = list(range(52))

        while factorial_arr:
            factorial = factorial_arr.pop()
            n, k = divmod(k, factorial)
            permutation.append(res[n])
            res.remove(res[n])
        permutation.append(res[0])

        return [self.cards[i] for i in permutation]

class PlayingCards:
    CARDS=['AC', '2C', '3C', '4C', '5C', '6C', '7C', '8C', '9C', 'TC', 'JC', 'QC', 'KC',
            'AD', '2D', '3D', '4D', '5D', '6D', '7D', '8D', '9D', 'TD', 'JD', 'QD', 'KD',
            'AH', '2H', '3H', '4H', '5H', '6H', '7H', '8H', '9H', 'TH', 'JH', 'QH', 'KH',
            'AS', '2S', '3S', '4S', '5S', '6S', '7S', '8S', '9S', 'TS', 'JS', 'QS', 'KS']
    S=len(CARDS)
    
    def __init__(self):
        self.f=[0]*self.S
        self.f[0]=1
        for k in range(1,self.S):
            self.f[k]=self.f[k-1]*k
            
        self.CARD_index={c:self.CARDS.index(c)for c in self.CARDS}
        
    def baseEncode(self,s):
        r=0
        for c in s:
            r*=27
            r+=ord(c)%32
        return r

    def baseDecode(self,n):
        s=''
        while n:
            n,c=divmod(n,27)
            s=(chr(64+c)if c else' ')+s
        return s
    
    def permute(self,n):
        S=52
        p=[0]*S
        for k in range(S):
            p[k],n=divmod(n,self.f[S-1-k])
        for k in range(S-1,0,-1):
            for j in range(k-1,-1,-1):
                if p[j]<=p[k]:
                    p[k]+=1
        return [self.CARDS[i]for i in p]
        
    # Takes a String containing a message, and returns an array of Strings representing
    # a deck of playing cards ordered to hide the message, or None if the message is invalid.
    def encode(self, message):
        if not all(c==' 'or 'A'<=c<='Z' for c in message):return
        n=self.baseEncode(message)
        if n>=80658175170943878571660636856403766975289505440883277824000000000000:return
        p=self.permute(n)
        return p

    # Takes an array of Strings representing a deck of playing cards, and returns
    # the message that is hidden inside, or None if the deck is invalid.
    def decode(self, deck):
        if set(deck)!=set(self.CARDS):return
        
        i,j=0,1
        perm=[self.CARD_index[c]for c in deck]
        for p in range(50,-1,-1):
            s=0
            for q in range(p+1,52):
                if perm[p]>perm[q]:s+=1
            i+=s*self.f[j]
            j+=1
        return self.baseDecode(i)


class PlayingCards:
    codex = tuple(n+suit for suit in 'CDHS' for n in 'A23456789TJQK')
    ix = ' ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    xi = {ch:i for i,ch in enumerate(ix)}
    
    @staticmethod
    def encode(s):
        q = 0
        tiers = PlayingCards.get_tiers()
        for ch in s:
            if ch not in PlayingCards.xi: return
            q *= 27
            q += PlayingCards.xi[ch]
        if q >= 52*tiers[0]: return
        for i,x in enumerate(tiers):
            if q >= x: break
        codex = list(PlayingCards.codex[:i])
        cdx = list(PlayingCards.codex[i:])
        for n in tiers[i:]:
            v = q // n
            q %= n
            codex.append(cdx.pop(v))
        return codex + cdx
    
    @staticmethod
    def decode(r):
        if set(r) != set(PlayingCards.codex): return
        q = 0
        tiers = PlayingCards.get_tiers()
        for i,card in enumerate(r):
            if card != PlayingCards.codex[i]: break
        tiers = tiers[i:]
        cdx = list(PlayingCards.codex[i:])
        for card,tier in zip(r[i:],tiers):
            j = cdx.index(card)
            q += j * tier
            cdx.pop(j)
        s = ''
        while q:
            v = q % 27
            q //= 27
            s += PlayingCards.ix[v]
        return s[::-1]
    
    @staticmethod
    def get_tiers():
        r = []
        c = 1
        for i in range(1,52):
            c *= i
            r.append(c)
        return r[::-1]