import random
print(" --- WELCOME TO THE SUPER NUMBER GUESSING GAME --- " + ("\n" *
5))
pnum = int(input("1 OR 2 PLAYER?\nP#: "))
target = random.randint(1, 99) #Pick a random number under two digits
guess1 = 0 #Zero will never be picked as target...
guess2 = 0 #so it makes a good default value
p1score = 0 #For two player mode...
p2score = 0 #let's keep score!
print("LET'S START THE GAME. \nGUESS ANY WHOLE NUMBER FROM 1 TO 99.")
while True:
if pnum == 1: #1p mode
while True:
guess1 = int(input("\n>> "))
if guess1 > 100:
print("ONLY NUMBERS FROM 1 TO 99")
elif guess1 > target:
print("TOO HIGH")
elif guess1 == target:
print("CONGLATGURATIONS! PLAY AGAIN?")
target = random.randint(1, 99) #Set up the game
again
play = int(input("0 TO END: "))
if play == 0:
print("GOOD BYE. PLAY AGAIN SOON!")
quit()
else:
print("TOO LOW")
if pnum == 2: #2p mode
while True:
guess1 = int(input("\nP1> ")) #Player 1's turn
if guess1 > 100:
print("ONLY NUMBERS FROM 1 to 99")
elif guess1 > target:
print("TOO HIGH")
elif guess1 == target:
p1score += 1
print("GOOD JOB, PLAYER 1! THE SCORE IS:\nP1: %s
--- P2: %s\nPLAY AGAIN?" % (p1score, p2score))
target = random.randint(1, 99) #Set up game
again
play = int(input("0 TO END: "))
if play == 0:
print("GOOD BYE. PLAY AGAIN SOON!")
else:
print("TOO LOW")
guess2 = int(input("\nP2> ")) #Player 2's turn
if guess2 > 100:
print("ONLY NUMBERS FROM 1 to 99")
elif guess2 > target:
print("TOO HIGH")
elif guess2 == target:
p2score += 1
print("GOOD JOB, PLAYER 2! THE SCORE IS:\nP1: %s
--- P2: %s\nPLAY AGAIN?" % (p1score, p2score))
target = random.randint(1, 99) #Set up game again
play = int(input("0 TO END: "))
if play == 0:
print("GOOD BYE. PLAY AGAIN SOON!")
else:
print("TOO LOW")
else:
print("INVALID PLAYER SELECTION")
pnum = int(input("1 OR 2 PLAYER?\nPN#: "))
I have one major problem with this; the 'replay' selection. It quits
if you put in 0, as it should, and continues if you put in any other
number. However, if you just press enter, it exits with an error. it
also looks really ugly, and I'm sure there has to be plenty of better
ways to do it.
I'd also appreciate tips on how it could be better in general. I
should think that P1 and P2's turns shouldn't have to be completely
repeated; but I'm not quite sure how to def something like that.
1. Refactor. You should look at your code and see where you repeat the
same or similar patterns, see where they differ, make functions, and
make the differences parameters to the function call:
def guess(player, p1score, p2score):
guess1 = int(input("\n>> "))
if guess1 > 100:
print("ONLY NUMBERS FROM 1 TO 99")
elif guess1 > target:
print("TOO HIGH")
elif guess1 == target:
print("GOOD JOB, PLAYER %s! THE SCORE IS:" % player)
print("P1: %s --- P2: %s" % (p1score, p2score)))
print("PLAY AGAIN?")
#Set up the game again
play = int(input("0 TO END: "))
if play == 0:
print("GOOD BYE. PLAY AGAIN SOON!")
quit()
else:
target = random.randint(1, 99)
else:
print("TOO LOW")
You would call guess() like this, perhaps:
guess(2, 15, 22)
2. You need to use a try: except: within a loop when you cast the input
to int:
while True:
try:
guess1 = int(input("\n>> "))
except ValueError:
print 'Bad value.'
else:
break
Same with the seeing if the player will play again. See below.
3. Don't try to fit too much on one line. See how I broke the print
statement at logical places (new lines).
4. Further subdivide functions based on conceptual tasks. For example, I
would define a function like this:
def play_again():
while True:
try:
print("PLAY AGAIN?")
again = bool(input("0 TO END: "))
except ValueError:
print 'Bad value.'
else:
break
return again
You would use play_again() like this:
if play_again():
print("GOOD BYE. PLAY AGAIN SOON!")
quit()
else:
target = random.randint(1, 99)
5. Don't do anything until you need to do it. See how I handled setting
the new target for what I mean. You set a new target before you know if
the player wants to play again. Its not a big deal in this case, but
these inefficiencies build up in larger applications. This isn't
"premature optimization", but simply good coding style [ed: put in to
fend off the "premature optimization is bad" puppets who infest this list].
Notice that the sequence of commands follows a logical sequence
corresponding to decisions in the game. It makes the code more sensible,
readable, and a little faster some times to boot. Good logic has the
happy consequence of good speed most of the time.
My code is typed real-time so is untested. No promise that there aren't
typos but you will probably get the idea. But see if you can plug the
these functions into the proper places and apply some of these techniques.
James
--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095
> I have one major problem with this; the 'replay' selection. It quits if
> you put in 0, as it should, and continues if you put in any other
> number. However, if you just press enter, it exits with an error. it
> also looks really ugly, and I'm sure there has to be plenty of better
> ways to do it.
Start by refactoring your code into small, easy to understand functions.
For example,
You mix in the same piece of code the logic for:
- error handling;
- starting a new game;
- quiting (although you use a function for this, well done);
- and game logic
and then you have to repeat it all again, almost word-for-word, for one
player mode and two player mode.
Start with a high-level approach. The guessing game has the following
structure:
while you want to play a game:
play a game
ask play again?
which in Python might look like this:
playing = True
while playing:
play_one_game()
playing = play_again()
def play_again():
# For Python 3, change "raw_input" to "input".
response = raw_input("Would you like to play again? y/n ")
return response.strip().lower() == "y"
This function accepts *only* Y or y to play another game. Later, after
you've got the game working, you can come back to this and modify it so
that it accepts Yes or just enter on it's own. Make it work as simply as
possible first, then come back and make it more complicated later.
Now do the same thing for playing one game. A single game in two player
mode looks something like this:
pick a target number
start with one person as the guesser
until the target is guessed:
guess a number
let the other person be the guesser
which in Python might look like this:
def play_one_game():
target = pick_target() # you need to write this function
guessed = False
player = "Player One"
while not guessed:
guess = guess_number(player) # you need to write this too
if guess == target:
guessed = True
else:
player = swap_player(player) # player one <=> player two
# When we exit the loop, player is the person who guessed correctly.
if player == "Player One":
p1score += 1
else:
p2score += 1
Best of all, you can change from two player mode to one player mode just
by skipping the line "player = swap_player(player)". The rest of the code
remains exactly the same, and you don't need to repeat everything.
Have a play around with this approach, and then come back to us if you
need more hints.
--
Steven
I realized this has a bug. The target is locked in the scope of the
function. I wouldn't use global, though:
def guess(player, p1score, p2score):
target = None
guess1 = int(input("\n>> "))
if guess1 > 100:
print("ONLY NUMBERS FROM 1 TO 99")
elif guess1 > target:
print("TOO HIGH")
elif guess1 == target:
print("GOOD JOB, PLAYER %s! THE SCORE IS:" % player)
print("P1: %s --- P2: %s" % (p1score, p2score)))
print("PLAY AGAIN?")
#Set up the game again
play = int(input("0 TO END: "))
if play == 0:
print("GOOD BYE. PLAY AGAIN SOON!")
quit()
else:
target = random.randint(1, 99)
else:
print("TOO LOW")
Use it like this:
new_target = gues(player, p1score, p2score)
if new_target is not None:
target = new_target
I officially declare that I can't guarantee no more bugs in my previous
post. I just fixed this one because my conscience was bothering me.
def guess(player, p1score, p2score):
target = None
guess1 = int(input("\n>> "))
if guess1 > 100:
print("ONLY NUMBERS FROM 1 TO 99")
elif guess1 > target:
print("TOO HIGH")
elif guess1 == target:
print("GOOD JOB, PLAYER %s! THE SCORE IS:" % player)
print("P1: %s --- P2: %s" % (p1score, p2score)))
print("PLAY AGAIN?")
#Set up the game again
play = int(input("0 TO END: "))
if play == 0:
print("GOOD BYE. PLAY AGAIN SOON!")
quit()
else:
target = random.randint(1, 99)
else:
print("TOO LOW")
return target
import random
def startup():
print("WELCOME TO THE SUPER NUMBER GUESSING GAME!")
global pnum, play, player, p1sc, p2sc
pnum = int(input("1 OR 2 PLAYERS?\n> "))
play = True
player = "P1" #P1 goes first
p1sc = 0 #Number of times...
p2sc = 0 #player guessed before opponent
def setup():
global target, guess, a, b
a = 1
b = 99
target = random.randint(a, b)
guess = 0 #Won't fall between 1 and 99
def playerswap():
global player
if player == "P1":
player = "P2"
else:
player = "P1"
def guessing():
global guess, player, target, play, pnum, p1sc, p2sc, a, b
guess = int(input("[%s-%s]%s>> " % (a, b, player))) #keeps the
user aware of min/max
if guess == target:
if pnum == 1:
print("CONGRATULATIONS!" )
else:
if player == "P1":
p1sc += 1
else:
p2sc += 1
print("CONGRATULATIONS %s! SCORE -- P1:%s P2:%s" %(player,
p1sc, p2sc))
playover = input("PLAY AGAIN? Y/N: ")
if playover.strip().lower() == "y":
play = True
setup()
else:
play = False
elif guess > b:
print("NUMBER MUST BE IN RANGE")
elif guess <= a:
print("NUMBER MUST BE IN RANGE")
elif guess > target:
print("TOO HIGH")
b = guess
else:
print("TOO LOW")
a = guess
if pnum ==2:
playerswap()
startup()
setup()
while play is True:
guessing()
This is what I have so far. better? worse? I'm guessing a mix of the
two. It took me a lot longer to get working, but I think it works
better. I also added a bit that tells you if you go higher or lower
than an already specified too high/low markers; although it doesn't
make you repeat that turn. I'm not sure if all those 'globals' are
bad, but they don't seem like they're something that should be good.
Functionally, it seems to work just fine.
Much better. I didn't check if it works. But you need to figure out a
way to give up on your reliance on global variables. They will end up
stifling you in the long run when you move to substantial projects.
Also, you should start moving the nested if: then: blocks to functions.
Finally, you should limit your lines to no more than 80 chars. I do 71.
Don't be afraid to use transient variables to help.
Be assured that it takes on special intelligence to write unintelligible
code at will. Also be assured that fitting everything on one line is not
a good way to save time.
Aim for clarity.
If you want to start off on the right foot, you'll grind on your
guessing game until all variables are insulated within local scope and
the logic of the program becomes apparent from its architecture as a
collection of functions.
This is an example of how to combine these concepts:
def update_scores(player, p1sc, p2sc):
if player == "P1":
plsc +=1
else:
p2sc +=1
tmplt = "CONGRATULATIONS %s! SCORE -- P1:%s P2:%s"
print(tmplt % (player, p1sc, p2sc))
return p1sc, p2sc
p1sc, p2sc = update_scores(player, p1sc, p2sc)
Finally, put comments on their own lines. Google "python style guide".
James
I meant "*no* special intelligence".
import random
def setup():
#global target, guess, a, b
#a, b make minimum, maximum. Can be adjusted.
a, b = 1, 99
target = random.randint(a, b)
return a, b, target
def playerswitch(player):
#Player Switch
#if player's a witch, burn her!
if player == "P1":
player = "P2"
else:
player = "P1"
return player
def youwin(pnum, player, p1sc, p2sc):
if pnum == 1:
print("CONGRATULATIONS!")
else:
if player == "P1":
p1sc += 1
else:
p2sc += 1
end = "CONGRATULATIONS %s! SCORE -- P1:%s P2:%s"
print(end %(player, p1sc, p2sc))
return p1sc, p2sc
def playagain(play):
playover = input("PLAY AGAIN? Y/N: ")
if playover.strip().lower() == "y":
play = 1
a, b, target = setup()
else:
print("GOOD BYE. PLAY AGAIN SOON!")
quit()
return play, a, b, target
def guesscheck(guess, target, play, a, b, p1sc, p2sc):
if guess == target:
p1sc, p2sc = youwin(pnum, player, p1sc, p2sc)
play, a, b, target = playagain(play)
elif guess >= b:
print("NUMBER MUST BE IN RANGE")
guess = int(input("[%s-%s]%s>> " % (a, b, player)))
play, a, b, target, p1sc, p2sc = guesscheck(guess, target,
play,
a, b, p1sc, p2sc)
elif guess <= a:
print("NUMBER MUST BE IN RANGE")
guess = int(input("[%s-%s]%s>> " % (a, b, player)))
play, a, b, target, p1sc, p2sc = guesscheck(guess, target,
play,
a, b, p1sc, p2sc)
elif guess > target:
print("TOO HIGH")
b = guess
else:
print("TOO LOW")
a = guess
return play, a, b, target, p1sc, p2sc
def guessing(a, b, player, pnum, target, p1sc, p2sc, play):
#a and b are to keep the user aware of min/max
guess = int(input("[%s-%s]%s>> " % (a, b, player)))
play, a, b, target, p1sc, p2sc = guesscheck(guess, target, play,
a, b, p1sc, p2sc)
if pnum == 2:
player = playerswitch(player)
return play, a, b, player, target, p1sc, p2sc
#Let the show begin!
print("WELCOME TO THE SUPER NUMBER GUESSING GAME!")
pnum = int(input("1 OR 2 PLAYERS?\n> "))
play = 1
player = "P1" # P1 goes first
#Scores, keep track of times player guessed first.
p1sc, p2sc = 0, 0
#Grabs minimum, maximum, and target numbers
a, b, target = setup()
while play == 1:
play, a, b, player, target, p1sc, p2sc \
= guessing(a, b, player, pnum, target, p1sc, p2sc, play)
This is what I have now. It seems to work perfectly, and I tried to
work in your suggestions. Thanks, by the way, for recommending the
style guide. I've bookmarked it, and I'll try to remember to consult
it in the future.
One (extremely minor) annoyance is that if you have only one possible
guess left you still have to type it in manually. As an example,
[30-32]P#>> can only possibly be 31 (and I've changed it so that any
number >= 32 or <= 30 won't be accepted, so it's all the user can
input), which means whatever player is in control has a %100 chance of
winning. I know that "if b - a == 2" would be a simple enough test for
this, but I'm not quite sure when to put it, or what to do with it.
And yes, I'm aware that
guess = int(input("[%s-%s]%s>> " % (a, b, player)))
play, a, b, target, p1sc, p2sc = guesscheck(guess, target, play,
a, b, p1sc, p2sc)
is repeated three times. I will probably try to change this into a
function later on; right now, I just spent a few hours trying to get
this to work and making sure that it does (by playing it), so I'm
going to take a break.
You should now try to rewrite the whole thing to avoid using globals.
> pnum = int(input("1 OR 2 PLAYERS?\n> "))
What happens here if you type something that's not a valid argument for
int() ?
(snip)
Seems ok. You may want to use arguments with default values for a and b
(and possibly to use more meaningfull names):
def setup(mini=1, maxi=99)
# sanity check
if mini >= maxi:
raise ValueError("mini must be lower than maxi")
target = random.randint(mini, maxi)
return mini, maxi, target
> def playerswitch(player):
> #Player Switch
> #if player's a witch, burn her!
Extra bonus point for quoting Monty Pythons !-)
> if player == "P1":
> player = "P2"
> else:
> player = "P1"
> return player
I'd name this one "switch_player" (most of the time, function names
should be verbs) - but this is mostly a matter of personal taste !-)
Minor point for a short program, but still good practice : use
constants. IE :
# at the top level
PLAYER_1 = 1
PLAYER_2 = 2
# in your code
....
if player == PLAYER_1:
...
Also, you could use early returns here instead of rebinding then
returning player.
def switch_player(player):
if player == PLAYER_1:
return PLAYER_2
else:
return PLAYER_1
> def youwin(pnum, player, p1sc, p2sc):
I assume 'p1sc' means "player_1_score" ?
If so, you may want to use a dict for scores:
scores = {PLAYER_1:0, PLAYER_2:0}
then...
> if pnum == 1:
> print("CONGRATULATIONS!")
<ot>Is it really necessary to WRITE THIS IN ALL UPPERS ?-)</ot>
> else:
> if player == "P1":
> p1sc += 1
> else:
> p2sc += 1
Which would then become:
scores[player] +=1
> end = "CONGRATULATIONS %s! SCORE -- P1:%s P2:%s"
> print(end %(player, p1sc, p2sc))
> return p1sc, p2sc
> def playagain(play):
> playover = input("PLAY AGAIN? Y/N: ")
> if playover.strip().lower() == "y":
> play = 1
If it's meant to be 0/1 flag, Python has proper booleans too (True and
False).
> a, b, target = setup()
> else:
> print("GOOD BYE. PLAY AGAIN SOON!")
> quit()
It might be better to avoid exiting so brutally. Why not returning 0,
none, None, None ?
You should either put this in it's own function (could be named 'main'),
or at least "protect" it with an "if __name__ == '__main__':" test.
> print("WELCOME TO THE SUPER NUMBER GUESSING GAME!")
> pnum = int(input("1 OR 2 PLAYERS?\n> "))
> play = 1
> player = "P1" # P1 goes first
> #Scores, keep track of times player guessed first.
> p1sc, p2sc = 0, 0
>
> #Grabs minimum, maximum, and target numbers
> a, b, target = setup()
>
> while play == 1:
> play, a, b, player, target, p1sc, p2sc \
> = guessing(a, b, player, pnum, target, p1sc, p2sc, play)
>
>
> This is what I have now.
And it looks way better than your first version.
(snip)
while True:
try:
guess1 = int(input("\n>> "))
except ValueError:
print 'Bad value.'
else:
break
Other than that, you still have some points where you can break lines
down to improve clarity. Think of it like trying to avoid run-on sentences.
Over all, it looks like you have picked up some good technique that you
could only get by experimentation over the course of about 5 or 6 months.
James
I changed it to minr and maxr. Mini is fine, but I can't name a
variable maxi unless I have a good feminine hygiene joke to use with
it.
I don't see the aim of your changes to setup(). I can kinda understand
checking to make sure that you didn't make the minimum higher than the
maximum, but I think where you put minr/maxr would make it use the
same minr/maxr as the end of the previous game, wouldn't it?
>Minor point for a short program, but still good practice : use
>constants. IE :
I had done this initially, but it seemed wasteful and needlessly
confusing in this situation.
>I assume 'p1sc' means "player_1_score" ?
>If so, you may want to use a dict for scores:
I don't really understand dicts yet; actually, the tutorial I'm
following (http://www.briggs.net.nz/log/writing/snake-wrangling-for-
kids/ , designed for tweens, but other than the pointless anecdote and
joke here and there, I've found it a very good guide) doesn't even
seem to mention them, from a search of the pdf. Actually, apparently I
stopped and started working on this just before the chapter on
functions and modules.
I'll look into that later on, but for now I'm pretty happy with how it
works.
><ot>Is it really necessary to WRITE THIS IN ALL UPPERS ?-)</ot>
If you didn't notice, in the original it was "CONGLATURATIONS".
I could also make a "VIDEO GAME BAND. Heavy Metal's Not Dead." joke
here, but I'm afraid a disappointingly small amount of people will get
it.
>Python has proper booleans too
Yeah, I had those initially too, but "play = True" was causing trouble
for some reason when I copy/pasted it into IDLE to try to
troubleshoot, so I changed it to 1. I'll probably change it back
later.
>You should either put this in it's own function (could be named 'main'),
>or at least "protect" it with an "if __name__ == '__main__':" test.
Could you go into a bit more detail on this? I don't understand what
should be its own function, nor do I understand what that line would
do or how to use it.
James, could you work that into a section of what I have to make it a
bit easier to understand?
> I don't see the aim of your changes to setup(). I can kinda understand
> checking to make sure that you didn't make the minimum higher than the
> maximum, but I think where you put minr/maxr would make it use the
> same minr/maxr as the end of the previous game, wouldn't it?
No. Each function call creates its own name space. The function as Bruno
has written it will have default values (mini & maxi). A call to this
function can set different values optionally:
setup(2) #==> range from 2 to 99
setup(maxi=101) #==> range from 1 to 101
setup(5, 10) #==> range from 5 to 10
setup(10, 5) #==> throws an error
>> Minor point for a short program, but still good practice : use
>> constants. IE :
>
> I had done this initially, but it seemed wasteful and needlessly
> confusing in this situation.
No. Tracking down and changing hard-coded values within a module is
wasteful and needlessly confusing. Creating well named and well
documented module level constants is good style and will make your life
easier in the long run.
>> I assume 'p1sc' means "player_1_score" ?
>> If so, you may want to use a dict for scores:
>
> I don't really understand dicts yet; actually, the tutorial I'm
> following (http://www.briggs.net.nz/log/writing/snake-wrangling-for-
> kids/ , designed for tweens, but other than the pointless anecdote and
> joke here and there, I've found it a very good guide) doesn't even
> seem to mention them, from a search of the pdf. Actually, apparently I
> stopped and started working on this just before the chapter on
> functions and modules.
scores = {'player 1' : 0, 'player 2' : 0 }
scores['player 2'] = 10 #==> now player 2's score is 10
scores['player 1'] += 1 #==> now player 1's score is 1
print scores['player 0'] #==> prints "0"
print scores['player 2'] * 2 #==> prints "20"
If you get that, you'll have about all you need to know about dicts to
use them for keeping track of scores (and other values) in your game.
> I'll look into that later on, but for now I'm pretty happy with how it
> works.
Try it sooner rather than later. I didn't get this kind of advice when I
was first learning. It would have shaved months from my learning curve.
>> You should either put this in it's own function (could be named 'main'),
>> or at least "protect" it with an "if __name__ == '__main__':" test.
>
> Could you go into a bit more detail on this? I don't understand what
> should be its own function, nor do I understand what that line would
> do or how to use it.
The idea is that everything you write is reusable and can be imported as
a module. Upon importing a module, it's code is executed. So, as
written, if someone imports it as a library module, they will start
playing the game. Wrapping in the "if __name__ == '__main__':" test
prevents the main loop of the game from executing on import. Only when
the module is "__main__" will that test evaluate to true and its
commands execute.
For small programs like you have here, I'd do it like this (again
combining ideas):
def num_players(game, prompt='1 or 2 Players?\n> '):
while True:
num = input(prompt)
try:
num = int(num)
except ValueError:
print "Bad Value"
else:
break
game['pnum'] = num
def main(game=None):
if game is None:
game = {}
print("WELCOME TO THE SUPER NUMBER GUESSING GAME!")
num_players(game)
game['play'] = 1
# P1 goes first
game['player'] = "P1"
#Scores, keep track of times player guessed first.
game['p1sc'], game['p2sc'] = 0, 0
setup(game)
while game['play'] == 1:
guessing(game)
if __name__ == "__main__":
main()
I just threw a little advanced stuff at you. But you would be doing
yourself a huge favor if you struggled to understand it. The idea is
that since game is a dict, you can modify game inside of the functions,
and all you do is pass the game around to functions that need the values
of its contents.
For example:
def setup(game):
game['a'], game['b'] = 1, 99
game['target'] = random.randint(a, b)
def playagain(game):
playover = input("PLAY AGAIN? Y/N: ")
if playover.strip().lower() == "y":
game['play'] = 1
setup(game)
else:
print("GOOD BYE. PLAY AGAIN SOON!")
quit()
Notice that I just made return values obsolete.
You will also notice that management of all of your values now becomes
more tractable using the mutability of dict ("game"). Long, ugly lines
now become simple function calls. See if you can understand what I'm
doing here and try to propagate the idea through your game using the
game dict.
If you can do it, you'll be at least 80% of the way to understanding
object oriented programming, by the way.
James
> I don't really understand dicts yet; actually, the tutorial I'm
> following (http://www.briggs.net.nz/log/writing/snake-wrangling-for-
> kids/ , designed for tweens, but other than the pointless anecdote
> and joke here and there, I've found it a very good guide) doesn't
> even seem to mention them, from a search of the pdf. Actually,
> apparently I stopped and started working on this just before the
> chapter on functions and modules.
>
> I'll look into that later on, but for now I'm pretty happy with how
> it works.
Dicts, or dictionaries, also known as "hash tables" in some computer
languages, are a mapping from a key to a value. Think of looking up a
word in a real dictionary: the word is the key, and the definition is
the value.
Imagine a game with multiple players, each known by their name.
Because you don't know how many players there are, or what their
names are, you can't do this:
fred_score = 0 # How do I know there's a player called Fred?
barney_score = 0
...
But you can do this:
names = get_players_names()
scores = {} # start with an empty dict
for name in names:
# the player name is the key, and the score is the value
scores[name] = 0
print scores
=> {"fred": 0, "barney": 0, "wilma": 0, "betty": 0}
(or whatever names you have been given).
Later, you want to print Fred's score:
print "%s's score is %d" % ("fred", scores["fred"])
will print "fred's score is 0".
You might need to add 1 to Wilma's score:
score["wilma"] += 1
And so forth.
[...]
>>You should either put this in it's own function (could be
>>named 'main'), or at least "protect" it with an "if __name__
>>== '__main__':" test.
>
> Could you go into a bit more detail on this? I don't understand what
> should be its own function, nor do I understand what that line would
> do or how to use it.
Consider a really simple Python module:
# module.py
def hello():
print "Hello parrot!"
print "Running the module"
hello()
# end module.py
If you execute that file, from the commandline or the desktop, it
prints
Running the module
Hello parrot!
just as you expect. But when another Python module imports it, using
the command "import module", not only is the function hello() loaded,
but the two lines above are printed too -- but only the first time
you import the module. This is usually not what you want.
Generally, you want the *execution* to be separate from the
*importing*. There is a way to do this is Python:
# module.py
def hello():
print "Hello parrot!"
if __name__ == "__main__":
print "Running the module"
hello()
# end module.py
When you import the module, Python sets the special variable
"__name__" to the string "module". It's the name of the module. But
when you are executing the file from the command line, Python sets
the special variable to the magic string "__main__" instead. So the
code inside the if __name__ block is only executed when you are
actually executing the module, not when you import the module.
Hope this helps somewhat.
--
Steven
#!/usr/bin/python
#Py3k, UTF-8
import random
def setup(game, minr=1, maxr=99):
#minr, maxr make minimum and maximum. Can be adjusted.
game['minr'], game['maxr'] = minr, maxr
game['gcount'] = 0 #Reset guess count
game['target'] = random.randint(minr, maxr)
def playerswitch(game):
#Player Switch
#if player's a witch: burn(her)
if game['player'] == game['player1']:
game['player'] = game['player2']
else:
game['player'] = game['player1']
def youwin(game):
if game['pnum'] == 1:
print("CONGRATULATIONS! IT TOOK YOU %s GUESSES" % game
['gcount'])
else:
if game['player'] == game['player1']:
game['p1sc'] += 1
else:
game['p2sc'] += 1
end = "CONGRATULATIONS %s! SCORE -- P1:%s P2:%s"
#Can the following line be more compact?
print(end % (game['player'], game['p1sc'], game['p2sc']))
def playagain(game):
playover = input("PLAY AGAIN? Y/N: ")
if playover.strip().lower() == "y":
game['play'] = True
setup(game)
else:
print("GOOD BYE. PLAY AGAIN SOON!")
game['play'] = False
def autofinish(game):
if game['maxr'] - game['minr'] == 2:
print("...ONLY ONE OPTION LEFT!")
youwin(game)
playagain(game)
def numplayers(game, prompt="1 OR 2 PLAYERS?\n> "):
while True:
num = input(prompt)
try:
num = int(num)
except ValueError:
print("BAD VALUE")
else:
break
game['pnum'] = num
def guesses(game):
game['guess'] = int(input("[%s-%s]%s>> " \
#keeps user aware of who's turn it is, and the range
% (game['minr'], game['maxr'], game['player'])))
def guesscheck(game):
if game['guess'] == game['target']:
if game['pnum'] == 1:
game['gcount'] += 1
youwin(game)
playagain(game)
elif game['guess'] >= game['maxr']:
print("NUMBER MUST BE IN RANGE")
guesses(game)
guesscheck(game)
elif game['guess'] <= game['minr']:
print("NUMBER MUST BE IN RANGE")
guesses(game)
guesscheck(game)
elif game['guess'] > game['target']:
print("TOO HIGH")
if game['pnum'] == 1:
game['gcount'] += 1
game['maxr'] = game['guess']
else:
print("TOO LOW")
if game['pnum'] == 1:
game['gcount'] += 1
game['minr'] = game['guess']
def guessing(game):
guesses(game)
guesscheck(game)
if game['pnum'] == 2:
playerswitch(game)
autofinish(game)
def main(game=None):
if game is None:
game = {}
print("WELCOME TO THE SUPER NUMBER GUESSING GAME!")
numplayers(game)
game['play'] = True
game['player1'], game['player2'] = "P1", "P2"
game['player'] = game['player1'] # P1 goes first
#Scores start at 0
game['p1sc'], game['p2sc'], game['gcount'] = 0, 0, 0
setup(game)
while game['play'] is True:
guessing(game)
if __name__ == "__main__":
main()
first off, I want to thank all of you for your help with this. I
really don't think I could've learned all of this out nearly as
quickly by reading tutorials and documentation, let alone had anything
near the grasp I have on it now. '''This''' is why I like learning by
doing. The only things I still don't really understand are .strip
().lower(), and try/except/else, and I plan on looking them up before
I do anything else. In the past few hours I've gone from not having a
clue what the whole {'fred': 0, 'barney': 0} thing was about to being
able to fully understand what you're talking about, and put it into
practice
2; I feel like this process is going quicker and quicker every time I
refine it. It also feels like it's getting easier to solve various
bugs when <s>I create them</s> they pop up. It might be because I'm
getting into it and having more fun, because the refinements are less
major each time, because they're easier to pick up, or some
combination of all of those. Either way, I feel very excited about it.
3; I found some very helpful gedit plugins. While I was in
preferences, I noticed you can have it highlight the margin; so I set
that to 75 to try to keep from going over the character limit/line
recommendation. Draw Spaces, a plugin, showing spaces is also pretty
helpful. I also found a python auto complete plugin which I haven't
used so far, but which looks very promising, along with a terminal
program (Keeps me from juggling windows, anyway)
4; I readded the counter for one player games. Out of curiosity, what
do you think of:
if game['pnum'] == 1:
game['gcount'] += 1
? I'm not sure whether this is good or bad. On the one hand, it keeps
it from adding to gcount without needing to, on the other hand it
seems like it might be more wasteful to check pnum than to just add to
gcount. It also makes it harder to adjust it to show gcount in two
player mode, if you want to do that for some reason.
5; I added the ability for it to automatically complete when there's
only one option left. I was amazed' I was actually going to ask for
advice on how to do it here. I was going to say "I was thinking (blah
blah)", but then I just typed it in, and it worked flawlessly. This
goes back to one, but I'm very excited, and thankful.
6; can anyone think of anything else to add on to/do with this game?
With the minr/maxr display, multiplayer, score keeping, and
automation, I'm just about all of ideas. All I can think of left to
add is 3 and 4 player modes, or a fork where player 2 can't win
(kekekekeke. Though I'm not sure how to do it...), both of which I
feel are somewhat pointless for a game like this. If I can't learn
anything more from it, I will probably go back to reading python
guides for a bit, and then try to make something else.
def customrange(game, lowunsafe=True):
game['defrang'] = False #Keeps setup from changing range to
defaults
while lowunsafe: #makes sure that the low number is positive
picklow = int(input("PLEASE PICK THE LOW NUMBER: "))
if picklow < 0:
print("LOW NUMBER MUST BE POSTIVE")
else:
lowunsafe = False
pickhigh = int(input("PLEASE PICK THE HIGH NUMBER: "))
if pickhigh - picklow <= 2: #see setup().
print("HIGH MUST BE AT LEAST THREE GREATER THAN LOW")
else:
game['minr'], game['maxr'] = picklow, pickhigh
print("RANGE IS [%s-%s]!" % (game['minr'], game['maxr']))
def wantcustom(game, unsure=True):
#Allows user to decide their own range for guessing.
while unsure:
pickrange = input("WOULD YOU LIKE TO CREATE A CUSTOM RANGE? Y/
N: ")
if pickrange.lower() == "n":
game['minr'], game['maxr'] = 1, 99 #Default range
unsure = False
elif pickrange.lower() == "y":
customrange(game)
unsure = False
else:
print("INVALID INPUT")
A slightly updated setup (it needed it anyway):
def setup(game):
#minr, maxr make minimum and maximum. Can be adjusted.
#Make sure that maxr - minr is at least 3.
#1 or less would be impossible. 2 would only have one guess for
victory
#The first would be unplayable, the second would play itself
if game['maxr'] - game['minr'] <= 2:
raise ValueError("INVALID RANGE!")
game['gcount'] = 0 #Reset guess count
game['target'] = random.randint(game['minr'], game['maxr'])
and putting wantcustom(game) immediately before setup(game) in main().
import random
def customrange(game, lowunsafe=True):
game['defrang'] = False #Keeps setup from changing range to
defaults
while lowunsafe: #makes sure that the low number is positive
picklow = int(input("PLEASE PICK THE LOW NUMBER: "))
if picklow < 0:
print("LOW NUMBER MUST BE POSTIVE")
else:
lowunsafe = False
pickhigh = int(input("PLEASE PICK THE HIGH NUMBER: "))
if pickhigh - picklow <= 2: #see setup().
print("HIGH MUST BE AT LEAST THREE GREATER THAN LOW")
else:
game['minr'], game['maxr'] = picklow, pickhigh
print("RANGE IS [%s-%s]!" % (game['minr'], game['maxr']))
def wantcustom(game, unsure=True):
#Allows user to decide their own range for guessing.
while unsure:
pickrange = input("WOULD YOU LIKE TO CREATE A CUSTOM RANGE? Y/
N: ")
if pickrange.lower() == "n":
game['minr'], game['maxr'] = 1, 99 #Default range. see
setup
unsure = False
elif pickrange.lower() == "y":
customrange(game)
unsure = False
else:
print("INVALID INPUT")
def samesettings(game, unsure=True):
while unsure:
keepset = input("USE SAME SETTINGS? Y/N: ")
if keepset.lower() == "y":
game['minr'], game['maxr'] = 1, 99 #Default range. see
setup
unsure = False
elif keepset.lower() == "n":
wantcustom(game)
numplayers(game)
unsure = False
else:
print("INVALID INPUT")
def setup(game):
#minr, maxr make minimum and maximum. Can be adjusted.
#Make sure that maxr - minr is at least 3.
#1 or less would be impossible. 2 would only have one guess for
victory
#The first would be unplayable, the second would play itself
if game['maxr'] - game['minr'] <= 2:
raise ValueError("INVALID RANGE!") #If this fails, check line
43
game['gcount'] = 0 #Reset guess count
game['target'] = random.randint(game['minr'], game['maxr'])
def playerswitch(game):
#Player Switch
#if player's a witch: burn(her)
if game['player'] == game['player1']:
game['player'] = game['player2']
else:
game['player'] = game['player1']
def youwin(game):
if game['pnum'] == 1:
print("CONGRATULATIONS! IT TOOK YOU %s GUESSES" % game
['gcount'])
else:
if game['player'] == game['player1']:
game['p1sc'] += 1
else:
game['p2sc'] += 1
end = "CONGRATULATIONS %s! SCORE -- P1:%s P2:%s"
print(end % (game['player'], game['p1sc'], game['p2sc']))
def playagain(game, unsure=True):
while unsure:
playover = input("PLAY AGAIN? Y/N: ")
if playover.lower() == "y":
game['play'] = True
samesettings(game)
setup(game)
unsure = False
elif playover.lower() == "n":
print("GOOD BYE. PLAY AGAIN SOON!")
game['play'] = False
unsure = False
else:
print("INVALID INPUT")
def autofinish(game):
if game['maxr'] - game['minr'] == 2:
print("...ONLY ONE OPTION LEFT!")
youwin(game)
playagain(game)
def numplayers(game, unsafe=True, prompt="1 OR 2 PLAYERS?\n> "):
while unsafe:
while True:
num = input(prompt)
try: #Make sure that num is valid
num = int(num)
except ValueError:
print("BAD VALUE!")
else:
break
if num == 1 or 2: #ONLY allow 1 or 2P.
unsafe = False
else:
print("INVALID INPUT")
game['pnum'] = num
def guesses(game, unsafe=True):
while unsafe:
while True:
try:
guess = int(input("[%s-%s]%s>> " \
#keeps user aware of who's turn it is, and the range
% (game['minr'], game['maxr'], game['player'])))
except ValueError:
print("BAD VALUE!")
else:
break
if guess >= game['maxr']:
print("NUMBER MUST BE IN RANGE")
guesses(game)
guesscheck(game)
elif guess <= game['minr']:
print("NUMBER MUST BE IN RANGE")
guesses(game)
guesscheck(game)
else:
unsafe = False
game['guess'] = guess
def guesscheck(game):
if game['guess'] == game['target']:
if game['pnum'] == 1:
game['gcount'] += 1
youwin(game)
playagain(game)
elif game['guess'] > game['target']:
print("TOO HIGH")
if game['pnum'] == 1:
game['gcount'] += 1
game['maxr'] = game['guess']
else:
print("TOO LOW")
if game['pnum'] == 1:
game['gcount'] += 1
game['minr'] = game['guess']
def guessing(game):
guesses(game)
guesscheck(game)
if game['pnum'] == 2:
playerswitch(game)
autofinish(game)
def main(game=None):
if game is None:
game = {}
print("WELCOME TO THE SUPER NUMBER GUESSING GAME!")
game['play'] = True
game['player1'], game['player2'] = "P1", "P2"
game['player'] = game['player1'] # P1 goes first
#Scores start at 0
game['p1sc'], game['p2sc'], game['gcount'] = 0, 0, 0
wantcustom(game)
numplayers(game)
setup(game)
while game['play'] is True:
guessing(game)
if __name__ == "__main__":
main()
This is basically finding a balance between being annoyed by prompts
and being annoyed by having to quit and restart. Given the sorts of
people who will play this longer than to find out how it works are the
sort of people who find spreadsheets and powerpoints and EVE online
fun, I'll go with prompts.
> def youwin(game):
> if game['pnum'] == 1:
> print("CONGRATULATIONS! IT TOOK YOU %s GUESSES" % game
> ['gcount'])
> else:
> if game['player'] == game['player1']:
> game['p1sc'] += 1
> else:
> game['p2sc'] += 1
If you had initialized your "game" dict with
player1 = dict(score=0)
player2 = dict(score=0),
game = dict(
player1 = player1,
player2 = player2
player = player1
# ...
)
you wouldn't need the test on
game['player'] == game["player1"]
, and could just use:
game["player"]["score"] += 1
(snip)
> first off, I want to thank all of you for your help with this. I
> really don't think I could've learned all of this out nearly as
> quickly by reading tutorials and documentation, let alone had anything
> near the grasp I have on it now. '''This''' is why I like learning by
> doing. The only things I still don't really understand are .strip
> ().lower(),
.strip() returns a copy of the string without leading and ending
whitespaces (inlcuding newlines, tabs etc). .lower() returns a copy of
the string in all lowercases. Since .strip() returns a string object,
you can chain method calls.
" yaDDA\n".strip().lower()
is just a shortcut for
thestring = " yaDDA\n"
tmp1 = thestring.strip() # => "yaDDA"
tmp2 = tmp1.lower() # => "yadda"
> and try/except/else, and I plan on looking them up before
> I do anything else. In the past few hours I've gone from not having a
> clue what the whole {'fred': 0, 'barney': 0} thing was about to being
> able to fully understand what you're talking about, and put it into
> practice
Quite close... You still failed to understand how dicts could be used to
replace 'if/else' statements (dict-base dispatch is very idiomatic in
Python, and is also a good introduction to OO).
(snip)
> 5; I added the ability for it to automatically complete when there's
> only one option left. I was amazed' I was actually going to ask for
> advice on how to do it here. I was going to say "I was thinking (blah
> blah)", but then I just typed it in, and it worked flawlessly.
Yeps. That's probably why most of us here fell in love with Python: it
makes simple thing simple, and tend to JustWork(tm).
> 6; can anyone think of anything else to add on to/do with this game?
rewrite it once again using objects instead of dicts ?
Anyway, thanks for sharing your enthusiasm with us.
Ahh. I had removed it because it didn't seem to do anything, but I've
readded it.
And I understand your dictionary stuff correctly now, I think, and I
worked it in. Currently, I have:
import random
def safeint(prompt="y"):
while True:
x = input(prompt)
try:
x = int(x)
except ValueError:
print("BAD INPUT!")
else:
break
return x
def safestr(prompt="y"):
while True:
x = input(prompt)
try:
x = str(x)
except ValueError:
print("BAD INPUT!")
else:
break
return x
def customrange(game, lowunsafe=True):
game['defrang'] = False #Keeps setup from changing range to
defaults
while lowunsafe: #makes sure that the low number is positive
picklow = safeint(prompt="PLEASE PICK THE LOW NUMBER: ")
if picklow < 0:
print("LOW NUMBER MUST BE POSITIVE")
else:
lowunsafe = False
pickhigh = safeint(prompt="PLEASE PICK THE HIGH NUMBER: ")
if pickhigh - picklow <= 2: #see setup().
print("HIGH MUST BE AT LEAST THREE GREATER THAN LOW")
else:
game['minr'], game['maxr'] = picklow, pickhigh
print("RANGE IS [%s-%s]!" % (game['minr'], game['maxr']))
def wantcustom(game, unsure=True):
#Allows user to decide their own range for guessing.
while unsure:
tryrange = safestr(prompt=\
"WOULD YOU LIKE TO CREATE A CUSTOM RANGE?
"\
+"Y/N: ")
if tryrange.strip().lower() == "n":
game['minr'], game['maxr'] = 1, 99 #Default range. see
setup
unsure = False
elif tryrange.strip().lower() == "y":
customrange(game)
unsure = False
else:
print("INVALID INPUT")
def samesettings(game, unsure=True):
while unsure:
keepset = safestr(prompt="USE SAME SETTINGS? Y/N: ")
if keepset.strip().lower() == "y":
game['minr'], game['maxr'] = 1, 99 #Default range. see
setup
unsure = False
elif keepset.strip().lower() == "n":
wantcustom(game)
numplayers(game)
unsure = False
else:
print("INVALID INPUT")
def setup(game):
#minr, maxr make minimum and maximum. Can be adjusted.
#Make sure that maxr - minr is at least 3.
#1 or less would be impossible. 2 would only have one guess for
victory
#The first would be unplayable, the second would play itself
if game['maxr'] - game['minr'] <= 2:
raise ValueError("INVALID RANGE!") #If this fails, check line
43
game['gcount'] = 0 #Reset guess count
game['target'] = random.randint(game['minr'], game['maxr'])
def playerswitch(game):
#Player Switch
#if player's a witch: burn(her)
if game['player'] is game['player1']:
game['player'] = game['player2']
else:
game['player'] = game['player1']
def youwin(game):
if game['pnum'] == 1:
print("CONGRATULATIONS! IT TOOK YOU %s GUESSES" % game
['gcount'])
else:
game['player']['score'] += 1
end = "CONGRATULATIONS %s! SCORE -- P1:%s P2:%s"
print(end % (game['player']['name'],\
game['player1']['score'], game['player2']['score']))
def playagain(game, unsure=True):
while unsure:
playover = safestr(prompt="PLAY AGAIN? Y/N: ")
if playover.strip().lower() == "y":
game['play'] = True
samesettings(game)
setup(game)
unsure = False
elif playover.strip().lower() == "n":
print("GOOD BYE. PLAY AGAIN SOON!")
game['play'] = False
unsure = False
else:
print("INVALID INPUT")
def autofinish(game):
if game['maxr'] - game['minr'] == 2:
print("...ONLY ONE OPTION LEFT!")
youwin(game)
playagain(game)
def numplayers(game, unsafe=True):
while unsafe:
num = safeint(prompt="1 OR 2 PLAYERS?\n> ")
if num == 1 or 2: #ONLY allow 1 or 2P.
unsafe = False
else:
print("INVALID INPUT")
game['pnum'] = num
def guesses(game, unsafe=True):
while unsafe:
guess = safeint(prompt="[%s-%s]%s>> " % \
#Shows range
(game['minr'], game['maxr'],\
#And which player's turn
game['player']['name']))
if guess >= game['maxr']:
print("NUMBER MUST BE IN RANGE")
guesses(game)
guesscheck(game)
elif guess <= game['minr']:
print("NUMBER MUST BE IN RANGE")
guesses(game)
guesscheck(game)
else:
unsafe = False
game['guess'] = guess
def guesscheck(game):
if game['guess'] == game['target']:
if game['pnum'] == 1:
game['gcount'] += 1
youwin(game)
playagain(game)
elif game['guess'] > game['target']:
print("TOO HIGH")
if game['pnum'] == 1:
game['gcount'] += 1
game['maxr'] = game['guess']
else:
print("TOO LOW")
if game['pnum'] == 1:
game['gcount'] += 1
game['minr'] = game['guess']
def guessing(game):
guesses(game)
guesscheck(game)
if game['pnum'] == 2:
playerswitch(game)
autofinish(game)
def main(game=None):
player1, player2 = dict(name="P1",score=0), dict
(name="P2",score=0)
if game is None:
game = dict(
player1 = player1,
player2 = player2,
player = player1,
play = True
)
print("WELCOME TO THE SUPER NUMBER GUESSING GAME!")
wantcustom(game)
numplayers(game)
setup(game)
while game['play'] is True:
guessing(game)
if __name__ == "__main__":
main()
>rewrite it once again using objects instead of dicts ?
I'd need to find out how those work, and I have a list of python stuff
to read piling up anyway... That said, I think for something like
that, something that's not a major flaw, I'd prefer to make something
else, and maybe work on this again later on. There is only so much
guessing numbers one person can take.
Doesn't input already return a string ?
> except ValueError:
> print("BAD INPUT!")
> else:
> break
> return x
You could as well replace the 'break' statement by 'return x' - since
returning will obviously break the loop
Now don't you notice kind of a pattern in these two functions ?
obviously, the only thing that change is the conversion/validation part.
The good news is that Python functions are objects too, so you can pass
them as params to another function. The generic version of your above
code could be:
def safeinput(prompt, convert):
while True:
x = input(prompt)
try:
x = convert(x)
except ValueError, e:
print("Bad input : %s" % e)
else:
return x
then you can use it for int:
i = safeinput("Please enter an integer", int)
or use more complex conversion/validation:
def yesno(s):
s = s.strip().lower()
if not s in ("y", "n"):
raise ValueError("please answer with 'y' or 'n'")
# we return a boolean
return s == 'y'
answer = safeinput("really do this ?", yesno)
Last point : if your conversion/validation function needs more arguments
than the value to convert - ie : converting to an int and vaidating this
int is in a specified range, which require mini and maxi arguments for
the range - you can use partial evaluation[1]:
from functools import partial
def int_in_range(x, mini, maxi):
x = int(x)
if not mini <= x <= maxi:
raise ValueError("%s is not in range (%s, %s)" % (x, mini, maxi))
return x
i = safeinput(
"Please enter an int between 1 and 99",
partial(int_in_range, mini=1, maxi=99)
)
[1] given the function f(x, y): return x + y, the partial evaluation
partial(f, x=2) is a function fx(y) that when called returns the result
of f(2, y).
(snip)
>> rewrite it once again using objects instead of dicts ?
>
> I'd need to find out how those work,
Mostly as glorified dicts with associated functions. Your game and
players dicts are obvious candidates. Whenever you see a dict with a
more or less defined "structure" and a set of functions working on this
dict, you have in fact a class waiting to be born.
> and I have a list of python stuff
> to read piling up anyway... That said, I think for something like
> that, something that's not a major flaw, I'd prefer to make something
> else, and maybe work on this again later on. There is only so much
> guessing numbers one person can take.
Indeed. That was just a suggestion, and it would have been pretty
interesting IMHO as a basis for a "from Q&D procedural scripting to OO
application programing" tutorial.
duh, duh, duh, duh, duh! I knew I was missing something there. Thanks.
>if not mini <= x <= maxi:
also thanks for this, I forgot about that. But I have it as
if not minr < guess < maxr:
because it's to DISALLOW the numbers to stay the same.
>That was just a suggestion, and it would have been pretty
>interesting IMHO as a basis for a "from Q&D procedural scripting to OO
>application programing" tutorial.
Yeah, I can see that.
Or (I think more straightforwardly):
def safeinput(prompt, convert):
while True:
text = input(prompt)
try:
return convert(text)
except ValueError as e:
print("Bad input ({0!r}): {1}".format(text, e))
> ...
>
> def yesno(s):
> s = s.strip().lower()
> if not s in ("y", "n"):
> raise ValueError("please answer with 'y' or 'n'")
> # we return a boolean
> return s == 'y'
def yesno(s):
s = s.strip().lower()
if s in ("y", "n"):
return s == 'y' # return a boolean
raise ValueError("please answer with 'y' or 'n'")
> def int_in_range(x, mini, maxi):
> x = int(x)
> if not mini <= x <= maxi:
> raise ValueError("%s is not in range (%s, %s)" % (x, mini, maxi))
> return x
def int_in_range(x, below, above):
x = int(x) # may cause ValueError on its own
if below < x < above:
return x
raise ValueError("{0} is not between {1} and {2}".format(
x, mini, maxi))
These changes are mostly:
(1) Negated tests are harder yo read
(2) raise and return change the flow of control, so
if ...:
<raise or return>
else:
...
is "fat" (more trouble to read).
(3) Adopting to the new 3.0 string formatting.
--Scott David Daniels
Scott....@Acm.Org
You could also do this to be a little more user friendly:
if not (s and s[0] in ("y", "n")):
Or reverse the test for clarity.
--
D'Arcy J.M. Cain <da...@druid.net> | Democracy is three wolves
http://www.druid.net/darcy/ | and a sheep voting on
+1 416 425 1212 (DoD#0082) (eNTP) | what's for dinner.
> 6; can anyone think of anything else to add on to/do with this game?
> With the minr/maxr display, multiplayer, score keeping, and
> automation, I'm just about all of ideas. All I can think of left to
> add is 3 and 4 player modes, or a fork where player 2 can't win
> (kekekekeke. Though I'm not sure how to do it...), both of which I
> feel are somewhat pointless for a game like this. If I can't learn
> anything more from it, I will probably go back to reading python
> guides for a bit, and then try to make something else.
Well, if you want to aim for several more rounds of refinement, how
about having the game allow many players identified by name
and have it keep records in a file: player name, number of times
played, best score, best elapsed time for game completion - for each
player. Can you do it in such a way that multiple people on different
PC's can all play the game at the same time and not scribble over each
other's scores? One approach would be to insist that the player's
computers be able to share access to a particular directory, perhaps
using a network mount of a disk from somewhere. A fancier approach
would be to have a score keeping "service" that runs somewhere and
each player's computer uses the network to interact with that score
keeping service. Besides the game playing front end to the score
keeping service, maybe you should have an administrative front end to
the score keeping service to allow you to delete the names of deceased
game players. (The only thing keeping him on his perch were tiny
little nails through his feet).
Can just anyone play the game or does the administrator have to add
their name as an authorized player to the score keeping service before
they are allowed to play? Is it "Scout's honor" that palyers are who
they say they are, or is there some kind of authentication for a
player to "prove" their identify before they are allowed to play?
I remember many years ago back in graduate school, a friend
implemented a clone of "pong" with record keeping. People would sit
with that stupid game into the middle of the night striving to improve
their standings in the best score display. May be more addictive
with a "harder" game than this number guessing game but having your
score being visible to other players can be powerful motivation to
strive for better scores. If only my friend had figured out a way to
have the little DEC GT40 demand quarters if the player wanted to play
again, he'd have had most of his tuition nicely covered.
If your mind is ready to try something completely different, another
thing you could strive to do is change the game from a "tty" interface
to something more screen oriented. e.g. instead of having a prompt
for "play again (y or n):" you'd have buttons on the screen that the
player can click that say "quit" or "start new game". Note that the
player might decide to click on either of those buttons at any time,
not just after they have completed a game. Python has several many
different libraries that would give you a basis for building such a
"graphical user interface" (GUI) version of your game, but I'm not
experienced enough to tell you which GUI package you should look into.
Not so much related to the business of making a niftier game, but
another area you might want to look into is change management (e.g.
"subversion") so you can track the evolution and refinement of your
source code over time. The player-visible part of that is perhaps
just to have something that announces which revision of the game they
are running such that you can tell from that which revision of the
source code to look at if you are tracking down a fix for a problem
they have encountered and reported to you.
Drew
> On Tue, 16 Dec 2008 13:59:24 -0800
> Scott David Daniels <Scott....@Acm.Org> wrote:
>>> > def yesno(s):
>> > s = s.strip().lower()
>> > if not s in ("y", "n"):
There was a thread about "is not" recently. Python also allows "not in".
if s not in ("y", "n"):
> You could also do this to be a little more user friendly:
> if not (s and s[0] in ("y", "n")):
Or:
if s[:1] not in ("y", n"):
--
Arnaud