Question about some Python code I'm trying to teach myself with... WHAT AM I MISSING?!? :)
February 4, 2009 6:55 PM   Subscribe

Hive-mind Python users, I call upon thee. I'm just learning the language, and I think I'm missing something pretty obvious regarding making a nested while and if loop work. There's 64 lines of code and...

OK, first, the code. You may find it here (for some reason the code function on Ask MeFi didn't preserve whitespace in the preview...).

As you may be able to tell, first, it's ugly (still working on that) but secondly, it's a number guessing program. It guesses a number, you tell it if it's right or wrong (higher or lower, etc). The part that's confusing me is in the "guess" function that's defined right at the start.

I included basic error checking (the "Else: a = raw_input("Ahem. Please. 'l' 'm' or 'y' aka 'less' 'more' or 'yes': ")" part), but it doesn't seem to work... it does it once, but then for some reason it just assumes that you picked the "More" option (m, M, More, etc).

I'm pretty sure I'm missing something stupid, but I haven't the foggiest what. Ah, the joys of self-learning. Thankfully, I have you folks... ;)

At any rate, thanks in advance, and please let me know if I need to clarify anything. Thanks a lot!

P.S.: Any pointers on good places to go to learn more about Python are welcome, though obviously not the point of the question. Thanks!
posted by TrueVox to Computers & Internet (21 answers total) 3 users marked this as a favorite
 
I downloaded your code, ran it as a python script, and don't get the error you describe. Can you list the steps to take that allow you to reproduce the buggy behavior?
posted by chrisamiller at 7:07 PM on February 4, 2009


Best answer: I copied that Python script onto my machine to run it, and although I wouldn't call it elegant, it works for me... sample runs (I chose 3 as my secret number both times), one with valid input and one with invalid input from me:

$ python guess.py
Is your choice 7? l
Is it 4? l
How about 2? h
Oh! I know it! Your number was 3 !
YAY! I got it!!! And it only took 3 guesses!
Please hit Return
$ python guess.py
Is your choice 7? z
Ahem. Please. 'l' 'm' or 'y' aka 'less' 'more' or 'yes': w
Ahem. Please. 'l' 'm' or 'y' aka 'less' 'more' or 'yes': x
Ahem. Please. 'l' 'm' or 'y' aka 'less' 'more' or 'yes': l
Is it 4? l
How about 2? h
Oh! I know it! Your number was 3 !
YAY! I got it!!! And it only took 3 guesses!
Please hit Return

Are you sure you have everything indented correctly, and you're not mixing tab indents with space indents?
posted by letourneau at 7:08 PM on February 4, 2009


Response by poster: Er, yeah, that would have helped. Sorry! :)

Here's a transcript of when it messes up. The 'zzz' is what you're NOT supposed to put in (what the error correction should be catching). It works the first time, but, after you enter it in the error catch prompt ("Ahem. Please. 'l' 'm' or 'y' aka 'less' 'more' or 'yes':") it just assumes that you entered the "higher" or "more" or "m" input.

Does that make sense? See below. It's supposed to keep looping the "Ahem. Please. 'l' 'm' or 'y' aka 'less' 'more' or 'yes':" until you enter an acceptable input. At least I think that's what my guess function should do. That's what I intended anyway. :)


Is your choice 7? zzz
Ahem. Please. 'l' 'm' or 'y' aka 'less' 'more' or 'yes': zzz
Hmmm.... is it 9? zzz
Ahem. Please. 'l' 'm' or 'y' aka 'less' 'more' or 'yes': zzz
Oh! I know it! Your number was 10 !
YAY! I got it!!! And it only took 2 guesses!
Please hit Return

posted by TrueVox at 7:12 PM on February 4, 2009


Response by poster: Um, I THINK I do. But it does appear to be working for you... hmmm....
posted by TrueVox at 7:13 PM on February 4, 2009


Response by poster: Wow. I didn't realize that would do it. Yes, I had tabs and spaces mixed. THANK YOU!!!!
posted by TrueVox at 7:15 PM on February 4, 2009


Also, I might suggest trying to eliminate some of that nasty nested-if structure. Running this whole thing in a loop will make it a lot simpler. Some pseudo code:

min = 0 
max = 10
found = false
count = 1

while found == false
  guess = (max + min)/2
  print Is your number $guess ?
  input = getInput()

  if input == "yes"
    print "yay I got it in $count guesses"
    found = true
  elsif input == "lower"
    max = input
    count++
  else 
    min = input
    count++
  end
end

print "game over"

posted by chrisamiller at 7:17 PM on February 4, 2009


Well, it does seem to work fine for me... if I enter gibberish it'll keep saying "Ahem:" until I give it correct input.

A couple of things that struck me as I was looking at this:

Please, please, give things useful names. gscnt is less useful than guessCount for you, or anyone else - yes, you know what it means because you're writing it right now, but in two months you won't. While outrageously long variable names are obviously not great (countOfHowManyTimesMomCallsToAskWhenImGoingToMarryJane), it's not like you have a character restriction on names, so don't be afraid to make them long enough to be descriptive. I still haven't figured out what fnum10 is supposed to represent. Similarly, your "guess" function doesn't actually guess - it gets user input and does error-checking on that input. I'd probably call it something like validateInput().

I'm not sure why there's a counter in the while loop - you're just repeating "dude, give me a value" until you get an acceptable value, right? The usual way to handle something like that is either to loop forever and use a break statement once you get an acceptable response, or to immediately return the value you're looking for.
posted by Tomorrowful at 7:19 PM on February 4, 2009


Hmm, finger slipped before I made my next point, but chrisamiller made it and threw in pseudocode to boot. So consider this a recommendation to take his advice.
posted by Tomorrowful at 7:21 PM on February 4, 2009


Chrisamiller has a good suggestion. Funny how similar Python really is to "pseudocode". On first glance I read his example as actual python without any hesitation -- only after Tomorrowful pointed it out did I look back and notice the "ends" and non-pythonic count++ incrementation. Heck of a language, Python!
posted by Hello, Revelers! I am Captain Lavender! at 8:10 PM on February 4, 2009


If you do need to make long compound 'if' statements, use 'in' instead -- like:

if a in ("l", "L", "less", "LESS", "f", "F", "<"): a = 'l'

Or even better:

if a.lower() in ("l", "less", "f", "<"): a = 'l'

But n+=1ing chrisamiller's approach. Think there's a typo though: the 'max = input' and 'min = input' lines should probably be '= guess' instead.

As for recommendations, read http://diveintopython.org/ if you haven't already. It's a few versions behind the times, but still extremely useful. You'll get a good sense of what elegant Python looks like, even if a few minor details are different now.
posted by toxotes at 8:15 PM on February 4, 2009


Here's a tip I wish someone had told me when I was learning Python: if a.lower() in "l less f <>. (Some Perl idioms are good.)
posted by shadytrees at 8:30 PM on February 4, 2009


Escaping! This is what I meant to type: if a.lower() in "l less f < blah blah".split()
posted by shadytrees at 8:32 PM on February 4, 2009


Best answer: If you're finding that mixing spaces and tabs is causing you trouble, calling python with the -t flag will cause it to warn you about them, and -tt will cause it to refuse to run programs where you use them to to confusing things.
posted by JiBB at 9:00 PM on February 4, 2009


possibleNumbers = [x for x in range(1,11)]
gotIt = False
guessCount = 0

while not gotIt:
    
    guess = possibleNumbers[(len(possibleNumbers)/2)]
    guessCount += 1
    answer = raw_input("is it %d? " % guess)
    while answer not in ['l','g','y']:
        answer = raw_input('Huh?  gimme a l/g/y')
        
    if answer == 'l':
        possibleNumbers = possibleNumbers[:possibleNumbers.index(guess)]
    elif answer == 'g':
        possibleNumbers = possibleNumbers[possibleNumbers.index(guess+1):]
    elif answer == 'y':
        print "Who's your momma!  It only took me %d tries.  Suck on that!" % guessCount
        gotIt = True

posted by H. Roark at 9:19 PM on February 4, 2009


For tutorials, you could do worse than starting on this site: http://wiki.python.org/moin/BeginnersGuide



On first glance I read his example as actual python without any hesitation -- only after Tomorrowful pointed it out did I look back and notice the "ends" and non-pythonic count++ incrementation.

I actually mostly sling ruby these days, and find it suits my natural flow even better than python. Among other things, I just never could get past the "whitespace matters" bit.

And yeah, the ++ convention isn't in ruby either - I mistakenly thought it was used in python.

posted by chrisamiller at 12:02 AM on February 5, 2009


Response by poster: Wow, sweet jesus, this grew over night! I don't have time to read everything now, but I can't wait to check this out after work! Thank you all for so much feedback (presumably) and general python help! :D
posted by TrueVox at 3:37 AM on February 5, 2009


Response by poster: Bagh, screw work. I decided to read it now and be a smidge late. :)

OK, first off, I know the useless names are bad. Why I'm using them is inexcusable. I will attempt to break that habit starting today. Thank you for the lesson that I SHOULD have been doing. ;)

As for the ugly nested ifyness, perhaps your version does it too (I haven't had a chance to code it and test it), but this was the only way I could find to have it succeed in 4 or less guesses (if yours does that too, then yes, I fully agree with you). I'm not a math wiz (which is bad for programming, I know ;D), so I've kind of hacked together my fix for making this self imposed PITA work.

And I think a lot of the advice I will pick up shortly. I'm kind of still in the early learning phases (not sure what a "break" is yet, or an escape), but yeah, you're probley right about it being better. :) I'm only on lesson 5 of this tutorial (not going with Civ4, but it seems to be a good tutorial regardless): http://www.sthurlow.com/. But I'll also check out the beginners guide mentioned. I'm also looking into Dive Into Python and Learn How Think Like A Computer Scientest w/ Python.

Too much to hope Python supports something like the ++ thingie? I vaguelly remember liking it from one of the other languages I tried to learn (I'm pretty sure it WASN'T c++ either).

And thank you all for the great code examples, and other assorted help. I can't wait to chew on this further.
posted by TrueVox at 4:11 AM on February 5, 2009


Assuming your range is between 1 and 10, the code I posted will succeed in at most 4 tries. To be more general, it is essentially a binary search algorithm, so for any range of n numbers, it will solve it in at most log2n tries.
posted by chrisamiller at 3:47 PM on February 5, 2009


Response by poster: ... see, this is what I mean about being bad at math. ;) Thanks a lot for the follow up, Chris. You created algorythmicly what I managed to come to slowly, and piece by piece. :D
posted by TrueVox at 4:01 PM on February 6, 2009


This is a bit of an old thread, but...

Python doesn't support the x++ syntax, but you can use x+=1 as an easier to read and shorter alternative to x=x+1.
posted by JiBB at 6:14 PM on April 6, 2009


Response by poster: Thank you for that, Jibb. Any advice is treasure. :)
posted by TrueVox at 4:58 PM on July 16, 2009


« Older Connecting with WiFi, what does "Identifying" mean...   |   Has "Unfailing Love" been recorded by any artist... Newer »
This thread is closed to new comments.