I have this issue I did where the replace function calls the uppercase function, what I need to do is, I need the main function to call the other functions(SO first the uppercase and then the replace). I also need to change the interactive area. What I mean by this is right now the uppercase function is asking the user for a string, but I need the main function to ask the user for a string and then call the uppercase function and then call replace function.
def uppercase():
cap_letters = input("Please enter your string here: ")
new_uppercase=''
for letters in cap_letters:
if ord(letters) > 96:
new_uppercase += chr(ord(letters)-32)
else:
new_uppercase += letters
print(new_uppercase)
return new_uppercase
def replace():
old,new = [],[]
newString = ""
new_uppercase = uppercase()
string = new_uppercase
char = input("Change: ")
toThis = input("Change " + char + " to this: ")
for x in range(0,len(string)):
old.append(string[x])
for y in range(0,len(old)):
if old[y] != char:
new.append(old[y])
else:
new.append(toThis)
for z in range(0,len(new)):
newString+=new[z]
print(newString)
def main():
print("Hello, And Welcome to this Slang Program")
uppercase()
# write the part of the program that interacts with the user here
replace()
main()
You are trying to pass values between functions. You need to return the values from each function so that the parent function can use them. Passing values around works like this:
def function2(foo):
double_foo = foo * 2 # Do something to create whatever output you need
return double_foo
def function1(bar):
foobar = function2(bar) # Note that the foo and bar variables here are locally scoped
return foobar
def main():
user_input = input("Please enter your string here: ")
output = function1(user_input)
return output
main()
For more on scoping, check out https://matthew-brett.github.io/teaching/global_scope.html
Related
Disclaimer
To preface this, I am new to programming and even newer to python, so my knowledge of the mechanics of the interpreter is very limited.
Explanation I am currently writing a pythonic code that simulates a text-based game of cheating hangman, which means the program changes the word to evade the player from guessing the correct word using "word families." The game requires three files: hangman.py, play_hangman.py, and dictionary.txt. In hangman.py, I have created a hangman class that contains the self-instance of the class, several methods for producing the necessary objects, and a play method that uses these methods. Then, in play_hangman.py, it calls the hangman instance, and the play method, and puts the play method into a while loop that repeats as long as the player enters "yes" to keep playing.
The Problem I have called the methods into the play function for executing the game. However, it gives me an error saying:
- "12 positional arguments: 'word_length', 'num_guesses',
'remaining_words', 'remainingWords', 'letters_already_guessed',
'askForWordLength', 'printGameStats', 'askForPlayerGuess',
'wordStatus', 'printCountOfRemainingWords', 'retreiveRemainingWords',
and 'askForNumberOfGuesses' "
These are the twelve variables and methods I have called in the def play(): function. I have researched that I need to call an object of the class before the method, which I attempted to do, but does not work. I am not sure how to avoid the error.
HANGMAN.PY
import re
class Hangman:
# hangman self method
def hangman(self):
self.hangman = Hangman() # object of the Hangman class
def words(self):
with open('dictionary.txt') as file: # opens dictionary text file
file_lines = file.read().splitlines() # reads and splits each line
all_words = [] # empty list to contain all words
valid_words = [] # empty list to contain all valid words
for word in file_lines: # traverses all words in the file lines
if len(word) >= 3: # accepts word if it has at least 3 letters
all_words.append(word) # appends accepted word to list
# list of all invalid characters in python
CHARACTERS = ["~", "`", "!", "#", "#", "$", "%", "^", "&", "*", "(",
")", "-", "_", "=", "+", "[", "]", "{", "}", "|", "\","
"", "'", "?", "/", ">", ".", "<", ",", "", ";", ":"]
for i in CHARACTERS: # traverse list of invalids
for word in all_words:
if i not in word: # if invalid character is not in word
valid_words.append(word) # accept and append to list
return valid_words # return list of valid words
def askForWordLength(self, valid_words):
word_lengths = [] # empty list for possible word lengths
for word in valid_words: # traverse list of valid words
length = word.__len__() # record length of current word
if (length not in word_lengths):
word_lengths.append(length) # accept and append to list
word_lengths.sort()
# inform user of possible word lengths
print('The available word lengths are: ' + str(word_lengths[0]) + '-'
+ str(word_lengths[-1]))
print()
# have user choose from possible word lengths
while(1):
try:
length = int(input('Please enter the word length you want: '))
if (length in word_lengths):
return length
except ValueError:
print('Your input is invalid!. Please use a valid input!')
print()
def askForNumberOfGuesses(self):
while(1):
try:
num_guesses = int(input('Enter number of guesses you want: '))
if (num_guesses >= 3):
return num_guesses
except ValueError:
print('Your input is invalid!. Please use a valid input!')
print()
def wordStatus(self, length):
status = '-'
for i in range(0, length):
status += '-'
return
def remainingWords(self, lines, length):
words = []
for word in lines:
if (word.__len__() == length):
words.append(word)
return words
def printGameStats(self, letters_guessed, status, num_guesses):
print('Game Status: ' + str(status))
print()
print('Attempted Guesses' + str(letters_guessed))
print('Remaining Guesses' + str(num_guesses))
def askPlayerForGuess(self, letters_guessed):
letter = str(input('Guess a letter: ')).lower()
pattern = re.compile("^[a-z]{1}$")
invalid_guess = letter in letters_guessed or re.match(pattern, letter) == None
if (invalid_guess):
while (1):
print()
if (re.match(pattern, letter) == None):
print('Invalid guess. Please enter a correct character!')
if (letter in letters_guessed):
print('\nYou already guessed that letter' + letter)
letter = str(input('Please guess a letter: '))
valid_guess = letter not in letters_guessed and re.match(pattern, letter) != None
if (valid_guess):
return letter
return letter
def retrieveWordStatus(self, word_family, letters_already_guessed):
status = ''
for letter in word_family:
if (letter in letters_already_guessed):
status += letter
else:
status += '-'
return status
def retrieveRemainingWords(self, guess, num_guesses, remaining_words,
wordStatus, guesses_num, word_length,
createWordFamiliesDict,
findHighestCountWordFamily,
generateListOfWords):
word_families = createWordFamiliesDict(remaining_words, guess)
family_return = wordStatus(word_length)
avoid_guess = num_guesses == 0 and family_return in word_families
if (avoid_guess):
family_return = wordStatus(word_length)
else:
family_return = findHighestCountWordFamily(word_families)
words = generateListOfWords(remaining_words, guess, family_return)
return words
def createWordFamiliesDict(self, remainingWords, guess):
wordFamilies = dict()
for word in remainingWords:
status = ''
for letter in word:
if (letter == guess):
status += guess
else:
status += '-'
if (status not in wordFamilies):
wordFamilies[status] = 1
else:
wordFamilies[status] = wordFamilies[status] + 1
return wordFamilies
def generateListOfWords(self, remainingWords, guess, familyToReturn):
words = []
for word in remainingWords:
word_family = ''
for letter in word:
if (letter == guess):
word_family += guess
else:
word_family += '-'
if (word_family == familyToReturn):
words.append(word)
return words
def findHighestCountWordFamily(self, wordFamilies):
familyToReturn = ''
maxCount = 0
for word_family in wordFamilies:
if wordFamilies[word_family] > maxCount:
maxCount = wordFamilies[word_family]
familyToReturn = word_family
return familyToReturn
def printCountOfRemainingWords(self, remainingWords):
show_remain_words = str(input('Want to view the remaining words?: '))
if (show_remain_words == 'yes'):
print('Remaining words: ' + str(len(remainingWords)))
else:
print()
def play(self, askForWordLength, askForNumberOfGuesses, remainingWords,
words, wordStatus, printCountOfRemainingWords, printGameStats,
askPlayerForGuess, retrieveRemainingWords):
MODE = 1
openSession = 1
while (openSession == 1):
word_length = askForWordLength(words)
num_guesses = askForNumberOfGuesses()
wordStatus = wordStatus(word_length)
letters_already_guessed = []
print()
game_over = 0
while (game_over == 0):
if (MODE == 1):
printCountOfRemainingWords(remainingWords)
printGameStats(remainingWords, letters_already_guessed,
num_guesses, wordStatus)
guess = askPlayerForGuess(letters_already_guessed)
letters_already_guessed.append(guess)
num_guesses -= 1
remainingWords = retrieveRemainingWords(guess, remainingWords,
num_guesses, word_length)
wordStatus = wordStatus(remainingWords[0], letters_already_guessed)
print()
if (guess in wordStatus):
num_guesses += 1
if ('-' not in wordStatus):
game_over = 1
print('Congratulations! You won!')
print('Your word was: ' + wordStatus)
if (num_guesses == 0 and game_over == 0):
game_over = 1
print('Haha! You Lose')
print('Your word was: ' + remainingWords[0])
print('Thanks for playing Hangman!')
Self as First Parameter
When creating functions inside classes, the first parameter should be 'self', as you've done in the function askForNumberOfGuesses. This happens because, when calling functions from an object, Python passes the object to 'self' so the method's logic can access its data.
When calling functions such as "play" (in which you haven't used the self parameter in the declaration), the first parameter will be handled as the self, even though it has a different name. So, actually, your code expects the variable 'words' to be a Hangman object.
Static Functions
If the function needs to know information about the object, you need to add the 'self' as the first parameter.
However, if your method does not use any data declared inside the Hangman class (such as self.hangman that you've created inside init) you can just add a "#staticmethod" to the line before the function definition. This way, Python will know that you don't need self and that the first parameter is not the object.
Notice that, if you want to use a static method, you can use the class itself to call the method. You don't even need to create an object:
Hangman.static_function_name(function_parameters) # calls static function
hangman_object = Hangman()
hangman_object.non_static_function_name(function_parameters) # calls non-static function
hangman_object.static_function_name(function_parameters) # calls static function using object (there is no problem)
Design Considerations
Also, I believe you should change your init implementation and use 'self' to store data that you use in more than one function, instead of passing arguments to all the functions and returning them.
Also note that, in order to create a Hangman object, you need to use ():
self.hangman = Hangman # reference to the Hangman class
self.hangman = Hangman() # Object of the Hangman class
However, if you create a Hangman object inside init, it will call init again and this will go on "forever". So, you shouldn't create a Hangman object inside it's init method. I believe you should create the Hangman object in play_hangman.py file and call the play method from there.
In my opinion, init should create all the data you need as self.<var_name>, load should prepare words or whatever you need using self.<functions_you_create> and play should just start the game. play_hangman.py shouldn't need to know all these parameters.
hangman.py
class GameClass:
def __init__(self):
self.words = list()
# TODO: Implement adding other game data
def load(self):
# TODO: Implement logic
self.words.append('country')
pass
def play(self):
# TODO: Implement loop logic
print(self.words)
# while(True):
# break
pass
play_hangman.py
game = GameClass()
game.load()
game.play()
IDE
Use a good IDE so it will remember you to add self if you are not used yet.
None of those methods have self as their first argument.
And that is what is used to define class methods and give access to attributes.
So, adding that "self" keyword is the first step to make your code work.
I would recommend installing a linter, it automatically identifies this kind of error for you:
So I'm making a game of hangman and it starts with a "BotMaster" entering a string and then how many guesses that player will have to try and guess the string. I only just started and I'm trying to write a function that will check if what the BotMaster put is a valid string. A valid string would be a string that is only letters, no symbols, numbers, or extra spaces. I already have the functions that will remove extra spaces, and non-alpha inputs (So it takes out periods, extra spaces and such) and a function that makes it all lower case, but my function breaks if I enter a number an empty string. How should I add these?
#Imports (this is for later code I haven't written)
import os,time,random
#Removes extra spaces from the function
def space_cull(the_str):
result = the_str
result = result.strip()
result =" ".join(result.split())
the_str = result
return the_str
#Makes the string lowercase
def make_lower(the_str):
the_str = the_str.lower()
return the_str
#Checks if everything in the string are Alpha Inputs
def check_alpha(the_str):
the_str =''.join([char for char in the_str if char.isalnum()])
return the_str
#Ask Botmaster the string they want
def ask_bot():
while True:
bot_str = input('Enter a string for the player to guess: ')
bot_str = space_cull(bot_str)
bot_str = make_lower(bot_str)
bot_str = check_alpha(bot_str)
if bot_str == '':
print('That is not a correct string, try again')
True
return bot_str
ask_bot()
I added the ask_bot() part so I can test the function faster
This is what happens:
Enter a string for the player to guess: 1
#nothing
#Tested again:
Enter a string for the player to guess: ''
That is not a correct string, try again.
#But then exits the loop, which I don't want it to, if the string is wrong I want it to ask them again.
#Tested Again
Enter a string for the player to guess: 'Katze'
#Nothing, which is actually good this time
How do I fix this?
Your while loop will always terminate in the function as it is written.
def ask_bot():
while True:
bot_str = input('Enter a string for the player to guess: ')
bot_str = space_cull(bot_str)
bot_str = make_lower(bot_str)
bot_str = check_alpha(bot_str)
if bot_str == '':
print('That is not a correct string, try again')
True # <- this does nothing
return bot_str # < - this breaks out of the function and the loop
Your code edited to work:
def ask_bot():
while True:
bot_str = input('Enter a string for the player to guess: ')
bot_str = space_cull(bot_str)
bot_str = make_lower(bot_str)
bot_str = check_alpha(bot_str)
if bot_str == '':
print('That is not a correct string, try again')
else: # returns the string if the input is correct
return bot_str # this still breaks out of the function and the loop
# but only if the string has passed the checks
As other answers already mention, you could use str.isalpha() to check that the string is valid, or if you would like to modify the string in place you will need to adjust your check_alpha function like so:
def check_alpha(the_str):
the_str =''.join([char for char in the_str if char.isalpha()])
return the_str
As John Gordon already mentioned the solution is the method "isalpha" of the "str" class.
userInput = input("Your suggestion: ")
if userInput.isalpha():
# do some magic
else:
print("please only type in letters")
You don't need the check_alpha(str) function at all. Modify the ask_bot() as follows.
def ask_bot():
while True:
bot_str = input('Enter a string for the player to guess: ')
bot_str = space_cull(bot_str)
bot_str = make_lower(bot_str)
if not bot_str.isalpha():
if bot_str.isnum():
print("The entered string is a number")
continue
if bot_str == '':
print('That is not a correct string, try again')
continue
continue
break
return bot_str
ask_bot()
So I set out to make a simple game of hangman and everything worked fine, the whole code worked but it lacked the ability to allow the user to replay when the game is over. Thus I set out to put all the code I have written in various functions. So that I can call the functions when they are required (I thought it was the most logical way to allow replay-ability). Various problems followed but one stood out.
The main culprit (I think) is that I could not successfully get a value to update globally. I've read similar questions on the site but could not successfully adapt it to my case. I have a sample code to show what exactly I mean:
def GameMode():
choice = input('Play alone or play with friends? A F : ')
choice = choice.upper()
if choice == 'A':
wordslotmachine = ['stand','emerald','splash']
word = random.choice(wordslotmachine)
word = word.upper()
Rules()
elif choice == 'F':
word = input('Enter your word for your friends to guess: ')
word = word.upper()
Rules()
else:
choice = input('Please enter A or F: ')
choice = choice.upper()
I would need the program to remember what the value of "word" is and use this word in another method (this method is ran by another method showed below "Rules()"):
def MainGame():
guesses = ''
turns = 10
underscore = 0
seconds = 1
checker = 0
cheaterchance = 5
while turns > 0: #check if the turns are more than zero
for char in word: # for every character in secret_word
if char in guesses: # see if the character is in the players guess
print(char+' ', end='')
else:
print('_ ', end='')# if not found, print a dash
underscore += 1
if underscore == 0:
print(': You got it!')
Wait()
NewGame()
break
#A block of if's to check for cheating
if guess not in word:
print('Your guesses so far: '+guesses)
turns -= 1
if turns == 0:
break
else:
print('')
print('Try again. You have',turns,'more guesses')
print('Delayed chance to answer by',seconds,'seconds')
counter = 1
print(0,'.. ', end='')
while counter < seconds:
time.sleep(1)
print(counter,'.. ', end='')
counter += 1
if counter == seconds:
time.sleep(1)
print(counter,'.. done!', end='')
print('')
print('')
seconds += 1
underscore = 0
else:
print('Your guesses so far: '+guesses)
underscore = 0
#The else portion of the code to check for cheating
I have tried defining "word" outside of the function. Doing this doesn't fix the problem, GameMode() will not successfully update the value of "word". And whatever the value of "word" defined outside of the function will be called and used by MainGame(). However doing this shows another problem.
That being, the code that previously worked (it successfully read the input and correctly updated the game status) now does not work. Even if the correct letter is entered by the user, the program reads the input as incorrect.
These are the two problems I have faced so far and have yet to find a way to overcome them.
Note: I have successfully created a way to make the game replay-able by putting the entire original code (without the functions) inside a while loop. However I would still very much like to know how I can get the code to work using functions.
Edit: This is the function for Rules():
def Rules():
#Bunch of prints to explain the rules
MainGame()
print('Start guessing...')
Wait() is just a delay function with a countdown.
Global vs. Local variables.
You can reference and use a global variable from within a function, but you cannot change it.
It's bad practice, but you CAN declare a variable within your function to be global and then changes to it inside your function will apply to the variable of the same name globally.
HOWEVER, what I suggest is to return the word at the end of your function.
def whatever_function(thisword):
do some stuff
return word
new_word = whatever_function(thisword)
Functions can, and usually should, return values. Make GameMode() return the word to the caller;
def GameMode():
choice = input('Play alone or play with friends? A F : ')
choice = choice.upper()
if choice == 'A':
wordslotmachine = ['stand','emerald','splash']
word = random.choice(wordslotmachine)
word = word.upper()
Rules() #ignore this
elif choice == 'F':
word = input('Enter your word for your friends to guess: ')
word = word.upper()
Rules() #ignore this
else:
choice = input('Please enter A or F: ')
choice = choice.upper()
return word
From the main call GameMode and save the word;
def MainGame():
guesses = ''
turns = 10
underscore = 0
seconds = 1
checker = 0
cheaterchance = 5
word = GameMode() # add this here
You almost certainly want to use a class with instance variables
Contrived example:
class Hangman:
def __init__(self):
print("Starting hangman")
def mode(self):
# ...
self.word = 'whatever'
def play(self):
print("Look i have access to word", self.word)
if __name__ == '__main__':
hm = Hangman()
hm.mode()
hm.play() # may be what you want to put in a while loop
To access a global variable from inside a function, you have to tell python that it is global:
my_global_var = 1
def some_func():
global my_global_var
You have to use global keyword in every method that the global variable is being used or python will think you are defining/ using a local variable
Having said that, you should avoid globals as a coding practise.
global word #probably define this after imports.
def GameMode():
global word #add this
choice = input('Play alone or play with friends? A F : ')
choice = choice.upper()
if choice == 'A':
wordslotmachine = ['stand','emerald','splash']
word = random.choice(wordslotmachine)
word = word.upper()
Rules() #ignore this
elif choice == 'F':
word = input('Enter your word for your friends to guess: ')
word = word.upper()
Rules() #ignore this
else:
choice = input('Please enter A or F: ')
choice = choice.upper()
def MainGame():
guesses = ''
turns = 10
underscore = 0
seconds = 1
checker = 0
cheaterchance = 5
global word # add this here
use the code
global word
above the def or let the def return the value of word so it is stored in a variable outside the def
For starters here is my current code:
import ipaddress
class Net():
def __init__(self, ip, mask):
self.ip = ip
self.mask = mask
def getipmask(self):
return self.ip, self.mask
def __mul__(self, ip1, ip2, sn1):
ip1_Bin = [bin(int(ip1))[2:].rjust(8,'0') for ip1 in ip1.split('.')]
IP1 = ''.join(ip1_Bin)
ip2_Bin = [bin(int(ip2))[2:].rjust(8,'0') for ip2 in ip2.split('.')]
IP2 = ''.join(ip2_Bin)
sn_Bin = [bin(int(sn1))[2:].rjust(8,'0') for sn1 in sn1.split('.')]
SUB1 = ''.join(sn_Bin)
IP1Final = (IP1 + "/" + SUB1)
IP2Final = (IP2 + "/" + SUB1)
if ipaddress.ip_address(IP1Final) in ipaddress.ip_network(IP2Final, strict=False):
print("")
print("Same Subnet!")
else:
print("")
print("Different Subnet!")
userIP = None
name_list = ['A', 'B', 'C', 'D', 'E']
net_dict = {}
while True:
userIP = input("Enter IP (type 'end' to exit): ")
if userIP == 'end':
break
userMask = input("Enter Mask: ")
name = name_list.pop(0)
net_dict[name] = Net(userIP, userMask)
#print out all ip/mask combos with proper names
print('')
for x in net_dict:
print(x, "-->", net_dict[x].getipmask())
print('')
#evaluations
while True:
userFuncIn = input("Please enter a function (e.g. A+B). Enter 'end ' to stop: ")
charList = list(userFuncIn)
#Get the object letters
charList_Objs = charList[0:][::2]
#Get the operators
charList_Ops = charList[1:][::2]
#assign letter value to proper ip and subnet values
for x in charList_Objs:
x = net_dict[x].getipmask()
#Get number of operators
numberofOps = len(charList_Ops)
#while charList_Ops still has operations
while len(charList_Ops) != 0:
#current operator
operator = charList_Ops.pop(0)
#xpression with proporly assigned values on objects
expression = [charList_Objs[0], operator, charList_Objs[1]]
#convert from list to string to use in eval
exp_str = "".join(expression)
#Delete objects 0 and 1 from the charList
del(charList_Objs[0:1])
print(eval(exp_str))
What should be happening is after all the user's inputs are displayed with their corresponding letter they are able to enter what function they want to preform. For now to keep it simple I am just focusing on __mul__. What __mul__ will do is take in two IP/subnet combos and evaluate them to see if they are on the same subnet. I can fix the code in the __mul__ function once I properly figure out how I am to get the user's function entry to work properly. So if user enters A*B. It should take A and B from net_dict and then send those 2 key/value pairs to the overridden __mul__ function to perform. The correct action.
Any help or suggestions would be much appreciated.
PS: Other functions (not __mul__) will allow for multiple operations and multiple IP/subnet pairs. For example (A+B+C) so that is why I added charList_Ops and charlist_Objs. If it was just a case where there was always 3 chars in the user entered function (e.g. A*B) that would obviously not be needed.
This is tricky. The naive way to do this is of course just eval, but that's ugly. Instead let's do this:
import re
import operator
operators = {"*": operator.mul,
"+": operator.add,
"-": operator.sub,
"/": operator.truediv} # add or delete from this dict as desired
re_splitters = re.compile('|'.join([re.escape(splitter) for splitter in operators.keys()])
user_input = input("Here's a prompt! ")
Alice, Bob = map(net_dict.get, re_splitters.split(user_input))
# this may give you errors if you have a poorly formed user input. Catch and handle
# those errors as appropriate
action = re_splitters.search(user_input).group(0)
result = operators[action](Alice, Bob)
You could also do:
Alice, Bob = re_splitters.split(user_input)
# YOU MUST CHECK HERE THAT ALICE AND BOB ARE BOTH IN net_dict
action = re_splitters.search(user_input).group(0)
if action:
result = eval("net_dict[{}] {} net_dict[{}]".format(Alice, action, Bob))
# strong warning about an injection vulnerability!
But imagine the case where you fail to check if Alice and Bob are in net_dict and a malicious user does:
>> # User input below:
known_key];import os;os.system("format C:");net_dict[known_key+known_key
Which then becomes:
net_dict[known_key]
import os
os.system("format C:")
net_dict[known_key] + net_dict[known_key]
Congratulations, the hard drive is now toast.
I'm working on a simple text based hangman game in python. I have a rough program running but I've encountered two minor problems:
Why does the welcome message print twice?
When the user inputs a letter not in the word two times in a row, the second time, the "nope, try again"-message does not display and current word does not display. The first time an incorrect letter is input, it works. Why doesn't it work the second time?
from random import randrange
class HangmanApp:
def __init__(self, interface):
self.infile = open("hangman.txt", "r")
self.interface = textInterface()
for line in self.infile:
self.wordlist = line.split()
self.secretword = self.wordlist[randrange(len(self.wordlist))]
self.letter_list = list(self.secretword)
#tests the user's guess
def guess(self):
self.new_list = ["_"]*len(self.secretword)
#keep loop going as long as there are letters in the list
while self.letter_list != ["_"]*len(self.letter_list):
self.guess = self.interface.guess()
if self.guess in self.letter_list:
while self.guess in self.letter_list:
i = self.letter_list.index(self.guess)
#replace that letter from the list with "_"
self.letter_list[self.letter_list.index(self.guess)] = "_"
#add the chosen letter to a new list for display
self.new_list[i] = self.guess
#print list with letter added
self.interface.correct(self.new_list)
else:
self.interface.incorrect(self.new_list)
self.guess = self.interface.guess()
class textInterface:
def __init__(self):
print("Welcome to Hangman!")
def guess(self):
guess = input("Guess a letter! ")
return guess
def display (self, word):
string = ' '.join(word)
print(string)
def incorrect(self, word):
print("Nope, try again")
self.display(word)
def correct(self, word):
print("Correct")
self.display(word)
def main():
inter = textInterface()
app = HangmanApp(inter)
app.guess()
The welcome message is printed twice because you're creating two instances of textInterface: one in main() and another inside HangmanApp.__init__(). I think you meant to do:
self.interface = interface
instead of
self.interface = textInterface()
Inside HangmanApp.guess(), after receiving an incorrect guess (reaching the else: clause) you have an extra guess prompt that is not needed---one that doesn't pass through your checking code. I think this is probably causing the issue with it not working the second time around.