Basic Python Vigenere Cypher - python-3.x

I have the Basic of the code laid out the problem is I do not know how to use the length of the keyword correctly.
When I run the problem I just get a bunch of S's as my output cause the code is not going to the next letter of the keyword.
I need help in the Def Encrypt part (the second def)
Keyword is SECRET // This is input
def encrypt_letter(text_letter , code_letter):
alphabet = string.ascii_uppercase
index = alphabet.find(code_letter)
cypher = alphabet[index:]+alphabet[:index]
index2 = alphabet.find(text_letter.upper())
result = cypher[index2]
if text_letter.islower():
result = result.lower()
return result
def encrypt(text, code):
cypher_text = ''
for letter in text:
if letter.isalpha():
cypher_text += code_word[0:1:6]
# code_letter = ?
# encrypt_letter(letter, )
else:
cypher_text += letter
return cypher_text
code_word = input('Please enter the code word: ')
code_word = code_word.upper()
cypher_text = encrypt(plain_text, code_word)
print(cypher_text)

Since this is clearly a student problem set, work on it a little longer and come back to ask a specific question, but a few hints:
Initialize a counter to count how many letters .isalpha() you've encountered
Use counter % len(secret_code) to keep track of your current position in the secret code
Use ASCII integer arithmetic and some if/else logic to modify characters in the cypher_text by counter % len(secret_code)
ord() and chr() will help you
If you're really stuck and need to peek at a solution, mine's here: https://github.com/bennett39/learning-exercises/blob/master/cs50/pset6/vigenere/vigenere.py
Spend a little more time on your solution before clicking that link, though.

Related

Find anagrams of a given sentence from a list of words

I have a sentence with no spaces and only lowercase letters, for example:
"johndrinksmilk"
and a list of words, which contains only words that could be anagrams of the sentence above, also these words are in alphabetical order, for example:
["drink","drinks","john","milk","milks"]
I want to create a function (without using libraries) which returns a tuple of three words that together can form the anagram of the given sentence. This tuple has to be the last possible anagram of the sentence. If the words in the given list can't be used to form the given sentence, the function should return None. Since I know I'm very bad at explaining things I'll try to give you some examples:
For example, with:
sentence = "johndrinksmilk"
g_list = ["drink","drinks","john","milk","milks"]
the result should be:
r_result = ("milks","john","drink")
while these results should be wrong:
w_result = ("drinks","john","milk")
w_result = None
w_result = ("drink","john","milks")
I tried this:
def find_anagram(sentence, g_list):
g_list.reverse()
for fword in g_list:
if g_list.index(fword) == len(g_list)-1:
break
for i in range(len(fword)):
sentence_1 = sentence.replace(fword[i],"",1)
if sentence_1 == "":
break
count2 = g_list.index(fword)+1
for sword in g_list[count2:]:
if g_list.index(sword) == len(g_list)-1:
break
for i in range(len(sword)):
if sword.count(sword[i]) > sentence_1.count(sword[i]):
break
else:
sentence_2 = sentence_1.replace(sword[i],"",1)
count3 = g_list.index(sword)+1
if sentence_2 == "":
break
for tword in g_list[count3:]:
for i in range(len(tword)):
if tword.count(tword[i]) != sentence_2.count(tword[i]):
break
else:
return (fword,sword,tword)
return None
but instead of returning:
("milks","john","drink")
it returns:
None
Can anyone please tell me what's wrong? If you think my function is bad feel free to show me a different approach (but still without using libraries), because I have the feeling my function is both complex and very slow (and wrong of course...).
Thanks for your time.
Edit: new examples as requested.
sentence = "markeatsbread"
a_list = ["bread","daerb","eats","kram","mark","stae"] #these are all the possibles anagrams
the correct result is:
result = ["stae","mark","daerb"]
wrong results should be:
result = ["mark","eats","bread"] #this could be a possible anagram, but I need the last possible one
result = None #can't return None because there's at least one anagram
Try this and see if it works with all of your cases:
def findAnagram(sentence, word_list):
word_list.reverse()
for f_word in word_list:
if word_list[-1] == f_word:
break
index1 = word_list.index(f_word) + 1
for s_word in word_list[index1:]:
if word_list[-1] == s_word: break
index2 = word_list.index(s_word) + 1
for t_word in word_list[index2:]:
if (sorted(list(f_word + s_word + t_word)) == sorted(list(sentence))):
return (f_word, s_word, t_word)
Hopefully this helps you

Replace isn't working for every letter in python

import time, random
#WELSCR
print(WOF1)
print("\n")
print(WOF2)
print("\n"*2)
input("Hit enter to play")
print("\n"*45)
print(WOF1)
print("\n")
print(WOF2)
doublespace = print("\n\n")
singlespace = print("\n")
tripplespace = print("\n\n\n")
guessed = []
score = 1000
wrong = 0
puzzle , hint = random.choice(questions)
blank = puzzle
for round in range (1,10):
tries = 0
iscorrect = False
while (not iscorrect) and (tries < 6):
blank = puzzle
for letter in blank:
if letter in "abcdefghijklmnopqrstuvwxyz":
blank = blank.replace(letter, "-")
def print_puzzle():
print("\n"*45)
print(WOF1)
print("\n")
print(WOF2)
print("\n"*2)
print(blank.center(80))
print("The hint is:",hint.title())
print("You currently have $",score)
print_puzzle()
input("enter")
break
break
This is the beginning of my program that I just started, a wheel of fortune game for a class. I can get it to replace almost all of the letters with a dash, however, there are the occasional few letters that do not always get hidden by this code and I'm not sure why. I have a variable defined as question which is a nested tuple but I did not include it because it's long and contains about 150 different entries.
Nevermind, the problem was case sensitivity. I had proper nouns and capitalized them, but I did not include capital letters in my replace string.

How to decode a list of letters and rebuild the original word in Python?

So I'm trying to make a makeshift encoder/decoder without the use of modules and well my method works with singular letters but not words. I have the code set up so it encodes every letter of the word with a key you choose.
What I'm wondering is how can you decode a list of encoded numbers one by one and then rebuild the word. This would be amazing and very helpful thanks.
P.S. I'm a beginner in Python and this is my second day so I tried everything I know also please don't use any modules.
while True :
option = input('Encode or Decode? : ')
if option == 'encode':
start = input('What word do you want to be encoded?: ')
word = start
key = int(input('What key would you like to use?: '))
z=[]
for i in word:
encoder = ord(i)*key+key/key
z.append(encoder)
print(z)
else:
start = float(input('What encoded string do you want to be decoded?: '))
key = int(input('What key would you like to use?: '))
decoder = start/key
print(chr(round(decoder)))
What you could do to decode is to type the sequence of numbers back into the code I have adjusted for you:
else:
x = []
start = (input('What encoded nubmers do you want to be decoded?: '))
split_list = start.split()
key = int(input('What key would you like to use?: '))
for i in split_list:
integer = int(i)
decoder = int(integer/key)
letter = chr(decoder)
x.append(letter)
print("".join(x))
start.split() splits the code into separate strings and puts them in a list, split_list. The code then checks every number in split_list and decodes the number, then turns it back into a character. It then prints the joined result of the characters.
For example, if I encode apple with key 5, then run the decoder and type 486 561 561 541 506 with key 5 it successfully returns apple.
This even works for multiple words, as I tried encoding hello world then decoding it and it was successful. I hope this helps! :)

Using the random function in Python for Evil Hangman

What I am trying to do is alter my original hangman game into what is called evil hangman. In order to do this, I need to first generate a random length of a word and pull out all words of that length from the original list.
Here is the code I am working with:
def setUp():
"""shows instructions, reads file,and returns a list of words from the english dictionary"""
try:
print(60*'*' +'''\n\t\tWelcome to Hangman!\n\t
I have selected a word from an english dictionary. \n\t
I will first show you the length of the secret word\n\t
as a series of dashes.\n\t
Your task is to guess the secret word one letter at a time.\n\t
If you guess a correct letter I will show you the guessed\n\t
letter(s) in the correct position.\n
You can only make 8 wrong guesses before you are hanged\n
\t\tGood luck\n''' + 60*'*')
infile=open('dictionary.txt')
l=infile.readlines()# list of words from which to choose
infile.close()
cleanList = []
for word in l:
cleanList.append(l[:-1])
return(cleanList)
except IOError:
print('There was a problem loading the dictionary file as is.')
def sort_dict_words_by_length(words):
"""Given a list containing words of different length,
sort those words based on their length."""
d = defaultdict(list)
for word in words:
d[len(word)].append(word)
return d
def pick_random_length_from_dictionary(diction):
max_len, min_len = ( f(diction.keys()) for f in (max, min) )
length = random.randint(min_len, max_len)
return diction[length]
def playRound(w,g):
""" It allows user to guess one letter. If right,places letter in correct positions in current guess string g, and shows current guess to user
if not, increments w, number of wrongs. Returns current number of wrongs and current guess string"""
print('You have ' + str(8 - w) + ' possible wrong guesses left.\n')
newLetter = input('Please guess a letter of the secret word:\n')
glist = list(g)#need to make changes to current guess string so need a mutable version of it
if newLetter in secretWord:
for j in range (0,len(secretWord)):
if secretWord[j]==newLetter:
glist[j] = newLetter
g = ''.join(glist)#reassemble the guess as a string
print('Your letter is indeed present in the secret word: ' + ' '.join(g)+'\n')
else:
w += 1
print('Sorry, there are no ' + newLetter + ' in the secret word. Try again.\n')
return(w,g)
def endRound(wr, w,l):
"""determines whether user guessed secret word, in which case updates s[0], or failed after w=8 attempts, in s\which case it updates s[1]"""
if wr == 8:
l += 1
print('Sorry, you have lost this game.\n\nThe secret word was '+secretWord +'\n')#minor violation of encapsulation
else:
w +=1
print(15*'*' + 'You got it!' + 15*'*')
return(w,l)
def askIfMore():
"""ask user if s/he wants to play another round of the game"""
while True:
more = input('Would you like to play another round?(y/n)')
if more[0].upper() == 'Y' or more[0].upper()=='N':
return more[0].upper()
else:
continue
def printStats(w,l):
"""prints final statistics"""
wGames='games'
lGames = 'games'
if w == 1:
wGames = 'game'
if l ==1:
lGames = 'game'
print('''Thank you for playing with us!\nYou have won {} {} and lost {} {}.\nGoodbye.'''.format(w,wGames,l,lGames))
try:
import random
from collections import defaultdict
words=setUp()#list of words from which to choose
won, lost = 0,0 #accumulators for games won, and lost
while True:
wrongs=0 # accumulator for wrong guesses
secretWord = random.choice(words)[:#eliminates '\n' at the end of each line
print(secretWord) #for testing purposes
guess= len(secretWord)*'_'
print('Secret Word:' + ' '.join(guess))
while wrongs < 8 and guess != secretWord:
wrongs, guess = playRound(wrongs, guess)
won, lost = endRound(wrongs,won,lost)
if askIfMore()== 'N':
break
printStats(won, lost)
except:
quit()
What I would like to do is generate a random number with the lower bound being the shortest length word and the upper bound being the highest length word, and then use that random number to create a new container with words of only that length, and finally returning that container to be used by the game further. I tried using min and max, but it seems to only return the first and last item of the list instead of showing the word with the most characters. Any help is appreciated.
If your 'dictionary.txt' has a single word on each line, you could use the following, which is speed efficient, because it'll only go over the list once. But it'll consume the memory of your original list again.
from collections import defaultdict
import random
def sort_dict_words_by_length(words):
"""Given a list containing words of different length,
sort those words based on their length."""
d = defaultdict(list)
for word in words:
d[len(word)].append(word)
return d
def pick_random_length_from_dictionary(diction):
max_len, min_len = ( f(diction.keys()) for f in (max, min) )
length = random.randint(min_len, max_len)
return diction[length]
You would then pass the output from your setUp to sort_dict_words_by_length and that output to pick_random_length_from_dictionary.
If you are memory-limited, then you should first go over all words in the wordlist, keeping track of the minimal and maximal length of those words and then reiterate over that wordlist, appending only those words of the desired length. What you need for that is mentioned in the code above and just requires some code reshuffling. I'll leave that up to you as an exercise.

using a looop to add user input to the set and dict in order discovered

So I'm trying to write a small program that does a few things. First is:
Write a while loop that repeatedly creates a list of words from a line of input from the user. So I did this:
s = input("Please enter a sentence: ")
while True:
pos = 0
for c in s:
if c == " ":
print(s[:pos])
s = s [pos+1:]
break
pos += 1
else:
print(s)
break
I need to add the user inputted words to the set and dict and then display their value in the order in which the program discovered them. I believe I need another loop but I'm not sure. I'm pretty lost at this point and the above is as far as I can seem to come on this program. Any help is appreciated as I am (obviously)new at python.

Resources