For Loop Functions in Python

2019-09-08 20:36发布

问题:

I am continuing with a Hangman project, and I have encountered a problem with a for loop and performing a function inside it. For example, if you press in a level named 'CANADA', and you press 'B', since there are no Bs in Canada, it should draw the first line of the Hangman. This is what I've done so far:

def hangman1():
    pygame.draw.line(screen, black, (775, 250), (775, 50), (4))
def hangman2():
    pygame.draw.line(screen, black, (750, 250), (800, 250), (4))
def hangman3():
    pygame.draw.line(screen, black, (775, 50), (925, 50), (4))
def hangman4():
    pygame.draw.line(screen, black, (925, 50), (925, 175), (4))
def hangman5():
    pygame.draw.circle(screen, black, (925, 100), 30, (0))
def hangman6():
    pygame.draw.line(screen, black, (925, 125), (925, 200), (4))
def hangman7():
    pygame.draw.line(screen, black, (885, 160), (965, 160), (4))
def hangman8():
    pygame.draw.line(screen, black, (925, 200), (900, 225), (4))
def hangman9():
    pygame.draw.line(screen, black, (925, 200), (950, 225), (4))

After a bit more code...

letters = list('abcdefghijklmnopqrstuvwxyz')
a = font2.render(str(letters[0]), True, (black))
b = font2.render(str(letters[1]), True, (black))
c = font2.render(str(letters[2]), True, (black))
d = font2.render(str(letters[3]), True, (black))
e = font2.render(str(letters[4]), True, (black))
f = font2.render(str(letters[5]), True, (black))
g = font2.render(str(letters[6]), True, (black))
h = font2.render(str(letters[7]), True, (black))
i = font2.render(str(letters[8]), True, (black))
j = font2.render(str(letters[9]), True, (black))
k = font2.render(str(letters[10]), True, (black))
l = font2.render(str(letters[11]), True, (black))
m = font2.render(str(letters[12]), True, (black))
n = font2.render(str(letters[13]), True, (black))
o = font2.render(str(letters[14]), True, (black))
p = font2.render(str(letters[15]), True, (black))
q = font2.render(str(letters[16]), True, (black))
r = font2.render(str(letters[17]), True, (black))
s = font2.render(str(letters[18]), True, (black))
t = font2.render(str(letters[19]), True, (black))
u = font2.render(str(letters[20]), True, (black))
v = font2.render(str(letters[21]), True, (black))
w = font2.render(str(letters[22]), True, (black))
x = font2.render(str(letters[23]), True, (black))
y = font2.render(str(letters[24]), True, (black))
z = font2.render(str(letters[25]), True, (black))

Then...

    hangman = [hangman1, hangman2, hangman3, hangman4, hangman5, hangman6, hangman7, hangman8, hangman9]
    for linebyline in hangman:  

Later...

                    elif b1.collidepoint(pygame.mouse.get_pos()):
                        letter = letters[1]
                        check = country.count(letter)
                        if check >= 1:
                            if letter == letters[0]:
                                aPosition = 325, 235
                                a3 = screen.blit((a), (375, 235))
                                a4 = screen.blit((a), (425, 235))
                                a1.x, a1.y = -500, -500
                            elif letter == letters[2]:
                                cPosition = 300, 235
                                c1.x, c1.y = -500, -500
                            elif letter == letters[13]:
                                nPosition = 450, 235
                                n1.x, n1.y = -500, -500
                            elif letter == letters[3]:
                                dPosition = 600, 235
                                d1.x, d1.y = -500, -500
                        else:
                            b2 = font.render(str(letters[1]), True, (red))
                            screen.blit(b2, (485, 325))
                            linebyline()
                            time.sleep(0.5)
                            bPosition = -500, -500
                            b1.x, b1.y = -500, -500

When I press B, it turns red, and in 0.5 seconds it disappears, but it doesn't draw the line. Any help?

EDIT: I did some testing with another module, and the function thing works perfectly fine with printing normal text. But when I tested it again with drawing (Pygame), it worked, but when combined other things (like time.sleep()), it shows a white screen. When combined with a print the drawing thing doesn't work but the printing does. Also, if I added a time.sleep(1), it would have a black screen for exactly nine seconds, without doing anything else. This is my test code:

import pygame, sys, random, time
from pygame.locals import *
pygame.init()

screen = pygame.display.set_mode((1000, 700))
pygame.display.set_caption("Hangman: Countries")
black = 0, 0, 0
def hangman1():
    pygame.draw.line(screen, black, (775, 250), (775, 50), (4))
    print 'test'
def hangman2():
    pygame.draw.line(screen, black, (750, 250), (800, 250), (4))
    print 'test somethin'
def hangman3():
    pygame.draw.line(screen, black, (775, 50), (925, 50), (4))
    print 'test something else'
def hangman4():
    pygame.draw.line(screen, black, (925, 50), (925, 175), (4))
    print 'eggs'
def hangman5():
    pygame.draw.circle(screen, black, (925, 100), 30, (0))
    print 'hangman'
def hangman6():
    pygame.draw.line(screen, black, (925, 125), (925, 200), (4))
    print 'facebook'
def hangman7():
    pygame.draw.line(screen, black, (885, 160), (965, 160), (4))
    print 'internet'
def hangman8():
    pygame.draw.line(screen, black, (925, 200), (900, 225), (4))
    print 'more tests'
def hangman9():
    pygame.draw.line(screen, black, (925, 200), (950, 225), (4))
    print 'cheese'

while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

    screen.fill((255, 255, 255))
    list1 = [hangman1(), hangman2(), hangman3(), hangman4(), hangman5(), hangman6(), hangman7(), hangman8(), hangman9()]
    for greet in list1:
        greet
        time.sleep(1)
    pygame.display.flip()

It prints a bunch of words at the same time in the shell, and then after nine seconds the screen changes into the hangman fully drawn, and the same set of words come back on. Any ideas, anyone of you with experience at Pygame?

回答1:

I made a functioning hangman program just now. Perhaps looking at this logic will help:

Ignore this:

#!/usr/bin/python

import string
alphabet = string.ascii_lowercase

# represents drawing routines
def hangman1():
    print(1)
def hangman2():
    print(2)
def hangman3():
    print(3)
# ignore this, never do this:
def myprint(x): #python2 hack, unnecessary in python3
    print(x)
for i in range(1,10):
    globals()['hangman{}'.format(i)] = lambda i=i: myprint('bodypart#{}'.format(i))

# ignore this
class EnumItem(object):
    def __init__(self, namespace, namespace_name, value):
        self.namespace = namespace
        self.namespace_name = namespace_name
        self.value = value
    def __repr__(self):
        return '{}.{}'.format(self.namespace_name, self.value)
class Enumeration(object):
    def __init__(self, prefix, names):
        prefix = prefix.upper().replace(' ','_')
        globals()[prefix] = self  #don't do this with locals()

        self.items = names
        for i,name in enumerate(names.strip().splitlines()):
            name = name.strip().upper().replace(' ','_')
            value = EnumItem(self, prefix, name)
            setattr(self, name, value)
            #globals()[name] = value  #optional, also don't do this with locals()

Some enums:

Enumeration('GAME_STATE', '''
    active 
    lost 
    won
''')
Enumeration('GUESS', '''
    invalid not a letter
    invalid already guessed
    correct
    correct win
    incorrect
    incorrect loss
''')

Game logic - look at this part if you have trouble thinking through the rules of hangman (I left out a few things to make it run entirely correctly with spaces, to make it easier to understand):

class HangmanGame(object):
    MAX_INCORRECT_GUESSES = 10

    _bodyparts = [
        hangman1, hangman2, hangman3 #...
    ]

    def __init__(self, hidden_goal_phrase):
        self.phrase = hidden_goal_phrase.lower()    # e.g. batman
        self.revealed = '?'*len(hidden_goal_phrase) # e.g. ??????
        self.guessed = set()                        # e.g. {'b', 't'}
        self.num_incorrect_guesses = 0
        self.game_state = GAME_STATE.ACTIVE

    def guess(self, letter):
        """
            Interact with game by calling this function repeatedly with user's guesses
             letter - the letter the player has guessed
        """
        if not letter in alphabet or not len(letter)==1:
            return GUESS.INVALID_NOT_A_LETTER

        if letter in self.guessed:
            return GUESS.INVALID_ALREADY_GUESSED  # or throw a custom exception class HangmanIncorrectGuessException(Exception): pass

        # else guess is legitimate

        self.guessed.add(letter)
        if letter in self.phrase:  # if guess was correct
            # update internal state
            self.revealed = ''.join((c if c in self.guessed else (' ' if c==' ' else '?')) for c in self.phrase)

            # check for win
            print(set(self.guessed), set(self.phrase))
            if self.guessed>=set(self.phrase):  # non-strict superset, see set.__ge__ etc.
                self.game_state = GAME_STATE.WON
                self.redraw
                return GUESS.CORRECT_WIN
            else:
                return GUESS.CORRECT
        else:  # if guess was incorrect
            self.num_incorrect_guesses += 1

            # check for loss
            if self.num_incorrect_guesses==HangmanGame.MAX_INCORRECT_GUESSES:
                self.game_state = GAME_STATE.LOST
                self.redraw()
                return GUESS.INCORRECT_LOSS
            else:
                self.redraw()
                return GUESS.INCORRECT

    def redraw(self):
        '''
            updates canvas to reflect current game state
        '''
        # pygame.clearcanvasorsomething()
        for bodypart in HangmanGame._bodyparts[:self.num_incorrect_guesses]:
            bodypart()

        if self.game_state==GAME_STATE.LOST:
            pass #draw appropriate GAME OVER
        elif self.game_state==GAME_STATE.WON:
            pass #draw appropriate CONGRATULATIONS

Interactive loop:

while True:
    print('NEW GAME')
    game = HangmanGame('penguin')
    while game.game_state==GAME_STATE.ACTIVE:
        result = game.guess(raw_input('Guess a letter: '))
        print(game.revealed, result)
        print('')

Demo games:

NEW GAME                                                                                                                                    
Guess a letter: p
(set(['p']), set(['e', 'g', 'i', 'n', 'p', 'u']))
('p??????', GUESS.CORRECT)

Guess a letter: e
(set(['p', 'e']), set(['e', 'g', 'i', 'n', 'p', 'u']))
('pe?????', GUESS.CORRECT)

Guess a letter: n
(set(['p', 'e', 'n']), set(['e', 'g', 'i', 'n', 'p', 'u']))
('pen???n', GUESS.CORRECT)

Guess a letter: guin
('pen???n', GUESS.INVALID_NOT_A_LETTER)

Guess a letter: 7
('pen???n', GUESS.INVALID_NOT_A_LETTER)

Guess a letter:  
('pen???n', GUESS.INVALID_NOT_A_LETTER)

Guess a letter: z
bodypart#1
('pen???n', GUESS.INCORRECT)

Guess a letter: x
bodypart#1
bodypart#2
('pen???n', GUESS.INCORRECT)

Guess a letter: c
bodypart#1
bodypart#2
bodypart#3
('pen???n', GUESS.INCORRECT)

Guess a letter: i
(set(['p', 'c', 'e', 'i', 'x', 'z', 'n']), set(['e', 'g', 'i', 'n', 'p', 'u']))
('pen??in', GUESS.CORRECT)

Guess a letter: u
(set(['c', 'e', 'i', 'n', 'p', 'u', 'x', 'z']), set(['e', 'g', 'i', 'n', 'p', 'u']))
('pen?uin', GUESS.CORRECT)

Guess a letter: g
(set(['c', 'e', 'g', 'i', 'n', 'p', 'u', 'x', 'z']), set(['e', 'g', 'i', 'n', 'p', 'u']))
('penguin', GUESS.CORRECT_WIN)

NEW GAME
Guess a letter: q
bodypart#1
('???????', GUESS.INCORRECT)

Guess a letter: w
bodypart#1
bodypart#2
('???????', GUESS.INCORRECT)

Guess a letter: r
bodypart#1
bodypart#2
bodypart#3
('???????', GUESS.INCORRECT)

...more incorrect guesses...

('???????', GUESS.INCORRECT_LOSS)