In my lesson I was tasked with creating a Caesar Cipher decoder that takes a string of input and finds the best possible string using a letter frequencies. If not sure how m
I'm working on the same tutorial and used a slightly different method. This avoided creating and calling functions:
inp = input() #to hold code text
code = list(inp) #store code as a list
soln = [] #store the 'Goodness' for each of 26 possible answers
y=0 #variable to hold total goodness during calculations
clear = [] #will hold decoded text
pos=0 #position marker for a list
#for every possible value of shift
#note range as 0 to 25 are valid shifts and shift 26 = shift 0
for shift in range(0,26):
for i in code: #loop through each letter in code
if i == " ": #spaces have no score so omit them
continue
else: #if it's a letter
x = ord(i)-shift #apply the test shift
if x < 65: #prevent shifting outside A-Z range
x = x + 26
x = x - 64 #turn ord into character position in A-Z with A=1
x = letterGoodness[x-1] #turn this into the Goodness score
y = y + x #add this to a running total
soln.insert(shift-1,y) #AFTER decoding all letters in code, add total(y) to list of scores
y = 0 #reset y before next test value
bestSoln=max(soln) #find highest possible score
for i in range(0,26): #check the list of solutions for this score
if soln[i]==bestSoln: #the position in this list is the shift we need
bestShift = i+1 #+1 as the first solution is 0
for i in code: #now decode the original text using our best solution
if i == " ": #spaces are not encoded so just add these to the string
clear.insert(pos," ") #pos used to track next position for final string
pos = pos + 1
continue
else:
x = ord(i)-bestShift #same operation as before
if x < 65:
x = x + 26
z = chr(x)
clear.insert(pos,z) #add the decoded letter to the clear text
pos = pos + 1
print("".join(clear)) #join the list of clear text into one string and print it
Note that many parts of this code could (and should) be compressed, for example
x = x - 64
x = letterGoodness[x-1]
y = y + x
They are left expanded to 'show my working' for a tutorial exercise.
My final solution that works, thanks to the wonderful Cristian Ciupitu.
x = input()
NUM_LETTERS = 26 #Can't import modules I'm using a web based grader/compiler
def SpyCoder(S, N):
y = ""
for i in S:
if(i.isupper()):
x = ord(i)
x += N
if x > ord('Z'):
x -= NUM_LETTERS
elif x < ord('A'):
x += NUM_LETTERS
y += chr(x)
else:
y += " "
return y
def GoodnessFinder(S):
y = 0
for i in S:
if i.isupper():
x = ord(i)
x -= ord('A')
y += letterGoodness[x]
else:
y += 1
return y
def GoodnessComparer(S):
goodnesstocompare = GoodnessFinder(S)
goodness = 0
v = ''
best_v = S
for i in range(0, 26):
v = SpyCoder(S, i)
goodness = GoodnessFinder(v)
if goodness > goodnesstocompare:
best_v = v
goodnesstocompare = goodness
return best_v
print(GoodnessComparer(x))
Thank you for all of your help!
Here is my implementation which works fine.
You should print the goodness of each possible message and see why your program output it.
letterGoodness = dict(zip(string.ascii_uppercase,
[.0817,.0149,.0278,.0425,.1270,.0223,.0202,
.0609,.0697,.0015,.0077,.0402,.0241,.0675,
.0751,.0193,.0009,.0599,.0633,.0906,.0276,
.0098,.0236,.0015,.0197,.0007]))
trans_tables = [ str.maketrans(string.ascii_uppercase,
string.ascii_uppercase[i:]+string.ascii_uppercase[:i])
for i in range(26)]
def goodness(msg):
return sum(letterGoodness.get(char, 0) for char in msg)
def all_shifts(msg):
msg = msg.upper()
for trans_table in trans_tables:
txt = msg.translate(trans_table)
yield goodness(txt), txt
print(max(all_shifts(input())))