creating the reversal portion of a cryptography decoder - python

First of hopefully many questions to come as I dive deeper into Python. I'm following along to the Giraffe Academy course and have tried to create a more complex program. It's a silly little decoder tool but it's helping me learn a lot of the python basics. I have the first part of the program below:
import string
std = string.ascii_lowercase
rvs = string.ascii_lowercase[::-1]
vwls = {'a':5,'e':1,'i':4, 'o':2, 'u':3}
def translate(phrase):
phrase = phrase.lower()
translation = ""
for letter in phrase:
if letter.isspace() == True:
translation = translation + " "
elif letter in ".!?":
translation = translation + letter
elif letter in vwls:
if str(vwls[letter]) not in translation:
translation = translation + str(vwls[letter])
vwls[letter] = vwls[letter] + 5
else:
indx = std.index(letter)
translation = translation + rvs[indx]
return translation
print(translate(input("Enter a phrase: ")))
My goal is to create the decoder for the output of the previous code. The good news is I know what is causing my problem. Because the message is a string, any vowel that goes past 2 digits wont be picked up by my code below. I need to find a way to include the next character in the string so that it can choose the correct key/value pairing in the dict. Below is what I have so far:
import string
std = string.ascii_lowercase
rvs = string.ascii_lowercase[::-1]
vwls = {'5':'a','1':'e','4':'i','2':'o','3':'u'}
def translate(phrase):
translation = ""
for letter in phrase:
if letter.isspace() == True:
translation = translation + " "
elif letter in ".!?":
translation = translation + letter
elif letter in vwls:
if letter in vwls[letter]:
translation = translation + vwls[letter]
vwls[str(int(letter) + 5)] = vwls[letter]
del vwls[letter]
else:
for index in range(len(phrase)-1):
if phrase[index] == phrase[index+1]:
translation = translation + 'poop'
else:
indx = rvs.index(letter)
translation = translation + std[indx]
return translation
print(translate(input("Enter a phrase: ")))
Any feedback is greatly appreciated! I have tried searching for similar issues and I am still learning the rules for stack overflow so I apologize if I have broken any rules regarding this question.

good luck with your diving
tried here something, not sure if its correct
few points
for each vowel, the %5 is the same, for example u can be 3,8,13,18.. they all have % 5 of 3
the biggest match you can find is the correct one, 23 is either ou or just u after few iteration, so if the dict say u value is 23 the correct value is u
there is a problem with the translate function you provided
eeee is decoded to 1611 which is eee, missing one e
def decode(phrase):
vwls = {'a':5,'e':1,'i':4, 'o':2, 'u':3}
reverse_vwls = {0:'a',1:'e',4:'i',2:'o',3:'u'}
translation = ""
i=0
while i < len(phrase):
if phrase[i].isspace() == True:
translation = translation + " "
i+=1
continue
if phrase[i] in ".!?":
translation = translation + phrase[i]
i+=1
continue
if str.isdigit(phrase[i]): #check if the letter is a digit
tmp_index = i
str_num = ""
while tmp_index<len(phrase) and str.isdigit(phrase[tmp_index]): # take all the co
str_num = str_num+phrase[tmp_index]
tmp_index+=1
int_num = int(str_num) # turn the digits string into int
while int_num:
current_digit = int_num%10
curent_vwl = reverse_vwls[current_digit%5] #the ones digit % 5 is permenent f
if vwls[curent_vwl] == int_num:
vwls[curent_vwl] = vwls[curent_vwl]+5
translation = translation+curent_vwl
i = i+len(str(int_num))
break
int_num = int(int_num/10)
continue
indx = rvs.index(phrase[i])
translation = translation + std[indx]
i+=1
return translation

Related

How do I choose 2 or more letters in a word?

Basically my plan was to return text with random-sized letters in words i.e. "upper" or "lower". The script is working, though it seems raw (I am a Beginner and I'd appreciate some corrections from You).
The problem is:
It is not consistent. With that said, it can print word 'about' even if it should be 'About' or something similar.
I want to be sure that the maximum of UPPER or lower letters in a row do not exceed 3 letters. and I don't know how to do it.
Thank you in advance.
#!/usr/bin/env python3
import random
message = input()
stop = ''
def mocking(message):
result = ''
for word in message:
for letter in word:
word = random.choice(random.choice(letter.upper()) + random.choice(letter.lower()))
result += word
return result
while stop != 'n':
print(mocking(message))
stop = input("Wanna more? y/n ").lower()
if stop == 'n':
break
else:
message = input()
You need to split the input into words, decide how many positions inside the word you want to change (minimum 3 or less if the word is shorter).
Then generate 3 unique positions inside the word (via random.sample) to change, check if upper then make lower else make upper. Add to resultlist and join words back together.
import random
message = "Some text to randomize"
def mocking(message):
result = []
for word in message.split():
len_word = len(word)
# get max 3 random positions
p = random.sample(range(len_word),k = min(len_word,3))
for position in p:
l = word[position]
if l.isupper():
word = word[:position] + l.lower() + word[position+1:]
else:
word = word[:position] + l.upper() + word[position+1:]
result.append(word)
return ' '.join(result)
while True:
print(mocking(message))
stop = input("Wanna more? y/n ").lower()
if stop == 'n':
break
else:
message = input()
See Understanding slice notation for slicing
At most 3 modifications? I would go with something like this.
def mocking(message):
result = ''
randomCount = 0
for word in message:
for letter in word:
newLetter = random.choice( letter.upper() + letter.lower() )
if randomCount < 3 and newLetter != letter:
randomCount += 1
result += newLetter
else:
result += letter
randomCount = 0
return result
If the random choice has modified the letter then count it.

Brute Force Dictionary Attack Caesar Cipher Python Code not working past 18'th shift

This was made to brute force caesar ciphers using a dictionary file from http://www.math.sjsu.edu/~foster/dictionary.txt. It is run through three functions, lang_lib() which makes the text of the dictionary into a callable object, isEnglish(), which checks the percentage of the phrase, and if at least 60% of it matchwa with the any words in the dictionary, it would return a True value. Using this, a caeser cipher function runs through all shifts, and checking them from english words. It should return the result with the highest percentage, but it only seems to work through shifts 1-18. I can't figure out why it isn't working.
def lang_lib():
file = open('dictionary.txt', 'r')
file_read = file.read()
file_split = file_read.split()
words = []
for word in file_split:
words.append(word)
file.close()
return words
dictionary = lang_lib()
def isEnglish(text):
split_text = text.lower().split()
counter = 0
not_in_dict = []
for word in split_text:
if word in dictionary:
counter += 1
else:
not_in_dict.append(word)
length = len(split_text)
text_percent = ((counter / length) * 100)
#print(text_percent)
if text_percent >= 60.0:
return True
else:
return False
alphabet = "abcdefghijklmnopqrstuvwxyz0123456789!##$%/."
def caeser(text): #Put in text, and it will spit out all possible values
lower_text = text.lower()
ciphertext = "" #stores current cipher value
matches = [] #stores possible matches
for i in range(len(alphabet)): #loops for the length of input alphabet
for c in lower_text:
if c in alphabet:
num = alphabet.find(c)
newnum = num - i
if newnum >= len(alphabet):
newnum -= len(alphabet)
elif newnum < 0:
newnum += len(alphabet)
ciphertext = ciphertext + alphabet[newnum]
else:
ciphertext = ciphertext + c
testing = isEnglish(ciphertext)
for text in ciphertext:
if testing == True and len(ciphertext) == len(lower_text):
matches.append(ciphertext)
return i, matches
ciphertext = "" #clears ciphertext so it doesn't get cluttered
print(caeser('0x447 #0x$x 74w v0%5')) #shift of 19
print(caeser('zw336 #zw9w 63v uz#4')) #shift of 18
Thanks guys.
This part is indented too far as #tripleee suggested:
testing = isEnglish(ciphertext)
for text in ciphertext:
if testing == True:
matches.append(ciphertext)
return i, matches
Also you don't need to check the length if you have the indentation right and let the previous loop complete....
I found out that the dictionary.txt does not contain 2 or 3 letter words, so it would skew long inputs with many of these words, and return False. I added a list of common words, so now all inputs work accurately.
If anyone wants to help me make this code more efficient, I'd love some pointers. I am very new to Python.

Translate/Replace Multiple Letters With Python

I am working on a very basic translation program. Currently it can only deal with one letter in a phrase. For example if I were to input "test" it would blurt out "yesy" because it changes "t" to "y". Here's the code I use to do that:
def translate(phrase):
translation = ""
for letter in phrase:
if letter in "t":
translation = translation + "y"
else:
translation = translation + letter
return translation
print(translate(input("Enter word: ")))
Is it possible to add another letter to be translated. So for example "e" to "a" on top of "t" to "y". so that it would spit out "yasy".
There's a much easier way using str.replace: 'test'.replace('t','y').replace('e','a')
However, if you're looking to replace more and more letters str.translate would be more efficient:
from string import maketrans
trans_from = "te"
trans_to = "ya"
trans_model = maketrans(trans_from, trans_to)
'test'.translate(trans_model)
Or, if you want to keep your code, you can use elif:
def translate(phrase):
translation = ""
for letter in phrase:
if letter in "t":
translation = translation + "y"
elif letter in "e":
translation = translation + "a"
else:
translation = translation + letter
return translation
print(translate(input("Enter word: ")))
Use a dictionary.
en-gb = {'t':'y', add more here}
def translate(phrase):
translation = str()
for char in phrase:
translation = translation + en-gb[char]
return translation

Word-guessing game: trying to build an AI

I'm trying to create a little game.
The rules are very straightforward: you give an English word, and the computer will try to guess this word letter by letter.
The thing is, I'm trying to make the computer guess the letters in a smart way. Let me give you a simple example of what I'm trying to build so you can understand:
You give the word "cat" to the computer to guess.
The 130K words list I have is narrowed to only the words who have 3 characters, which makes up to 805 words only. And from this list of words, an alphabet is created, containing only 25 letters (not the whole 26) because the new 805 words list contains all the letters of the alphabet but the "z". So we now have a list containing 25 (different) letters.
-- As I can't upload anything here on SO, we will say for this example that the massive 130K words list is a 10 words list (variable name "fullDice") --
If you try to run my code, pick a word from inside this list or else
it's not going to work
The computer now guesses a random letter from this 25 letters list.
If the letter is not in the word, he doesn't do anything and re-guess a letter from the list.
But if the letter is in the word, that's where things become more complicated. Let's say the computer guess the letter "c". I want the computer to re-narrow the possible words list, to only those having a "c" in the first character. That way, the 805-words list become now an only 36 words list. Because there are only 36 words who are 3 characters and starts with a "c", a new alphabet is created. And the new alphabet is now made of only 14 letters, making it easier for the computer to guess the next letter and be correct about it. And so on until he finds all the letters.
I'm stuck on part 5. If you try to run my code just below, you'll see that the dictionnary list is never narrowed. That's my problem.
import time
from random import randint
fullDice = ["panda", "tiger", "cat", "elephant", "whale", "leopard", "gorilla", "fish", "snake", "eagle"]
askForWord = input("Please enter an english word: ")
while True:
updatedDice = []
for k in range (0, len(fullDice)):
if len(askForWord) == len(fullDice[k]):
updatedDice += [fullDice[k]]
alphabet = []
for i in range (0, len(updatedDice)):
for n in range (0, len(updatedDice[i])):
if updatedDice[i][n] not in alphabet:
alphabet += [updatedDice[i][n]]
guessRandomLetter = alphabet[randint(0, len(alphabet) - 1)]
print("I guess the letter: " + guessRandomLetter)
print("From this dice: " + str(len(updatedDice)))
print("From this amount of letters: " + str(len(alphabet)) + "\n")
time.sleep(0.75)
guessedWordUnderlined = "_" * len(askForWord)
if guessRandomLetter in askForWord:
for m in range(0, len(askForWord)):
if askForWord[m] == guessRandomLetter: # CHECKING IF THE GUESSED LETTER IS INSIDE THE WORD
guessedWordUnderlined = list(guessedWordUnderlined)
guessedWordUnderlined[m] = guessRandomLetter
guessedWordUnderlined = ''.join(map(str, guessedWordUnderlined))
if guessedWordUnderlined == askForWord: # CHECK IF USER HAS WON
print("YOU WON")
break
you just asked a qs including that code.
i tryed to make it work only with the available words in the dictionnary you gave as "python".
from random import randint
import random
import time
import datetime
random.seed(datetime.datetime.now())
wordOfTheUser = input("ENTER ENGLISH WORD HERE: ")
if wordOfTheUser in ("abracadabra", "python", "coding", "soup", "paper", "list", "leader", "program", "software", "eating","abcdefghigklmnopqrstuvwxyz"):
pass
else:
print("your word is not on the list, still devlopping.")
raise
diceList1 = ["abracadabra", "python", "coding", "soup", "paper", "list", "leader", "program", "software", "eating","abcdefghigklmnopqrstuvwxyz"]
diceList2 = []
for k in range (0, len(diceList1) - 1):
if len(diceList1[k]) == len(wordOfTheUser):
diceList2 += [diceList1[k]]
makeAlphabet = []
for b in range (0, len(diceList2)):
for x in range (0, len(diceList2[b])):
if diceList2[b][x] not in makeAlphabet:
makeAlphabet += [diceList2[b][x]]
computerWordSize = "_" * int(len(wordOfTheUser))
a= len(makeAlphabet)
while True:
try:
randomIndex = randint(0, a)
except ValueError:
randomIndex = randint(0, a)
pass
try:
letterChosenRandomly = makeAlphabet[randomIndex]
except IndexError as e:
try:
randomIndex = randint(0, int(len(makeAlphabet)))
letterChosenRandomly = makeAlphabet[randomIndex]
except:
pass
print("I guess the letter -> " + letterChosenRandomly)
diceList3 = []
if letterChosenRandomly in wordOfTheUser:
print("\n=== WON ===> " + letterChosenRandomly)
print("=== ALPHABET ===> " + str(len(makeAlphabet)))
print("=== HDW1 ===> " + str(len(diceList1)))
print("=== hdw2 ===> " + str(len(diceList2)))
print("=== hdw3 ===> " + str(len(diceList3)) + "\n\n")
k=-1
makeAlphabet = []
for i in range (0, len(wordOfTheUser) ):
if letterChosenRandomly == wordOfTheUser[i]:
computerWordSize = list(computerWordSize)
computerWordSize[i] = letterChosenRandomly
for l in range (0, len(diceList2)):
if computerWordSize[i] == diceList2[l][i]:
diceList3 += [diceList2[l]]
for d in range(0, len(diceList3)):
for h in range(0, len(diceList2[b])):
if diceList2[d][h] not in makeAlphabet:
makeAlphabet += [diceList2[d][h]]
won = False
computerWordSize = ''.join(map(str, computerWordSize))
print(computerWordSize)
if computerWordSize == wordOfTheUser:
won = True
if won is True:
print("YOU WON")
break
time.sleep(1)
else:
print("\n=== LOOSE ===> " + letterChosenRandomly)
print("=== ALPHABET ===> " + str(len(makeAlphabet)))
print("=== HDW1 ===> " + str(len(diceList1)))
print("== hdw2 ===> " + str(len(diceList2)))
print("=== hdw3 ===> " + str(len(diceList3)) + "\n\n")
try:
makeAlphabet.remove(letterChosenRandomly)
except:
print ("Letters not in list")
break
k=0
diceList3 = []
for q in range (0, len(wordOfTheUser) - 1):
for l in range(0, len(diceList2)):
if computerWordSize[q] == diceList2[l][q]:
diceList3 += [diceList2[l]]
for d in range(0, len(diceList3)):
for h in range(0, len(diceList2[b])):
try:
if diceList2[d][h] not in makeAlphabet:
makeAlphabet += [diceList2[d][h]]
except:
try:
for s in range(0, len(diceList3)):
for f in range(0, len(diceList2)):
if diceList2[s][f] not in makeAlphabet:
makeAlphabet += [diceList2[s][f]]
except:
("your word is too short")
time.sleep(1)
I believe the problem is that if guessedWordUnderlined in askForWord will never be true. The in operator tests whether the first operator is within the second argument, which is a container, such as a list or string. "_" * len(askForWord), the value of guessedWordUnderlined, is a string of underscores, and you are testing whether or not that is in askForWOrd. If the vale of askForWord is cat, askForWord can be thought of as ["c", "a", "t"], so the in operator will be testing "___" == "c" or "___" == "a" or "___" == "t", none of which will be true. This means that the code beneath it will never execute, so the code just repeats forever, randomly guessing letters within the word. I cannot really tell what the function of this if is, as you already know each letter you could have chosen is in askForWord, though I'm sure I'm missing something obvious.
As an aside, you frequently use a construction similar to for x in range(0, len(LIST): ... LIST[x], which can be more concisely and obviously written as for x in LIST: ... x. For example, your code
for k in range (0, len(fullDice)):
if len(askForWord) == len(fullDice[k]):
updatedDice += [fullDice[k]]
alphabet = []
could be written as
for k in fullDice:
if len(askForWord) == len(k):
updatedDice += [k] # This should be updatedDice.append(k), but I
# have left it as-is for simplicity's sake.
alphabet = []
which should help your code become more readable. There are a few other edits that could be made to make your code more pythonic, but aside from that line I cannot see anything functionally wrong with it. If you share what this if is supposed to help, it might make it a bit easier to find any other errors in your code. I hope this helps, and good luck!
Having reviewed your code again, I believe the problem is in the statement guessedWordUnderlined = "_" * len(askForWord). This creates a string of underscores whose length is equal to that of askFOrWord. The problem is that each at each iteration of the while True: loop, a new string. This means that at each iteration, the string becomes a list of underscores with one correct letter, but in the next iteration it is overridden. To fix this, you should move the line guessedWordUnderlined = "_" * len(askForWord) from its current location to directly below askForWord = input("Please enter an english word: "). This will mean that it is present in the global scope rather than the local scope, meaning it won't get overwritten. You should also put the line global guessedWordUnderlined at the beginning of the while loop, if I'm not mistaken. This may require you to rework some code. Hope this works for you!

Replacing every instance of a character in Python string

I have a game where the user guesses letters. They are shown a blank version of the mystery work (_____ for example, the _'s are equal to number of characters in the word). The program knows the word, and needs to replace every index in the blanked out version of the word if the letter they guess is present in the mystery word.
For example, if the player guesses "p" and the word is "hippo" they will be shown __pp_. But, my code will only replace the first instance of "p", giving __p__ instead.
Would this be easier to tackle as a list problem?
mistakes = 0
complete = False
t = False
words = ['cow','horse','deer','elephant','lion','tiger','baboon','donkey','fox','giraffe']
print("\nWelcome to Hangman! Guess the mystery word with less than 6 mistakes!")
# Process to select word
word_num = valid_number()
word = words[word_num]
#print(word)
print("\nThe length of the word is: ", str(len(word)))
attempt = len(word)*"_"
# Guesses
while not (mistakes == 6):
guess = valid_guess()
for letter in word:
if guess == letter:
print("The letter is in the word.")
position = word.index(guess)
attempt = attempt [0:position] + guess + attempt [position + 1:]
print("Letters matched so far: ", attempt)
t = True
while (t == False):
print("The letter is not in the word.")
print("Letters matched so far: ", attempt)
mistakes = mistakes + 1
hangMan = ["------------", "| |", "| O", "| / |", "| |", "| / |\n|\n|"]
hang_man()
t = True
t = False
answer = 'hippo'
fake = '_'*len(answer) #This appears as _____, which is the place to guess
fake = list(fake) #This will convert fake to a list, so that we can access and change it.
guess = raw_input('What is your guess? ') #Takes input
for k in range(0, len(answer)): #For statement to loop over the answer (not really over the answer, but the numerical index of the answer)
if guess == answer[k] #If the guess is in the answer,
fake[k] = guess #change the fake to represent that, EACH TIME IT OCCURS
print ''.join(fake) #converts from list to string
This runs as:
>>> What is your guess?
p
>>> __pp_
To loop over everything, I did not use index, because index only returns the first instance:
>>> var = 'puppy'
>>> var.index('p')
0
So to do that, I analyzed it not by the letter, but by its placement, using a for that does not put k as each letter, but rather as a number so that we can effectively loop over the entire string without it returning only one variable.
One could also use re, but for a beginning programmer, it is better to understand how something works rather than calling a bunch of functions from a module (except in the case of random numbers, nobody wants to make their own pseudo-random equation :D)
Based on Find all occurrences of a substring in Python:
import re
guess = valid_guess()
matches = [m.start() for m in re.finditer(guess, word)]
if matches:
for match in matches:
attempt = attempt[0:match] + guess + attempt[match+1:]
print("Letters matched so far: ", attempt)
else:
.
.
.

Categories

Resources