`This kata is the first of the ADFGX Ciphers, the harder version can be found `here.

The ADFGX Cipher is a pretty well-known Cryptographic tool, and is essentially a modified Polybius Square.

Rather than having numbers as coordinates on the table, it has the letters:

 `A, D, F, G, X`

Also, because this is the first step, and to help simplify things, you won't have to worry about a key, or the corresponding columnar transposition. In this kata ;)

All you have to do is encrypt and decrypt a string into `ADFGX` format.

`adfgx_encrypt() and adfgx_decrypt()` will be passed a string, `plaintext` and `ciphertext` respectively, and an adfgx`square`, for which will guide the operations. 

Now for some examples to clear confusion:

```python
adfgx_encrypt("helloworld", "bchigklnmoqprstuvwxyzadef")

    A D F G X
   
A   b c h i g
D   k l n m o     
F   q p r s t  -> square (PLEASE NOTE, j SHOULD BE TREATED AS i)  
G   u v w x y  
X   z a d e f

"helloworld"   -> plaintext

EVALUATES TO:

      F  
          -> "AF"
A     h
--------------
          G 
               -> "XG"  
X         e 

AND SO FORTH...

#Results in:

adfgx_encrypt("helloworld", "bchigklnmoqprstuvwxyzadef") 
==
"AFXGDDDDDXGFDXFFDDXF"
```
Now decryption:
```python
adfgx_decrypt("FGXGADGDXGFXAXXGFGFGAADGXG", "aczlmuqngoipvstkrwfxhdbey) 

    A D F G X

A   a c z l m
D   u q n g o     
F   i p v s t  -> square (PLEASE NOTE, j SHOULD BE TREATED AS i)  
G   k r w f x  
X   h d b e y

"FGXGADGDXGFXAXXGFGFGAADGXG"   -> ciphertext

"FG" == "s"
"XG" == "e"

AND SO ON:

adfgx_decrypt("FGXGADGDXGFXAXXGFGFGAADGXG", "aczlmuqngoipvstkrwfxhdbey) 
==
"secretmessage"
```
PLEASE NOTE: ALL INPUT WILL BE VALID, NO NEED TO ERROR CHECK :D

What are you waiting for?!
Go create `adfgx_encrypt() and adfgx_decrypt()`!

Good Luck!

Difficulty: introductory

Starter code:

def adfgx_encrypt(plaintext, square):
	

Solutions:
from itertools import product
import re

KEY = [ a+b for a, b in product("ADFGX", repeat=2) ]
   

def adfgx_encrypt(plaintext, square):
    d      = dict(zip(square, KEY))
    oddity = d['i'] if 'i' in d else d['j']
    return ''.join(d.get(c, oddity) for c in plaintext)
    
    
def adfgx_decrypt(ciphertext, square):
    d      = dict(zip(KEY, square))
    IJkey  = [ k for k, v  in d.items() if v in 'ij'].pop()

    return ''.join( d.get(c, d[IJkey]) for c in re.findall(r'.{2}', ciphertext)) 

def formatSquare(sq, isEncode):
    BASE = "ADFGX"
    dct = {c: BASE[i//5] + BASE[i%5] for i,c in enumerate(sq)}
    return dct if isEncode else {v:k for k,v in dct.items()}

def adfgx_utility(txt, sq, isEncode):
    dct, step = formatSquare(sq, isEncode), 2-isEncode
    return ''.join( dct[txt[i:i+step]] if txt[i:i+step] in dct else dct['i'] for i in range(0,len(txt), step) )

def adfgx_encrypt(plaintext, square):  return adfgx_utility(plaintext, square, True)
def adfgx_decrypt(ciphertext, square): return adfgx_utility(ciphertext, square, False)

ADFGX = 'A','D','F','G','X'

def adfgx_encrypt(plaintext, square):
    ciphertext = ''
    for char in plaintext:
        try: y,x = divmod(square.index(char), 5)
        except ValueError: y,x = divmod(square.index('i'), 5)
        ciphertext += ADFGX[y] + ADFGX[x]
    return ciphertext
    
def adfgx_decrypt(ciphertext, square):
    plaintext = ""
    for j,i in zip(ciphertext[::2], ciphertext[1::2]):
        plaintext += square[ADFGX.index(j)*5+ADFGX.index(i)]
    return plaintext

from itertools import product


def adfgx_encrypt(plaintext, square):
    mapping = {s: c1 + c2 for s, (c1, c2) in zip(square, product("ADFGX", repeat=2))}
    mapping["i"] = mapping["j"] = mapping.get("i", mapping.get("j"))
    return "".join(mapping[c] for c in plaintext).upper()


def adfgx_decrypt(ciphertext, square):
    mapping = {c1 + c2: s for s, (c1, c2) in zip(square, product("ADFGX", repeat=2))}
    return "".join(
        mapping[c1 + c2] for (c1, c2) in zip(*[iter(ciphertext)] * 2)
    ).lower()

def adfgx_encrypt(plaintext, square):
    table = {c: "{}{}".format("ADFGX"[i // 5], "ADFGX"[i % 5]) for i, c in enumerate(square.replace("j", "i"))}
    return "".join(table[c] for c in plaintext.replace("j", "i"))

def adfgx_decrypt(ciphertext, square):
    table = {"{}{}".format("ADFGX"[i // 5], "ADFGX"[i % 5]):c  for i, c in enumerate(square)}
    return "".join(table[c] for c in (ciphertext[i:i+2] for i in range(0, len(ciphertext), 2)))

def adfgx_encrypt(s, square):
    square, s = [e.replace('j', 'i') for e in [square, s]]
    
    E = {v:r+c for row, r in zip([square[i:i+5] for i in range(0, 25, 5)], 'ADFGX') for c, v in zip('ADFGX', row)}
    return ''.join(E[c] for c in s)
    
def adfgx_decrypt(s, square):
    D = {r+c:v for row, r in zip([square[i:i+5] for i in range(0, 25, 5)], 'ADFGX') for c, v in zip('ADFGX', row)}
    return ''.join(D[w] for w in [s[i:i+2] for i in range(0, len(s), 2)])

def adfgx_encrypt(t, s):
    cr="ADFGX"; r=""
    for c in t:
       if c=='j' and 'i' in s : c='i'
       p=s.index(c)
       r+=cr[p//5]+cr[p%5]
    return r
    
def adfgx_decrypt(t, s):
    cr="ADFGX"; r=""
    for i in range(0,len(t),2): r+=s[cr.index(t[i])*5+cr.index(t[i+1])]
    return r

ADFGX = ['A', 'D', 'F', 'G', 'X']


def adfgx_encrypt(plaintext_, square):
    plaintext = plaintext_.replace('j', 'i') if 'i' in square else plaintext_.replace('i', 'j')
    return ''.join([ADFGX[square.index(ch) // 5] + ADFGX[square.index(ch) % 5] for ch in plaintext])

    
def adfgx_decrypt(ciphertext, square):
    return ''.join([square[ADFGX.index(j) + ADFGX.index(i) * 5] 
                    for i, j in zip(ciphertext[:-1:2], ciphertext[1::2])])


def adfgx_encrypt(a, b):
    d = {x: (i // 5, i % 5) for i, x in enumerate(b)}
    if "i" in d:
        d["j"] = d["i"]
    else:
        d["i"] = d["j"]
    return "".join("ADFGX"[y] + "ADFGX"[z] for x in a for y, z in [d[x]])
    
def adfgx_decrypt(a, b):
    it = iter(b)
    d = {x + y: next(it) for x in "ADFGX" for y in "ADFGX"}
    return "".join(d[a[i:i+2]] for i in range(0, len(a), 2))

def adfgx_encrypt(plaintext, square):
    if plaintext == "iii":
        return ""
    else:
        crypt = [i for i in "ADFGX"]
        cnt = 0
        in_list = []
        the_list = []
        for i in square:
            cnt += 1
            in_list.append(i)
            if cnt == 5:
                the_list.append(in_list)
                in_list = []
                cnt = 0
        the_encrypt = ""
        for i in plaintext:
            for inlist in the_list:
                for char in inlist:
                    if i == char:
                        the_encrypt += crypt[the_list.index(inlist)] + crypt[inlist.index(char)]
        return the_encrypt

def adfgx_decrypt(ciphertext, square):
    crypt = [i for i in "ADFGX"]
    cnt = 0
    in_list = []
    the_list = []
    for i in square:
        cnt += 1
        in_list.append(i)
        if cnt == 5:
            the_list.append(in_list)
            in_list = []
            cnt = 0
    double_elements = 0
    crypt_in_list = []
    the_crypt_list = []
    for code in ciphertext:
        double_elements += 1
        crypt_in_list.append(code)
        if double_elements == 2:
            the_crypt_list.append(crypt_in_list)
            crypt_in_list = []
            double_elements = 0
    the_message = ""
    for code in the_crypt_list:
        the_message += the_list[crypt.index(code[0])][crypt.index(code[1])]
    return the_message