I am trying to code a simple hangman game in python with a gui using tkinter. I have the gui frame set up with a user entry. The problem is when I enter a letter then run the code by pressing the play button it runs the letter through the code until the code runs out of lives (10 times). How can i improve my code so a letter is only run through once then a new letter can be input to guess again?
thank you
from numpy import*
from Tkinter import*
#set up gui frame
win=Tk() #create window assigned to variable win
welc=Label(win,text="Welcome to Hangman!").grid(row=0)
inst=Message(win,text="instructions: To play start by guessing a letter in the secret word. if the letter is in the word it will fill in a blank if not you lose a life. Continue guessing untill you have guessed the secret word.").grid(row=1)
guess_text=Label(win,text="Enter a letter or Word").grid(row=2)
blank_text=Label(win,text="Secret Word").grid(row=3)
lives_text=Label(win,text="Lives Remaining").grid(row=4)
e=Entry(win)
e.grid(row=2,column=1)
#library of secret words
lib=['hanakah','christmas','holly','thanksgiving','reigndeer','family','presents','santa','kwanza', 'chocolate', 'cheesecake']
n=len(lib)
#randomly pick secret word
inx=random.randint(1,n)
secret=lib[inx]
#set up game
lives_remaining=10
guessed_letters=''
#define function to play game
def play():
word=secret
while True:
guess=get_guess(word)
print guess
print type(guess)
if process_guess(guess,word):
Label(win,text="You Win!").grid(row=6)
break
if lives_remaining==0:
Label(win,text="You Lose!").grid(row=6)
Label(win,text="The secret word was: "+word).grid(row=7)
break
Button(win,text=("Play"),command=play).grid(row=5,column=0)
def get_guess(word):
blanks(word)
guess=e.get()
return guess
#diplay guessed letter in postion of word
def blanks(word):
Label(win,text=lives_remaining).grid(row=4,column=1)
display_word=''
for letter in word:
if guessed_letters.find(letter)> -1:
#LETTER found
display_word=display_word+letter
else:
#letter not found
display_word=display_word+'-'
Label(win,text=display_word).grid(row=3,column=1)
def process_guess(guess,word):
if len(guess)>1 and len(guess)==len(word):
return whole_word_guess(guess, word)
else:
return single_letter_guess(guess, word)
def whole_word_guess(guess, word):
if guess.lower() == word.lower():
return True
else:
lives_remaining=lives_remaining+(-1)
return False
def single_letter_guess(guess, word):
global guessed_letters
global lives_remaining
if word.find(guess) == -1:
# letter guess was incorrect
lives_remaining = lives_remaining+(-1)
guessed_letters = guessed_letters + guess.lower()
if all_letters_guessed(word):
return True
return False
def all_letters_guessed(word):
for letter in word:
if guessed_letters.find(letter.lower()) == -1:
return False
return True
mainloop()
I think I understand now.
The get_guess function is always pulling whatever info is in the e Entry, it's not waiting for the value of e to change.
A simple fix without creating listeners would be to create a new global variable called last_guess which can be initialized to '' and then passsed to get_guess as a 2nd arg to check if the guess has changed:
def get_guess(word, last_guess):
blanks(word)
guess=e.get()
#If the guess has not changed ret false
if guess == last_guess:
return False
#If the guess has changed update the last_guess
else:
last_guess = guess
return guess
And then in the main While loop:
while True:
guess=get_guess(word)
print guess
print type(guess)
if not guess: #<-- If the get_guess returned False
continue #<-- Just go on to on to the next iteration of the loop w/out updating lives etc
if process_guess(guess,word):
Label(win,text="You Win!").grid(row=6)
break
if lives_remaining==0:
Label(win,text="You Lose!").grid(row=6)
Label(win,text="The secret word was: "+word).grid(row=7)
break
I haven't run this code so it might have errors, but I think the general idea will work
Related
I have this function I have built and it seems like I am missing something very minor here. This loop will not call for some reason. Indentation looks good and I am not getting any errors in my output, but the data is not being updated which you can see by the debug print statement I made not showing in the terminal.
Below is the function I am speaking of:
def updatefield(layer, prev_data):
print("DEUBG:: UPDATE FIELD")
fname, ftype, fdict = field_attr(prev_data)[0], field_attr(prev_data)[1], field_attr(prev_data)[2]
arcpy.AddField_management(
in_table=layer,
field_name=fname,
field_type=ftype,
field_is_nullable="NULLABLE"
)
# Use UpdateCursor to expedite the copy of the data to the new field.
with arcpy.da.UpdateCursor(layer, [prev_data, fname, "OID#"]) as uc:
print("DEUBG:: UPDATE CURSOR: {}".format(layer))
for record in uc:
print("\tDEBUG:: record: {}".format(record)) # THIS NEVER GETS CALLED
if record[0] in fdict.keys():
record[1] = fdict[record[0]]
else:
if layer == fms_conduit:
record[1] = None
# Can't recall if you can have empty keys...These also pretty much only apply to fiber.
elif prev_data == "CATEGORY" and record[0] == "":
record[1] = "OTH"
elif prev_data == "CABLECAPACITY" and (record[0] in ('', ' ', None)):
record[1] = 0
elif prev_data == "CABLECAPACITY":
record[1] = int(record[0])
else:
record[1] = ""
print("\nDEBUG:: OID: {}\tPrevField: {}\t NewFieldName: {}\tNewFieldValue: {}".format(
record[2], prev_data, fname, record[1])
)
uc.updateRow(record)
And here is the output:
The final few debug print statements are from another function but I should be getting that record printed. Again, probably something silly but I can't seem to get it.
Thank you for your time.
Turns out the data that was delivered to me was truncated at some point. The update cursor was empty and therefore nothing was being translated.
I need to send a user text input to the robot through the integrated tablet, and catch it somehow, for further processing in Choregraphe.
After reading the Aldebaran documentation about ALTabletService API, I found few methods which might be a solution to all this. The methods are ALTabletService::showInputTextDialog and ALTabletService::onInputText, but somehow I can't get them to work: they return absolutely nothing when I input some text through the tablet.
I need access to the string created when the user inputs a piece of text. Any advice how to do it?
i realized this without ALTabletService methods showInputTextDialog or onInputText
My Approach:
I made an html page with an input field and a button to send the input.
On button press I use the forceInput method from ALDialog doc via QiMessaging Javascript library. doc
I can't test it right now but this should help as a inspiration
function forceInput(input) {
QiSession(function(session) {
session.service('ALDialog').then(function(ALDialog) {
ALDialog.forceInput(input);
});
}
}
Now you can send the input to the topic.
This could be sth like "imput_from_tablet blablabla".
And in the Dialog you catch
u:(imput_from_tablet _*) $1
Where $1 should be blablabla.
Hope that helps
best regards
You can create a webpage for the tablet and package it in your application - see the documentation here; then on that webpage you can create a text input field (be careful that the bottom half of the screen will be hidden by the keyboard when the field is selected), and then use the javascript SDK to (for example) raise an ALMemory event with the inputted text value, that you can then get from Choregraphe.
I had exactly the same problem and I found this ALTabletService::onInputText method in the signal list. You can find examples how to use signals on the same page. Based on these examples I created the following script that can get a value from the input field:
import qi
import sys
def main(app):
try:
session = app.session
tabletService = session.service("ALTabletService")
tabletService.showInputTextDialog("Example dialog", "OK", "Cancel")
signal_id = 0
def callback(button_id, input_text):
if button_id == 1:
print "'OK' button is pressed."
print "Input text: " + input_text
if button_id == 0:
print "'Cancel' button is pressed"
tabletService.onInputText.disconnect(signal_id)
app.stop()
# attach the callback function to onJSEvent signal
signal_id = tabletService.onInputText.connect(callback)
print "Signal ID: {}".format(signal_id)
app.run()
except Exception, e:
print "Error was: ", e
if __name__ == "__main__":
ip = "10.0.10.254" # the IP of the robot
port = 9559
try:
connection_url = "tcp://{}:{}".format(ip, port)
app = qi.Application(url=connection_url)
app.start()
except RuntimeError:
print("Can't connect to Naoqi.")
sys.exit(1)
main(app)
Whenever I hit space bar I get this error: "Attempt to call field "resume" a nil value."
The intention is to the hit space bar once to stop the audio, and hit it again to resume.
if(key == "space") then
love.audio.pause()
paused = true
end
if paused == true then
if (key == "space") then
love.audio.resume()
end
end
Things I tried:
Changing "==" to "=" and vice versa;
Using "and" to avoid the nested "if" statement.
Documentation (if needed): http://love2d-community.github.io/love-api/#audio_resume
Any help is appreciated, and thank you for your time.
if key == "space" then
if paused then
love.audio.resume()
else
love.audio.pause()
end
paused = not paused
end
But love.audio.resume was removed in LÖVE 11.
Use love.audio.play instead.
I'm having trouble removing a widgets with a label once it's added
Here's the relevant piece of code:
logi= True
if data == []:
logn =Label(text= "Incorrect Username",color=(190,0,0,1),
pos_hint={"right":1.035,"top":1.14})
self.add_widget(logn)
logu =Label(text= "Incorrect Password",color=(190,0,0,1),
pos_hint={"right":1.035,"top":1.04})
self.add_widget(logu)
logi= False
if logi == True:
textinput.text=''
textinput2.text=''
if 'logn' in locals() and 'logu' in locals() :
self.remove_widget(logn)
self.remove_widget(logu)
once the widgets have been added I can't seem to remove them, if i remove the if 'logn' in locals() and 'logu' in locals() :statement I get an error "Local variable referenced before assignment " every time I test this without the above mentioned if statment I make sure the widgets have been added
I assume you are entering this method twice (1st data==[] 2nd time data=[...]). So You should keep your variables at hand (put them on the instance - self)
logi= True
if data == []:
self.logn =Label(text= "Incorrect Username",color=(190,0,0,1),
pos_hint={"right":1.035,"top":1.14})
self.add_widget(self.logn)
self.logu =Label(text= "Incorrect Password",color=(190,0,0,1),
pos_hint={"right":1.035,"top":1.04})
self.add_widget(self.logu)
logi= False
if logi == True:
textinput.text=''
textinput2.text=''
if hasattr(self, 'logn'): #check that we put something here before...
self.remove_widget(self.logn)
self.remove_widget(self.logu)
Note all the places I've added self ...
The gets function in crystal is not waiting for user input. When I start my console application it immediately outputs an error like the one below. It is saying that the second parameter given to the in_array function is Nil but the program doesn't even ask for user input.
My code looks like below.
# Only alice and bob are greeted.
def in_array(array : Array, contains : String)
array.each { |e|
if e == contains
return true;
end
}
return false;
end
allowed = ["Alice", "Bob"]
puts "Please enter your name to gain access."
name = gets
isAllowed = in_array(allowed, name)
if isAllowed
puts "You can enter the secret room"
else
puts "You are not allowed to enter the secret room."
end
The new version of my code using includes? and read_line
# Only alice and bob are greeted.
allowed = ["Alice", "Bob"]
puts "Please enter your name to gain access."
name = read_line.chomp
if allowed.includes?(name)
puts "You can enter the secret room"
else
puts "You are not allowed to enter the secret room."
end
But when I enter Bob into the name variable the includes? method returns false and executes the else statement.
A few things:
The error you are seeing is a compile error. This means that your program is not running, it failed to compile.
gets can return nil (as indicated in the docs), for example if the user presses Ctrl+C, so you have to handle this. You can either do if name = gets, use gets.not_nil! if you don't care about this case, or use read_line which is equivalent to gets.not_nil!
Array has a method includes? that does what you are trying to implement