forked from kkschick/intro-to-python-class
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pset06.py
205 lines (174 loc) · 5.51 KB
/
pset06.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# 6.00x Problem Set 6
#
# Part 1 - HAIL CAESAR!
import string
import random
WORDLIST_FILENAME = "words.txt"
# -----------------------------------
# Helper code
# (you don't need to understand this helper code)
def loadWords():
"""
Returns a list of valid words. Words are strings of lowercase letters.
Depending on the size of the word list, this function may
take a while to finish.
"""
print "Loading word list from file..."
inFile = open(WORDLIST_FILENAME, 'r')
wordList = inFile.read().split()
print " ", len(wordList), "words loaded."
return wordList
def isWord(wordList, word):
"""
Determines if word is a valid word.
wordList: list of words in the dictionary.
word: a possible word.
returns True if word is in wordList.
Example:
>>> isWord(wordList, 'bat') returns
True
>>> isWord(wordList, 'asdf') returns
False
"""
word = word.lower()
word = word.strip(" !@#$%^&*()-_+={}[]|\\:;'<>?,./\"")
return word in wordList
def randomWord(wordList):
"""
Returns a random word.
wordList: list of words
returns: a word from wordList at random
"""
return random.choice(wordList)
def randomString(wordList, n):
"""
Returns a string containing n random words from wordList
wordList: list of words
returns: a string of random words separated by spaces.
"""
return " ".join([randomWord(wordList) for _ in range(n)])
def randomScrambled(wordList, n):
"""
Generates a test string by generating an n-word random string
and encrypting it with a sequence of random shifts.
wordList: list of words
n: number of random words to generate and scamble
returns: a scrambled string of n random words
NOTE:
This function will ONLY work once you have completed your
implementation of applyShifts!
"""
s = randomString(wordList, n) + " "
shifts = [(i, random.randint(0, 25)) for i in range(len(s)) if s[i-1] == ' ']
return applyShifts(s, shifts)[:-1]
def getStoryString():
"""
Returns a story in encrypted text.
"""
return open("story.txt", "r").read()
# (end of helper code)
# -----------------------------------
#
# Problem 1: Encryption
#
def buildCoder(shift):
"""
Returns a dict that can apply a Caesar cipher to a letter.
The cipher is defined by the shift value. Ignores non-letter characters
like punctuation, numbers and spaces.
shift: 0 <= int < 26
returns: dict
"""
coder = {}
stringLower = 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'
stringUpper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ'
pos1 = 0
for letter in stringLower[0:26]:
offset1 = pos1 + shift
coder[letter] = stringLower[offset1]
pos1 += 1
pos2 = 0
for letter in stringUpper[0:26]:
offset2 = pos2 + shift
coder[letter] = stringUpper[offset2]
pos2 += 1
return coder
def applyCoder(text, coder):
"""
Applies the coder to the text. Returns the encoded text.
text: string
coder: dict with mappings of characters to shifted characters
returns: text after mapping coder chars to original text
"""
stringLower = 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'
stringUpper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ'
temp = []
s = 0
t = 1
while t <= len(text):
if text[s:t] in '12!@#$%;:, <>^&*.?/\0123456789':
temp.append(text[s:t])
else:
val = text[s:t]
temp.append(coder[val])
s += 1
t += 1
return ''.join(temp)
def applyShift(text, shift):
"""
Given a text, returns a new text Caesar shifted by the given shift
offset. Lower case letters should remain lower case, upper case
letters should remain upper case, and all other punctuation should
stay as it is.
text: string to apply the shift to
shift: amount to shift the text (0 <= int < 26)
returns: text after being shifted by specified amount.
"""
return applyCoder(text, buildCoder(shift))
#
# Problem 2: Decryption
#
def findBestShift(wordList, text):
"""
Finds a shift key that can decrypt the encoded text.
text: string
returns: 0 <= int < 26
"""
maxWordsFound = 0
bestShift = 0
totValidWords = 0
i = 0
while i < 26:
decodeText = applyShift(text, i)
decodeTextList = decodeText.split(' ')
for item in range(len(decodeTextList)):
if isWord(wordList, decodeTextList[item]) == True:
totValidWords += 1
if totValidWords > maxWordsFound:
maxWordsFound = totValidWords
bestShift = i
i += 1
return bestShift
def decryptStory():
"""
Using the methods you created in this problem set,
decrypt the story given by the function getStoryString().
Use the functions getStoryString and loadWords to get the
raw data you need.
returns: string - story in plain text
"""
encryptedStory = getStoryString()
wordList = loadWords()
shift = findBestShift(wordList, encryptedStory)
return applyShift(encryptedStory, shift)
#
# Build data structures used for entire session and run encryption
#
if __name__ == '__main__':
# To test findBestShift:
wordList = loadWords()
s = applyShift('Hello, world!', 8)
bestShift = findBestShift(wordList, s)
assert applyShift(s, bestShift) == 'Hello, world!'
# To test decryptStory, comment the above four lines and uncomment this line:
# decryptStory()