1

I've been struggling in creating the vigenere table in python That should be the result:

Vigenère Cypher Table

So basically I have the entire alphabet on the first line, and the alphabet shifted by one letter on the second one etc.

That's my code so far:

class CypherTable:

    def __init__(self):
        self.matrix = [[chr(i) for i in range(ord('a'),ord('z')+1)] for i in range(5)]

    def __str__(self):
        for i in range(len(self.matrix)):
            print self.matrix[i]
        return ""

table = CypherTable()
print(table)

I managed to print letters from a to z a number of times but I don't know how to modify each interaction in order to shift the first letter by one. I'm used to work in java where you first define the array length and then populate it, but since python has a faster syntax I can't figure out what's the best way to do it.

ekhumoro
  • 98,079
  • 17
  • 183
  • 279
Alex
  • 73
  • 7

2 Answers2

3

A simpler way is to use the string module:

from string import ascii_uppercase as l

class CypherTable:
   def __init__(self):
      self.final_table = [l[i:]+l[:i] for i in range(len(l))]

for i in CypherTable().final_table:
    print(i)

Output:

ABCDEFGHIJKLMNOPQRSTUVWXYZ
BCDEFGHIJKLMNOPQRSTUVWXYZA
CDEFGHIJKLMNOPQRSTUVWXYZAB
DEFGHIJKLMNOPQRSTUVWXYZABC
EFGHIJKLMNOPQRSTUVWXYZABCD
FGHIJKLMNOPQRSTUVWXYZABCDE
GHIJKLMNOPQRSTUVWXYZABCDEF
HIJKLMNOPQRSTUVWXYZABCDEFG
IJKLMNOPQRSTUVWXYZABCDEFGH
JKLMNOPQRSTUVWXYZABCDEFGHI
KLMNOPQRSTUVWXYZABCDEFGHIJ
LMNOPQRSTUVWXYZABCDEFGHIJK
MNOPQRSTUVWXYZABCDEFGHIJKL
NOPQRSTUVWXYZABCDEFGHIJKLM
OPQRSTUVWXYZABCDEFGHIJKLMN
PQRSTUVWXYZABCDEFGHIJKLMNO
QRSTUVWXYZABCDEFGHIJKLMNOP
RSTUVWXYZABCDEFGHIJKLMNOPQ
STUVWXYZABCDEFGHIJKLMNOPQR
TUVWXYZABCDEFGHIJKLMNOPQRS
UVWXYZABCDEFGHIJKLMNOPQRST
VWXYZABCDEFGHIJKLMNOPQRSTU
WXYZABCDEFGHIJKLMNOPQRSTUV
XYZABCDEFGHIJKLMNOPQRSTUVW
YZABCDEFGHIJKLMNOPQRSTUVWX
ZABCDEFGHIJKLMNOPQRSTUVWXY

To be even cleaner, particularly if you will not be declaring any other methods in the class, you can use @classmethod:

from string import ascii_uppercase as l
class CypherTable:
    final_table = [l[i:]+l[:i] for i in range(len(l))]
    @classmethod
    def show_board(cls):
        for i in cls.final_table:
           print(i)

CypherTable.show_board()

Regarding your recent comment, you can try this:

from string import ascii_uppercase as l
class CypherTable:
   def __init__(self):
      self.final_table = [l[i:]+l[:i] for i in range(len(l))]
   def cross(self, b, a):
       val1 = self.final_table[0].index(a)
       new_letter = [i for i in self.final_table if i[0] == b][0][val1]
       return new_letter

c = CypherTable()
print(c.cross('P', 'C'))

Output:

'R'
Ajax1234
  • 58,711
  • 7
  • 46
  • 83
  • Sorry I probably didn't quite explained myself very well That seems like a one-dimension list, I should be able to access those elements therefore in order to find the correspondent letter between two letters Eg. P and C crosses in R, so I should be able to to [indexOfP][indexOfC] – Alex Nov 18 '17 at 18:00
  • @Alex no problem, please see my recent edit and let me know if it works for you. – Ajax1234 Nov 18 '17 at 18:07
  • Perfectly working thank you very much! I can't really understand the algorithm you've used in the cross method although – Alex Nov 18 '17 at 18:11
  • @Alex first, the method takes the first line of the `final_table`, which is the "header" and finds the index of the second variable passed to the method. Then, `final_table` is iterated over to find the line that starts with the first value passed to the method. From there, the element from the list is accessed via indexing, and the index of the second variable, stored in `val1` is accessed, which is the crossed value. – Ajax1234 Nov 18 '17 at 18:15
  • That was very clever, great! That kinda emulates taking a value using two indexes in java like [ i ] [ j ] Understood everything! – Alex Nov 18 '17 at 18:28
  • @Alex: A Python string is a list of characters. So a 1-D list of strings is actually a matrix of characters. – Eric Duminil Nov 18 '17 at 18:30
0

Here's your code with a minimum amount of changes. You can use modulo to loop from 26 back to 0. Note that __str__ should return a string and shouldn't print anything:

class CypherTable:

    def __init__(self):
        self.matrix = [[chr(ord('A') + (i + j) % 26) for i in range(26)] for j in range(5)]

    def __str__(self):
        return "\n".join('|'.join(row) for row in self.matrix)

table = CypherTable()
print(table)

It outputs:

A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z
B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A
C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B
D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C
E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D
Eric Duminil
  • 48,038
  • 8
  • 56
  • 100