Hi, I'm in need of some help in using functions for the hangman game. The professor doesn't understand how difficult it is for a first time programmer and just doesn't explain new concepts thoroughly. The game that I'm trying to code looks like this:

Enter the secret word: LETTERS

------------------------------------------------------------

Word so far: _______
Misses: 0
What letter would you like to guess? E

Word so far: _E__E__
Misses: 0
.
.
.
.
Word so far: _ETTERS
Misses: 3
What letter would you like to guess? L

You guessed the secret correctly: LETTERS

So Here's what i have so far:

#stuff the first person sees
def get_secret(word):
    """Get the secret word/phrase"""
    input = raw_input(word)
    Words_so_far = "_ " * len(word)
    Misses = 0
    max_wrong = 5
    
#Stuff the second person sees
word = raw_input("Enter the secret word:")
display = len(word)
print display 
print word
print "\n"*10
print "_ " * display


def do_turn(display,misses):
    """
    Display the current status for the user and let them make a guess.
    """

These were the tips the Prof gave, and so I'm just wondering if someone can help me on what the next step is. I can honestly say that it took me 3 hours to type the code that I have shown you. I don't want to get accused for plagiarism of any sort, so I would like a step by step help as if I were going to ask my prof for help. I'm sorry if this post is super long but here's the tips that my prof gave:

Start by creating a function get_secret that asks the user for the secret word/phrase, clears the screen, and returns the secret string.

def get_secret():
"""
Get the secret word/phrase.
"""
In the main part of the program, call the get_secret function and store the result in secret. Create a string display that contains len(secret) underscores.

The string display will be what we show the user as they are guessing. The underscores will be replaced with letters as they are guessed.

Create a variable to count the number of incorrect guesses the user has made (“misses”) and initialize it appropriately. You will also need to keep track of the number of unguessed letters left in the secret: this (along with the count of the misses) will be used to decide when the game is over.

Create a function do_turn that takes two arguments: the display string, and the number of misses made so far. This function should do the part of the turn the user sees (display the part of the secret they have guessed, display the number of misses, and ask them to guess a letter).

def do_turn(display, misses):
"""
Display the current status for the user and let them make a guess.
"""
Don't worry about the error checking (exactly one letter). The function should return the letter the user enters.

Once we have both the secret word, and a guess, we need to be able to update the display string, and keep track of the number of letters discovered. Create a function new_display that takes three arguments: the secret, the display string, and the letter the user guessed.

Once it has these values, the function can calculate the new value for the display string (i.e. replace all of the underscores where the letter the user guessed is the letter). While it does this, it can count the replacements.

Both of those values (the new display string string, and the replacement count) should be returned. A Python function can return multiple values like this:

return newdisp, count
Then, you can call the function and capture both return values like this:

display, count = new_display(…)

Well, just to give you a bit of confidence ... the prof has given you good advice. Now for the details ... !

First, you need to plan your code. Make a plan (sometimes called pseudocode) that doesn't go into the details, but clearly and generally spells out exactly how the game will be played. By "generally", I mean that you can say things like

...
while True:
   letter = do_turn
   if letter in puzzle and letter not in already_used:
      add_to_puzzle
   else:
      increase_misses
      print message
...

So you can see that the plan doesn't give any details as to HOW some of these steps will happen; it's just a big-picture plan.

Do that first. Post it here if you like, and we can give pointers.

Then, create each function. I would do each function separately and make sure it works by testing it. The testing happens by passing the function typical arguments, and making sure it gives the right return values back.

Thus:

# Code version 1

def get_secret():
    """Get the secret word/phrase"""
    input = raw_input(word)
    # etc.

# test get_secret
word = get_secret()
print word
# Code version 2

def get_secret():
    """Get the secret word/phrase"""
    input = raw_input(word)
    # etc.

def do_turn(display, misses):
   print display
   # etc.

# test get_secret
word = get_secret()
print word

# test do_turn
display = "_ETTE_"
misses = 2
letter = do_turn(display, misses)
print letter

And so on. The idea here is this:

(1) Each function should do *one* thing. (The version of get_secret in your code tries to do too much, which paradoxically makes it less useful because it has trouble fitting into the big picture.

(2) The purposes of making functions are to (a) isolate actions like do_turn so that you can focus on just doing that one thing (that's the main benefit for you now), and (b) creating code that can be reused elsewhere (that's the main benefit as you get further along).

(3) As you write the functions, focus on the requirements your prof has given. Pay attention to what the function should receive, and make sure it returns what it should return. Functions should, for the most part, not have side effects besides returning the value that is specified.

So: make a plan. Then make functions, one at a time, and test them.

Then finally, put the functions together in your code according to the plan. And it should all work out! (hah-hah...debugging often takes a while :))

Hope it helps,
Jeff

Thanks for the tips, I'm a bit less frustrated now, since you gave me some ideas that could help me out.

This is my pseudocode that I thought of:

write "Enter the secret word"
.
.
.
write guess a letter
while misses is less than 6 and guess is not equal to secret word
    write guess a letter
        if letter guessed is in secret word, then
            add letter to display and replace underline
        else: increase misses by 1
            print display
    if letters guessed equals secret word
        print congratulations, you got the secret word

Here's my new code so far, and I'm still stuck on how to get the user to guess a letter and for it to display the underscores and misses from the function "do_turn". I guess I'm having trouble understanding "calling/returning" a function that's defined. Do i call in the function or out the function? Also, when asking the user for a letter, do i ask in the function or out?

So here's my code so far, and it isn't running too smoothly either. Any help would be great. I really appreciate it.

#stuff the first person sees
def get_secret(secret):
    """Get the secret word/phrase"""
    guess = raw_input(secret)
    
    
#Stuff the second person sees
def do_turn(display,misses):
    """
    Display the current status for the user and let them make a guess.
    """
    misses=0
    guess = raw_input("What letter would you like to guess?")
    while misses < 6 and guess!=secret:
        
        for i in range(len(secret)):
            if guess != secret[i]:
                misses = misses +1
            print str(misses)
            display = "_ " * len(secret)
            print display
            
guess = get_secret(secret)
print guess


letter = do_turn(display,misses)
print letter

Thanks again!

Your pseudocode is a great start!

Four things:

(1) You need to not simply write "Enter the secret word", but also store it.

(2) The last if clause can come outside the loop, since if guess the secret word, then the loop will exit ("fall through").

(3) All variables need to be initialized. This would be easy to catch in the code, since Python would complain the first time you tried to check "misses < 6"

(4) There is no need for the guess a letter outside the loop.

So we might tweak it like this:

get secret word
initialize misses to 0
initialize guess to "_"*len(secret word)
while misses is less than 6 and guess is not equal to secret word
    write guess a letter
        if letter guessed is in secret word, then
            add letter to display and replace underline
        else: increase misses by 1
            print display
if letters guessed equals secret word
        print congratulations, you got the secret word
else: print sorry

As you turn the pseudo-code into code, this will get refined.

Now about functions:

Think of a function as a dedicated servant. You "call" the servant to fetch you a burger("cheese", "ketchup", "lettuce", "medium-well"), and the servant returns the burger to you.

So here's an example relevant to your code:

# create the function -- this code gets stored, but not executed.
def new_display(secret_word, old_guess, letter):
    
    # flip the secret word and the guess: turn A into _ in secret word and _ into A in guess.
    while True:
        if letter in secret_word:
            index = secret_word.find(letter)
            secret_word = secret_word.replace(letter, "_",1)
            old_guess = old_guess[:index]+letter+old_guess[index+1:]
        else:
            break
    return old_guess

# call the function for testing purposes
# initialize variables
misses = 0
guess = "_E__E_"
secret = "LETTER"

# call the function with single letter
letter = "R"
guess = new_display(secret, guess, letter)

# check the output
if guess == "_E__ER":
    print "R: Test passed"
else:
    print "R: Test failed"

# call again with double letter
letter = "T"
guess = new_display(secret, guess, letter)

# check output
if guess == "_ETTER":
    print "T: Test passed"
else:
    print "T: Test failed"

# call with letter not in puzzle
letter = "Z"
guess = new_display(secret, guess, letter)

# check output
if guess == "_ETTER":
    print "Z: Test passed"
else:
    print "Z: Test failed"

This is not necessarily the most elegant way to code the new_display, but it illustrates some things.

First, note that when the function is *defined*, nothing happens ... except that the code for the function is stored in a location labeled "new_display". Note that if you later make a variable called "new_display", it will clobber the function! :lol:

Second, note that we call the function from the main code itself. You can call functions from within other functions as well. But for beginning projects, the usual plan is

def fn1
def fn2

main code calls fn1 and fn2 as needed

Third, note that the "arguments" (your prof may use the term "parameters") of the function are the values that the main code must supply to the servant in order for the servant to do his job. In this case, the servant needs to know the secret word, the current guess, and the guessed letter.

Fourth, note that the return value (at the end of the function, although functions can also return from the middle if an early exit is needed) is the command to our servant to bring back the requested result.

Fifth, note that our servant has but one job to do: to run through the secret word, and fill in any corresponding position in the guess with the letter given. He doesn't print stuff; he doesn't update the number of misses; he only replaces _ with letter.

So now, having tasked our servant with this one job, we call him anytime we need his service.

Sixth, notice that any scratch work the servant does is lost when the function returns. You can see in the definition of new_display() that I have the line secret_word = secret_word.replace(letter, "_",1) . You might think that this would cause the secret_word to get changed permanently in the main code. But actually, the function receives a copy of the secret_word, and when the function returns, all of its variables "go out of scope" -- that is, are forgotten.

This is why the return value is so important. It is the only result that the main code will ever see from the function.* The changes to old_guess that happen within the body of new_display() are not kept; this is why when the main code calls new_display(), it has to clobber guess with the return value: guess = new_display(secret, guess, letter) ; otherwise, those changes will be lost.

Does that help clear things up?

Jeff

* Not true for mutable objects like lists, but that's another story.

There's so much info that I'm getting confused. From the code I have above, I still don't know why secret is not defined in this code:

#stuff the first person sees
def get_secret(secret):
    """Get the secret word/phrase"""
    secret = raw_input(secret)
    
misses = 0
guess = "_ "*len(secret)
print guess
#Stuff the second person sees
def do_turn(display,misses):
    """
    Display the current status for the user and let them make a guess.
    """

    guess = raw_input("What letter would you like to guess?")
    while misses < 6 and guess!=secret:
        
        for i in range(len(secret)):
            if guess != secret[i]:
                misses = misses +1
            print str(misses)
            display = "_ " * len(secret)
            print display
            
guess = get_secret(secret)
print guess


letter = do_turn(display,misses)
print letter

I kind of understand what you're saying, but isn't "secret" stored in the function get_secret? so when i type guess = "_"*len(secret), isn't secret defined? This might be asking for too much, but do you think you can fix/delete whatever is wrong with my code right now so I can kind of start fresh. Everytime I get frustrated, I can't seem to think and this program is due tomorrow night (no sleep for me). I'll keep working on it, and if I figure it out, i'll post the updated code. Thanks again!

Sorry for the overload. :) Your code is improving.

Here's a walkthrough of your code up to the error:

lines 2-4: the function get_secret is defined. No code is executed yet; no variables are defined.

line 6: misses is set to 0

line 7: guess is set to "_" * len( ... wait, there is no variable called secret.

So you will definitely have to call get_secret before you try to set guess.

Two more issues, and then it'll work.

(1) get_secret() should not take secret as a parameter, since our servant should not have to know the secret in order to get the secret!

(2) get_secret() will have to return the secret in order for your main code to receive it. Watch the difference here:

## BAD ##
>>> def get_secret():
    """Get the secret word/phrase"""
       secret = raw_input("Enter the secret word: ")

>>> misses = 0
>>> get_secret()
Enter the secret word: phlerm
>>> guess = "_"*len(secret)

Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    guess = "_"*len(secret)
NameError: name 'secret' is not defined
>>>

Why the error? Because the variable 'secret' is defined within the function get_secret. It is a local variable; it is in the "namespace" of get_secret(). When get_secret() returns, all of the local variables "go out of scope" -- are forgotten. That is, our servant's scratchwork is thrown away.

So the remedy is to return the important result:

## GOOD ##
>>> def get_secret():
    secret = raw_input("Enter the secret word: ")
    return secret  # <<< 1

>>> misses = 0
>>> my_secret = get_secret()  # <<< 2
Enter the secret word: phlerm
>>> guess = "-"*len(my_secret)
>>> print guess
------
>>> print my_secret
phlerm
>>>

In the line marked <<< 1, the function returns the necessary value. This is its only means of communicating with the outside code.

In the line marked <<< 2, the main code calls the function and stores the return value in my_secret. This is the only means that the main code has of communicating with the function.

So the key is: all of the variables inside the function are private, or "local". The only connection the function has with the outside world is receiving parameters (when called) and returning a value back to the caller.

So here's the modified pair of functions:

# Define all your functions FIRST before the main code.

#stuff the first person sees
def get_secret():
    """Get the secret word/phrase"""
    secret = raw_input("Enter the secret word: ")
    return secret

#Stuff the second person sees
# This function was trying to do the whole game.  Your prof's directions gave you
# the design for this function.  It does one thing: get the user's guess.
def do_turn(display, misses):
    """
    Display the current status for the user and let them make a guess.
    """
    print display
    print "You have missed %d times." % misses

    guess = raw_input("What letter do you guess? ")
    return guess

misses = 0
secret = get_secret()
print secret

display = "-"*len(secret)
letter = do_turn(display,misses)
print letter

Hope it helps,
Jeff

So this is what I have now. I wanted to use your loop for replacing the underscores, but I don't think I was taught that complexity. Is there a way to replace the underscores using a different method in new_display?

Here's are the 2 codes for comparison, but unfortunately mine doesn't work.

#1

# Define all your functions FIRST before the main code.
#stuff the first person sees
def get_secret():
    """Get the secret word/phrase"""
    secret = raw_input("Enter the secret word: ")
    return secret


#Stuff the second person sees
# This function was trying to do the whole game.  Your prof's directions gave you
# the design for this function.  It does one thing: get the user's guess.
def do_turn(display, misses):
    """
    Display the current status for the user and let them make a guess.
    """
    return display
    print "You have missed %d times." % misses

    

#This is where we can update the letters guessed
def new_display(secret, display, guess):
    """Displays the replacement of underscores with letters that the user has guessed"""
    misses = 0
    while True:
        if guess in secret:
            index = secret.find(guess)
            secret = secret.replace(letter, "_",1)
            display = display[:index]+guess+display[index+1:]
        else:
            misses = misses+1
    return secret,display

misses = 0
secret = get_secret()
print secret

display = "-"*len(secret)
letter = do_turn(display,misses)
print letter

secret,display = new_display(secret,display,guess)
print secret,display

#2

# Define all your functions FIRST before the main code.
#stuff the first person sees
def get_secret():
    """Get the secret word/phrase"""
    secret = raw_input("Enter the secret word: ")
    return secret


#Stuff the second person sees
# This function was trying to do the whole game.  Your prof's directions gave you
# the design for this function.  It does one thing: get the user's guess.
def do_turn(display, misses):
    """
    Display the current status for the user and let them make a guess.
    """
    return display
    print "You have missed %d times." % misses

    

#This is where we can update the letters guessed
def new_display(secret, display, guess):
    """Displays the replacement of underscores with letters that the user has guessed"""
    misses = 0
    while True:
        for i in range (len(secret)):
            if secret[i] == guess:
                print guess
            else:
                misses = misses+1
    return secret,display

misses = 0
secret = get_secret()
print secret

display = "-"*len(secret)
letter = do_turn(display,misses)
print letter

secret,display = new_display(secret,display,guess)
print secret,display

I know when i used len(secret), secret isn't defined and so I don't know how to scan the letters for the secret way back in the first function.

Now I wish I knew some programming before coming to this course. Anyways, thanks for all your help Jeff. Much appreciated.

Not a problem. It's worth it to have people come back and say "It worked! I learned something!"

Let's focus on the new_display function and walk through it

#This is where we can update the letters guessed
def new_display(secret, display, guess):
    """Displays the replacement of underscores with letters that the user has guessed"""
    misses = 0
    while True:
        for i in range (len(secret)):
            if secret[i] == guess:
                print guess
            else:
                misses = misses+1
    return secret,display

So imagine dispatching the function and saying, "Here's the secret word 'phlerm', the current display '------', and the guess 'e'."

At line 4, misses is set to 0. This is NOT the same variable as 'misses' in the main code, because it is inside the function. It is a local variable.

At line 5, we begin the loop. Since the condition will never be false, we'll need to break or return out of the loop somewhere...

At line 6, we begin a for-loop. Since our secret word is 'phlerm', the range(len(secret) is [0,1,2,3,4,5], so we have "for i in [0,1,2,3,4,5]:"

At line 7, we check secret against 'e' and print it if it is. This will work out like this:

i screen
0
1
2
3 e
4
5

otherwise (line 10), misses += 1. So by the time the for loop is done, there will be an e on the screen and misses will be 5.

And then, because we're done with the for loop, the while loop now executes again ... printing another e and bringing misses up to 10. And then....

You get the idea. This was definitely not what you had in mind. For one thing, the display variable never gets updated. For another, you didn't want to print stuff on the screen.

So what did you have in mind? Write a plan for new_display(). NOTICE that new_display() does not have the responsibility of keeping track of the misses. That's not its job!

Jeff

so where in the code should i update misses or display misses? should it be in the function do_turn because that's where teh display gets updated?

i suppose my plan is that while True, if the letter is guessed correctly, it will scan the letters in secret and if it matches, the letter guessed would replace the underscore. the loops still continues until misses are less than 6 or until letters guessed is equal to the secret word. also, for each correct guess, the misses should not increase, therefore i should create an if,elif, else block?

I guess what i'm also confused about are where the variables should be, inside the function or part of the main code.

The variables should be inside the main code. All variables inside the function are "local" -- scratchwork, basically -- and will be forgotten when the function returns.

So the main code is going to keep track of the secret, the current display, the number of misses, and the user's guess.

Your plan is more like the plan for the overall game rather than for new_display(). What new_display needs to do is simply take the secret, the current display, and the guess and return the new display. So my plan would be something like

for i in range(len(secret)):
   if the guess is equal to secret[i], the new display[i] = guess.
   otherwise, the new display[i] = old display[i].

Then return the new display

See whether that plan works and then turn it into code. The only trick will be that you can't directly assign to a string (display = "h" gives an error). So you'll need a different way to build up the new display string.

Jeff

You only have to update the "display" variable and keep track of misses as in this snippet.

def new_display(secret, display, guess, misses):    
      """Displays the replacement of underscores with letters that the user has
      guessed"""
      index=secret.find(guess)
      display_list=[ eachltr for eachltr in display ]
      if (index > -1) and (display_list[index]=="_"):  ## not already replaced
         display_list[index]=guess
         display="".join(display_list)
      else:
         misses += 1
      return display, misses

It would be simplier if "display" were declared as a list and you only worked with a list. That would avoid converting to a list and then converting back to a string.

Good point wooee, except that his prof specified the function header for new_display as

new_display(secret, display, letter) --> new_display, replacement count.

So he pretty much has to do it as above, except that I left out the part about "replacementcount += 1" (Oops)

Jeff

I changed a bit of stuff here and there but the output looks like i'm getting somewhere. I still can't grasp the idea of how to write a code creating a variable to call the function to replace the underscore. here's my code so far:

#stuff the first person sees
def get_secret():
    """Get the secret word/phrase"""
    secret = raw_input("Enter the secret word: ")
    return secret


#Stuff the second person sees
def do_turn(display, misses):
    """
    Display the current status for the user and let them make a guess.
    """
    return do_turn
    print "You have missed %d times." % misses
    guesses = raw_input("What letter would you like to guess?")
    return guesses

#This is where we can update the letters guessed
def new_display(secret, display, guess):
    """Displays the replacement of underscores with letters that the user has guessed"""
    while True:
        if guess in secret:
            display = display.replace("_", guess)
        else:
            misses = misses + 1
    return display, guess


secret = get_secret()
print secret

misses = 0
display = "Words so far:" + "_"*len(secret)
letter = do_turn(display,misses)
guesses = do_turn(display, misses)
print guesses
print letter
print display

guess = raw_input("What letter would you like to guess?")
display,guess = new_display(secret,display,guess)
print display,guess

and wow, 300 views...i wonder if my fellow classmates are reading this. if so, try not to coompletely copy my code incase the prof questions my code being similar to others. lol =)

OK,

(1) what's the purpose of line 13, "return do_turn"? 'Cause what that does is return the entire function code itself ... not something useful in most cases. I think if you just take it out, the function works as needed.

(2) In new_display, line 23 has the effect of replacing the *first* _ character with the guess.

(3) the "while True" loop that starts in line 21 will never exit.

(2) and (3) together suggest that you want to think about

* How do you know which _ in guess to change? and
* How do you know when to stop checking and return the result?

(4) What's the purpose of calling do_turn twice in lines 34 and 35?

Jeff

I always got the impression that I should return the function or variables within the function in order for me to get an output from it in the main code. Should I have my while loop in the main code then? Since it will only recognize the first "_", will this be better?

#This is where we can update the letters guessed
def new_display(secret, display, guess):
    """Displays the replacement of underscores with letters that the user has guessed"""
    misses = 0
    while True:
        if guess in secret:
            for i in range (len(secret)):
                if secret[i] == guess:
                    display = display.replace("_", guess)
                else:
                    misses +=1
    return display, guess

As for returning the function twice, I guess I was wanting to display "Words so far" and the letter guessed. And to update both, I wanted to return the function at separate times. Should I have created more variables inside the function and call that variable in the main code?

Sorry, as you can see I really suck at programming and I can't easily grasp the idea behind this. =/

Ya know, my first C coding class, I had to have a Comp Sci friend sit down and explain in excruciating detail how #include worked. There was just some block that all of the sudden went "Click!" and I was hooked.

I always got the impression that I should return the function or variables within the function in order for me to get an output from it in the main code.

The variables that you care about ... yes, absolutely; return those. That's how the function communicates with the code that calls it.

Return the function itself? Never. Or at least, almost never. I've never written code that needed to.

Should I have my while loop in the main code then?

Yes.

Since it will only recognize the first "_", will this be better?

First step: take out the while loop

#This is where we can update the letters guessed
def new_display(secret, display, guess):
    """Displays the replacement of underscores with letters that the user has guessed"""
    misses = 0
    if guess in secret:
        for i in range (len(secret)):
            if secret[i] == guess:
                display = display.replace("_", guess)
            else:
                misses +=1
    return display, guess

Next step: notice that you never do anything with the variable 'misses'. You don't return it; and once the function returns, it is forgotten. So you can eliminate it entirely from the code:

#This is where we can update the letters guessed
def new_display(secret, display, guess):
    """Displays the replacement of underscores with letters that the user has guessed"""
    if guess in secret:
        for i in range (len(secret)):
            if secret[i] == guess:
                display = display.replace("_", guess)
    return display, guess

The next thing is that you aren't returning what your prof said you had to return, which was display and replacement_count. The replacement count was supposed to keep track of the number of times you had replaced a certain letter.

#This is where we can update the letters guessed
def new_display(secret, display, guess):
    """Displays the replacement of underscores with letters that the user has guessed"""
    rep_count = 0
    if guess in secret:
        for i in range (len(secret)):
            if secret[i] == guess:
                display = display.replace("_", guess)
                rep_count += 1
    return display, rep_count

If you run this, you will find now that the rep_count returns the right value, but the display is still wrong. The problem is that you need to find some way of identifying the particular index i where the replacement is supposed to happen.

I liked wooee's suggestion of using a list -- are you familiar with those?

Or, do you know how to do string slices?

Jeff

not familiar with lists, but i'm familiar with string splicing. i thought that for i in range(len(secret)) already finds which "_" to replace.

my misses don't seem to be updating, and isn't the while loop almost basically the same as the variables inside the new_display function? it feels like i'm suppose to be using the same code to keep the while loop running until the word is guessed(or under 6 tries)

does this while loop in the main code look anything remotely right?

#This is where we can update the letters guessed
def new_display(secret, display, guess):
    """Displays the replacement of underscores with letters that the user has guessed"""
    rep_count = 0
    if guess in secret:
        display = display.replace("_", guess)
    else:
        rep_count = rep_count + 1
    return display, rep_count



secret = get_secret()
print secret


guess = raw_input("What letter would you like to guess?")
misses = 0
display = "Words so far:" + "_"*len(secret)
letter = do_turn(display,misses)
while (misses<6) and (guess<len(secret)):
    display = "Words so far:" + "_"*len(secret)
    for i in range(len(secret)):
        if secret[i] == guess:
            display = display.replace("_", guess)
        else:
            misses = misses+1
            print misses
            print letter
            print display

display,rep_count = new_display(secret,display,guess)
print display,rep_count

i will also be seeing my prof tomorrow for some assistance, so i guess i'm trying to learn as much as i can today before seeing him tomorrow, to prevent me from looking like an idiot.

This is an app that should be coded as a class with self.misses as a variable, but it would be too much to hope for that you have already covered classes. Anyway, modified code to account for not being able to pass misses to the function

def new_display(secret, display, guess):    
      """Displays the replacement of underscores with letters that the user has
      guessed"""
      replacement_count = 0
      index=secret.find(guess)
      display_list=[ eachltr for eachltr in display ]
      if (index > -1) and (display_list[index]=="_"):  ## not already replaced
         display_list[index]=guess
         display="".join(display_list)
         replacement_count += 1

      return display, replacement_count
##
display, replacement_count = new_display(secret, display, guess)
if replacement_count:     ## letter was found and replaced
   total_replacement += replacement_count
else:    ## no letter replaced=miss
   misses += 1

WOW, I just became a "Junior Poster in Training". Guess I'll have to visit here more often. My available time is hit and miss though.

if guess in secret:
        ##-----  this will replace every "_" with guess.  You have to replace a specific position
        ## or use count to find the number to add to rep_count
        ## or you can use find() and add one to any position found to use as a start
        ##     parameter to find()
        ## add print statements to see what is happening
        print "before changing 'display'", display
        display = display.replace("_", guess)
        print "after changing 'display '", display

Another way to convert when guess is found (if this is any easier to understand)

new_display=""
   if guess in secret:
      index = secret.find(guess)
      for j in range(0, len(display)):
         this_char=display[j]
         if j != index:          ##   copy what is in display
            new_display += this_char
         else:                   ## replace this letter
            new_display += guess
            rep_count += 1
   else:
        new_display = display              ## nothing found=keep the same
return new_display, rep_count

i will try them out tomorrow evening. i have a midterm tomorrow for my biochem class and i really should start studying tom. i'll update my code for you guys tomorrow, the day that it's also due. even if i don't finish this before submission, i'd still like to work on this even after since i have to get this sooner or later. thanks for everything. will reply tomorrow.

On further reflection, there's an easier solution than what I suggested. My version would be

#This is where we can update the letters guessed
def new_display(secret, display, guess):
    """Displays the replacement of underscores with letters that the user has guessed"""
    rep_count = 0
    new_d = ""
    for i in range(len(secret)):
        if secret[i] == guess:
            new_d += guess
            rep_count += 1
        else:
            new_d += display[i]
    return new_d, rep_count

It functions by saying, OK, let's have a blank new display. Then go character by character through secret. If secret matches the guess, then add the guess to the new display. Otherwise, add display to the new display. So each character in the new display will come either from secret (if the guess matches that character) or from the old display (if not).

So if display == "--TT--" and secret == "LETTER" and guess == "E", then new_d builds up like this:

index  new_d
0        -           # from display
1        -E         # guess matched!
2        -ET       # from display
3        -ETT     # from display
4        -ETTE   # guess matched!
5        -ETTE-  # from display

That's a lot easier than either the lists or slices I was mentioning.

---

The while loop that you threw into your code was one step forward, one step back. You want to allow the user to take turns within the while loop, so line 20 should go in that block. Line 22 has the effect of resetting display every turn, which you don't want. And the for loop is unnecessary.

The best way to build the while loop in the main code is to plan it based on the fact that you now have two spiffy new functions: one that gets the user guess and one that creates the new display based on the guess *and* returns the number of times that the guess was in the secret.

So your basic while loop in the main code will be

while the user still isn't dead yet:
   do_turn(...)            # fill in the ... with your variables
   display, count = new_display(...)
   if the user got a hit:
      print an encouraging message
   else:
      make sure the user gets one step closer to hanging

And if you think about it, that's how you would play hangman yourself.

Jeff

Jeff's pseudo-code with total_replacement and misses fields added to keep track of successes vs failures

total_replacement=0
misses=0
total_guesses=0
while the_user_still_isn't_dead_yet:
   do_turn(...)            # fill in the ... with your variables
   total_guesses += 1
   display, count = new_display(...)
   if count:     ## letter was found and replaced
      total_replacement += count
      print an encouraging message
   else:    ## no letter replaced=miss
      misses += 1
      make sure the user gets one step closer to hanging
print "You guessed %d times, with %d letters replaced and %d misses" % 
       (total_guesses, total_replacements, misses)

Edit: In this version of hangman if the 'secret word' is "abac" and the guess is an "a", are both a's replaced or just one? It affects the way the function replaces.

it's suppose to replace both."

"abac"
a_a

gotta run for my bus now. gonna be late for class. thanks for your help!

hi, so i talked to my prof today and i told him if it was okay to ask for suggestions/help online and he said it would be academic dishonesty. so, i'll be rewriting the whole code so i know i understand this. can the moderator delete this post altogether?

thanks for everyone's time in helping, but i'm gonna have to stick with asking for help from my prof and his teaching assistants.

Your integrity is duly admired. If you remember one thing, remember this:

The only way to communicate to a function is by passing it parameters; the only way to get info back is from the return value.

Jeff

Here is the code I used for my Sonic the Hedgehog hangman game

import random
HANGMANPICS = ['''

  +---+
  |   |
      |
      |
      |
      |
=========''', '''

  +---+
  |   |
  O   |
      |
      |
      |
=========''', '''

  +---+
  |   |
  O   |
  |   |
      |
      |
=========''', '''

  +---+
  |   |
  O   |
 /|   |
      |
      |
=========''', '''

  +---+
  |   |
  O   |
 /|\  |
      |
      |
=========''', '''

  +---+
  |   |
  O   |
 /|\  |
 /    |
      |
=========''', '''

  +---+
  |   |
  O   |
 /|\  |
 / \  |
      |
=========''']
words = 'sonic knuckles amy shadow tails rouge big eggman robotnik vector silver cream cheese chao froggy chaosemerald masteremerald sallyacorn mobius unitedfederation naugus snively angelisland deathegg badnik greenhill chemicalplant worldring chaoscontrol tornado robotropolis newmegaopolis vanilla metalrobotnik metalsonic robotgenerator decoe bocoe freedomfighters'.split()

def getRandomWord(wordList):
    # This function returns a random string from the passed list of strings.
    wordIndex = random.randint(0, len(wordList) - 1)
    return wordList[wordIndex]

def displayBoard(HANGMANPICS, missedLetters, correctLetters, secretWord):
    print(HANGMANPICS[len(missedLetters)])
    print()

    print('Missed letters:', end=' ')
    for letter in missedLetters:
        print(letter, end=' ')
    print()

    blanks = '_' * len(secretWord)

    for i in range(len(secretWord)): # replace blanks with correctly guessed letters
        if secretWord[i] in correctLetters:
            blanks = blanks[:i] + secretWord[i] + blanks[i+1:]

    for letter in blanks: # show the secret word with spaces in between each letter
        print(letter, end=' ')
    print()

def getGuess(alreadyGuessed):
    # Returns the letter the player entered. This function makes sure the player entered a single letter, and not something else.
    while True:
        print('Guess a letter.')
        guess = input()
        guess = guess.lower()
        if len(guess) != 1:
            print('Please enter a single letter.')
        elif guess in alreadyGuessed:
            print('You have already guessed that letter. Choose again.')
        elif guess not in 'abcdefghijklmnopqrstuvwxyz':
            print('Please enter a LETTER.')
        else:
            return guess

def playAgain():
    # This function returns True if the player wants to play again, otherwise it returns False.
    print('Do you want to play again? (yes or no)')
    return input().lower().startswith('y')


print('H A N G M A N')
missedLetters = ''
correctLetters = ''
secretWord = getRandomWord(words)
gameIsDone = False

while True:
    displayBoard(HANGMANPICS, missedLetters, correctLetters, secretWord)

    # Let the player type in a letter.
    guess = getGuess(missedLetters + correctLetters)

    if guess in secretWord:
        correctLetters = correctLetters + guess

        # Check if the player has won
        foundAllLetters = True
        for i in range(len(secretWord)):
            if secretWord[i] not in correctLetters:
                foundAllLetters = False
                break
        if foundAllLetters:
            print('Yes! The secret word is "' + secretWord + '"! You have won!')
            gameIsDone = True
    else:
        missedLetters = missedLetters + guess

        # Check if player has guessed too many times and lost
        if len(missedLetters) == len(HANGMANPICS) - 1:
            displayBoard(HANGMANPICS, missedLetters, correctLetters, secretWord)
            print('You have run out of guesses!\nAfter ' + str(len(missedLetters)) + ' missed guesses and ' + str(len(correctLetters)) + ' correct guesses, the word was "' + secretWord + '"')
            gameIsDone = True

    # Ask the player if they want to play again (but only if the game is done).
    if gameIsDone:
        if playAgain():
            missedLetters = ''
            correctLetters = ''
            gameIsDone = False
            secretWord = getRandomWord(words)
        else:
            break

I wondered how difficult it would be to use a string/list of single bytes for the hangman picture and substitute the single byte every time there is an incorrect guess. Not too difficult, but it may not be worth the time either.

def print_hangman(list_in, wrong_guess):
    print "*"*30
    print "".join(list_in)
    lit = "%d wrong guess" % (wrong_guess)
    if 1 != wrong_guess:
        lit += "es"
    print lit

hangman_pic='''
 
  +---+
  |   |
      |
      |
      |
      |
      |
========='''

wrong_guess_pic = [("O", 21),
                   ("|", 29),
                   ("/", 28),
                   ("\\", 30),
                   ("|", 37),
                   ("/", 44),
                   ("\\", 46)]

new_pic = list(hangman_pic)
wrong_guess=0

## simulate wrong guesses
for ctr in range(len(wrong_guess_pic)):
    tup = wrong_guess_pic[wrong_guess]
    new_pic[tup[1]] = tup[0]
    wrong_guess += 1

    print_hangman(new_pic, wrong_guess)

Edited 4 Years Ago by woooee: n/a

This article has been dead for over six months. Start a new discussion instead.