Public Group

# PyGame, Scrambled Words (Basic Graphics)

This topic is 3751 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Download Here You can download it and try it out there, it requires a couple font files to be in the same directory so just extract the whole thing to a folder and run game.py It doesn't have a whole lot of functionality right now but it shows a scrambled word and you can enter input on the pygame window. Press enter to submit your guess, and it quits the program should you have guessed it correctly. The code is really messy though, I'm not happy with it, so any suggestions on how to tidy it up/organize it would be awesome. Game.py
# SCRAMBLED WORDS
# v0.1b
#
# A game that asks users to guess scrambled words.
# Stephen Lemp - 2008

# IMPORTS #

from random import randrange, shuffle, choice
from sys import exit
from pygame.locals import *
from words import Words, scramble_word
from round import Round
import pygame, os, resource, textbox

# VARIABLES/CONSTANTS #

''' Contains all the strings we may want to show the user for quick access.'''
prompts = { 'wrong_answer': 'Sorry, that is incorrect.\n',
'right_answer': 'Congratulations, you\'ve guessed the word.\n',
'welcome': 'Welcome to Scrambled Words!\n',
'goodbye': 'Thanks for playing Scrambled Words!\n' }

''' Number of words per round. '''
ROUNDLENGTH = 4

''' Pygame Constants'''
SCREEN_SIZE = [640, 480]
BLACK = (0, 0, 0)
WHITE = (255, 255 ,255)
BLUE = (25 ,25 , 255)

# METHODS #

def init_bg(pysurface):
bg = pygame.Surface(pysurface.get_size())
bg = bg.convert()
bg.fill(BLACK)
return bg

def init_title():
scrubble_font = resource.get_font("scrubble.ttf", 36)
text = scrubble_font.render("SCRAMBLED WORDS!", 1, BLUE)
return text

def main():
# Initializations #
pygame.init()
resource.set_fonts_path(os.path.dirname(__file__))

# Instantiations #
WORDS = Words()
ROUND = Round()
user_input_string = []

# -------------------------------------------------------------
screen = pygame.display.set_mode((SCREEN_SIZE))
clock = pygame.time.Clock()
background = init_bg(screen)
title = init_title()
font = pygame.font.Font(None, 24)
font = font.render(WORDS.init_word(), 1, WHITE)

# -------------------------------------------------------------
textbox.draw_input_box(background, WHITE, BLACK, 160, 70, 200, 40, 2)
background.blit(font, (160, 46))
background.blit(title, (160, 5))
screen.blit(background, (0,0))
pygame.display.flip()

# -------------------------------------------------------------
''' Game Loop Variable '''
RUNNING = True

while RUNNING:
if textbox.get_input(screen, background) == WORDS.the_word:
RUNNING = False
pygame.quit()

pygame.time.wait(20)

if __name__ == '__main__':
main()


Words.py
# ------------------------------------------------------------
# The Words class
#
# ------------------------------------------------------------

from random import shuffle, choice, randrange

class Words():
def __init__(self):
""" This class selects and scrambles words. """
self.clues = { 'gasoline': 'Fuel',
'airplane': 'Flying Machine',
'cardstock': 'Thick Paper',
'keyboard': 'Instrument',
'monitor': 'A Display',
'calculator': 'Number Cruncher',
'gigantic': 'Huge'}
self.the_word = ""       # Chosen word from clues
self.scrambled_word = "" # the_word once scrambled
self.remaining_words = self.clues.keys()    # A list of used words so we don't pick one twice.

def init_word(self):
""" Selects a word, then scrambles it. """
shuffle(self.remaining_words)
self.the_word = self.remaining_words.pop()
self.scrambled_word = scramble_word(self.the_word)

return self.scrambled_word

def show_scramble(self):
""" Display the scrambled word. """
font = pygame.font.Font(None, 24)
text = font.render("The Scrambled word is: " + self.scrambled_word, 1, WHITE)
print "The scramble is:", self.scrambled_word + '\n'
return text

def show_clue(self, tries):
""" Display a clue once the user has tried to guess it 3 times. """
if tries == 4:
print "Your clue is: ", self.clues[self.the_word], '\n'

def scramble_word(the_word):
""" Shuffle/Scramble a word up. """
word = list(the_word)
shuffle(word)
shuffled_word = "".join(word)
return shuffled_word


Round.py
# ------------------------------------------------------------
# The round class
#
# ------------------------------------------------------------

class Round():
""" This class keeps track of scores and game variables. """
def __init__(self):
self.roundnumber = 1
self.score = []
self.wordcount = 1
self.possiblescore = 0

def start_round(self, word):
""" Sets the required variables for the beinning of a round. """
self.tries = 1
self.the_word = word
self.possiblescore += len(word)

def get_guess(self):
""" Get the user's guess. """
guess = raw_input("Enter your guess: ")
guess = guess.lower()
print ""
return guess

def guess_again(self):
""" See if the user would like to guess again."""
print "Would you like to guess again?"
usr_input = raw_input("y or n: ")
usr_input = usr_input.lower()
print ""
self.tries += 1
if usr_input == "y":
return True
else:
return False

def calc_score(self):
""" Calculates the users score, on a per word basis
then it adds it to a list so we can see how they did
on each word as well as their final score. """
word_length = float(len(self.the_word))
tries = float(self.tries)
score = int(word_length / tries * 100)
self.score.append(score)
print "Your score for that word was:", score, "out of a possible", int(word_length * 100), '\n'

def show_score(self):
""" Displays the sum of each words score. """
total_score = 0
for item in self.score:
total_score += item
print "Your score was:", total_score, 'out of a possible:', self.possiblescore * 100, '\n'


textbox.py
import pygame, pygame.font, pygame.event, pygame.draw, resource, os
from pygame.locals import *

# COLORS #
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

# Letter List #
letter_list = [K_a, K_b, K_c, K_d, K_e, K_f, K_g, K_h, K_i, K_j, K_k,
K_l, K_m, K_n, K_o, K_p, K_q, K_r, K_s, K_t, K_u, K_v,
K_w, K_x, K_y, K_z]

def get_key_stroke():
""" Get user interaction from PyGame """
for event in pygame.event.get():
if event.type == KEYDOWN:
return event.key

def draw_input_box(surface, border_color, background_color, x, y, width, height, outline_width):
""" Draw two boxes to create an empty text box. """
pygame.draw.rect(surface, border_color, (x, y, width, height), 0)
pygame.draw.rect(surface, background_color, (x + outline_width, y + outline_width, width - (outline_width * 2), height - (outline_width * 2)), 0)

def draw_font(surface, message, color, x, y):
""" Draw a text message on a surface. """
font = resource.get_font("lucon.ttf", 18)
renderedfont = font.render(message, 1, color)
surface.blit(renderedfont, (x + 12, y + 12))

def get_input(screen, surface):
input_string = []

while 1:
key = get_key_stroke()
if key == K_ESCAPE:
return "".join(input_string)
elif key == K_RETURN:
return "".join(input_string)
elif key == K_BACKSPACE:
if len(input_string) > 0:
input_string.pop()
elif key in letter_list:
if len(input_string) > 15:
input_string.pop()
input_string.append(chr(key))
draw_input_box(surface, WHITE, BLACK, 160, 70, 200, 40, 2)
draw_font(surface, "".join(input_string), WHITE, 160, 70)
screen.blit(surface, (0,0))
pygame.display.flip()

def main():
pygame.init()
resource.set_fonts_path(os.path.dirname(__file__))
screen = pygame.display.set_mode((640, 480))
background = pygame.Surface((640, 480))
background.convert()
screen.blit(background, (0,0))
pygame.display.flip()

print get_input(screen, background)

if __name__ == '__main__' :
main()



##### Share on other sites
Hm, I have Python 2.5 and it says it can load the module 'resource'. What version are you using?

You probably want to use py2exe to wrap the whole thing into an .exe so that people can run it without having to install python or pygame.

##### Share on other sites
Quote:
 Original post by mikemanHm, I have Python 2.5 and it says it can load the module 'resource'. What version are you using?You probably want to use py2exe to wrap the whole thing into an .exe so that people can run it without having to install python or pygame.

I'll do that. one sec. It failed on MSCVR80.DLL and I have to head to work.

but here is resource.py
import pygame, os# import pygame.image, pygame.font, pygame.mixer # remove for pygame >=1.4"""resource.pyA caching resource loaderLicense: Public DomainAuthor: David Clark (silenus at telus.net)This module wraps pygame's resource loading functions.  It ensures that onlyone copy of any given resource will be in memory at any time - further requestsfor that same resource will get a reference to the loaded copy.  This behavoircan be overridden by specifying that the resource loading be forced - allclients of that resource will then refer to the new version.  The resource canbe manually removed from memory with the clear_* set of functions.This code might be useful if a game is going to be loading many copies of agiven disk resource.  Most of the time, you'd write your own cache; now youcan just use this one.Remember to call the 'set path' functions before trying to load anything;otherwise, you'll get a ValueError."""__images = {}__fonts = {}__sounds = {}__images_path = None__fonts_path = None__sounds_path = Nonedef get_image(filename, force_reload = 0):    """    get_image(filename, force_reload = 1) --> surface    Call this function instead of pygame.image.load - it will load the image    from the disk the first time, then just return a reference to the copy each    subsequent time.  This function does no colorkey setting or pixel format    conversion; you'll have to do that manually, if you wish.    """        if not __images_path:        raise ValueError, "resources.set_images_path() not called yet."    if (force_reload == 1 or filename not in __images.keys()):        try:            surface = pygame.image.load(os.path.join(__images_path, filename))        except pygame.error:            raise IOError, "File " + filename + " not found."        __images[filename] = surface        return surface    else:        return __images[filename]def has_image(filename):    """    has_image(filename) --> Boolean    Returns true if the image is in memory, false if it has to be loaded from    disk.    """    return __images.has_key(filename)def clear_image(filename):    """    clear_image(filename) --> Boolean    Eliminates the image from memory.  Subsequent calls will load it from the    disk.  Returns True if the resource was found in memory, False if it    Wasn't.  Use this to reduce the memory footprint, if you're sure you won't    be needing the resource again.    """        try:        del __images[filename]        return 1    except KeyError:        return 0def get_font(filename, size, force_reload = 0):    """     get_font(filename, size, force_reload = 1) --> surface    Call this function instead of pygame.font.Font - it will load the font    from the disk the first time, then just return a reference to the copy each     subsequent time.    """    if not __fonts_path:        raise ValueError, "resources.set_fonts_path() not called yet."    if (force_reload == 1 or filename not in __fonts.keys()):        try:            font = pygame.font.Font(os.path.join(__fonts_path, filename), size)        except pygame.error:            raise IOError, "File " + filename + " not found."        __fonts[filename] = font        return font    else:        return __fonts[filename]def has_font(filename):    """    has_font(filename) --> Boolean    Returns true if the font is in memory, false if it has to be loaded from    disk.    """    return __fonts.has_key(filename)def clear_font(filename):    """    clear_font(filename) --> Boolean    Eliminates the font from memory.  Subsequent calls will load it from the    disk.  Returns True if the resource was found in memory, False if it    Wasn't.  Use this to reduce the memory footprint, if you're sure you won't    be needing the resource again.    """    try:        del __fonts[filename]        return 1    except KeyError:        return 0def get_sound(filename, force_reload = 0):    """    get_sound(filename, force_reload = 1) --> sound    Call this function instead of pygame.mixer.Sound - it will load the sound    from the disk the first time, then just return a reference to the copy each     subsequent time.      """    if not __sounds_path:        raise ValueError, "resources.set_sounds_path() not called yet."    if (force_reload == 1 or filename not in __fonts.keys()):        try:            sound = pygame.mixer.Sound(os.path.join(__sounds_path, filename))        except pygame.error:            raise IOError, "File " + filename + " not found."        __sounds[filename] = sound        return sound    else:        return __sounds[filename]def has_sound(filename):    """    has_sound(filename) --> Boolean    Returns true if the sound is in memory, false if it has to be loaded from    disk.    """    return __sounds.has_key(filename)def clear_sound(filename):    """    clear_sound(filename) --> Boolean    Eliminates the sound from memory.  Subsequent calls will load it from the    disk.  Returns True if the resource was found in memory, False if it    Wasn't.  Use this to reduce the memory footprint, if you're sure you won't    be needing the resource again.    """    try:        del __sounds[filename]        return 1    except KeyError:        return 0def set_images_path(path):    """    set_images_path(path) --> Boolean    Set the path you'll be loading the images off of.  Pass the string    representation of the new path.  Raises an exception if the path doesn't    exist, otherwise it returns True.    """    if not os.access(path, os.F_OK):        raise IOError, path + " not found."    if path.endswith(os.sep):        path = path[:-1]    global __images_path    __images_path = path    return 1def set_fonts_path(path):    """    set_fonts_path(path) --> Boolean    Set the path you'll be loading the fonts off of.  Pass the string    representation of the new path.  Raises an exception if the path doesn't    exist, otherwise it returns True.    """    if not os.access(path, os.F_OK):        raise IOError, path + " not found."    if path.endswith(os.sep):        path = path[:-1]    global __fonts_path    __fonts_path = path    return 1def set_sounds_path(path):    """    set_sounds_path(path) --> Boolean    Set the path you'll be loading the sounds off of.  Pass the string    representation of the new path.  Raises an exception if the path doesn't    exist, otherwise it returns True.    """    if not os.access(path, os.F_OK):        raise IOError, path + " not found."    if path.endswith(os.sep):        path = path[:-1]    global __sounds_path    __sounds_path = path    return 1    def get_images_path():    """    get_images_path() --> String    Returns the current value of the images path, or None if it hasn't been    set yet.    """    return __images_pathdef get_fonts_path():    """    get_fonts_path() --> String    Returns the current value of the fonts path, or None if it hasn't been    set yet.    """    return __fonts_pathdef get_sounds_path():    """    get_sounds_path() --> String    Returns the current value of the sounds path, or None if it hasn't been    set yet.    """    return __sounds_path

##### Share on other sites
BTW, 'class X():' with nothing inside the ()'s is invalid syntax before Python 2.5. :)

A few suggestions:

# Don't need to document that Words is the words class. But anyway, don't make# big block comments in Python, when you can use docstrings. :)from random import shuffle, choice, randrange# I like to put helper functions up top. Just personal preference.def scramble_word(the_word):    """ Shuffle/Scramble a word up. """    word = list(the_word)    shuffle(word)    return "".join(word) # Don't bother naming things that are used immediately.class Words:        def __init__(self):        """ This class selects and scrambles words. """        self.clues = { 'gasoline': 'Fuel',                       'airplane': 'Flying Machine',                       'cardstock': 'Thick Paper',                       'keyboard': 'Instrument',                       'monitor': 'A Display',                       'calculator': 'Number Cruncher',                       'gigantic': 'Huge'}        # Instead of keeping a separate list of remaining words, I'm going to        # remove things from the dictionary as we go. This will require        # remembering the clue for the current word, of course...            def init_word(self):        """ Selects a word, then scrambles it. """        # Instead of shuffling something and taking the first value from the        # result, why not just make a random selection? :)        self.the_word = choice(self.clues.keys())        self.clue = self.clues[self.the_word]        del self.clues[self.the_word] # this is how we remove it from the dict.        self.scrambled_word = scramble_word(self.the_word)        return self.scrambled_word    def show_scramble(self):        """ Display the scrambled word. """        font = pygame.font.Font(None, 24)        text = font.render("The Scrambled word is: " + self.scrambled_word, 1, WHITE)        # I assume the print statement was for debugging?        return text    def show_clue(self, tries):        """ Display a clue once the user has tried to guess it 3 times. """        if tries == 4:            print "Your clue is: ", self.clue, '\n'# Let's make the "y or n prompt" function more generic, because I'm sure you'll# find it useful elsewhere.def ask_yes_no(self, prompt):    """ See if the user would like to guess again."""    print prompt    # Don't store temporary values when the logic is straightforward.    # Also, there's no need to check a boolean value in order to decide whether    # to return True or False. Just return the boolean value (or its negation,    # if appropriate).    return raw_input("y or n: ").lower() == 'y'        # ------------------------------------------------------------# The round class## ------------------------------------------------------------class Round:    """ This class keeps track of scores and game variables. """    def __init__(self):        self.roundnumber = 1        self.score = []        self.wordcount = 1        self.possiblescore = 0            def start_round(self, word):        """ Sets the required variables for the beinning of a round. """        self.tries = 1        # We don't need to remember 'the_word' for this class.        # Let's remember the maximum score for the current word, since it's        # used a few places, and factor the '* 100' into the "possible score".        self.wordscore = len(word) * 100        self.possiblescore += self.wordscore            def get_guess(self):        """ Get the user's guess. """        # As before...        guess = raw_input("Enter your guess: ").lower()        print ""        return guess        def guess_again(self):        """ See if the user would like to guess again."""        self.tries += 1        return ask_yes_no("Would you like to guess again?\n")            def calc_score(self):        """ Calculates the users score, on a per word basis            then it adds it to a list so we can see how they did            on each word as well as their final score. """        # A trick for dealing with the "integer division problem" without        # doing annoying stuff with float/int conversion: simply multiply        # before dividing, when you seek an integer percentage.        # Also, let's calculate the max score first, since it's used twice.        score = self.wordscore / self.tries        self.score.append(score)        print "Your score for that word was:", score, "out of a possible", self.wordscore, '\n'            def show_score(self):        """ Displays the sum of each words score. """        # Use built-in functions to add up scores.        total_score = sum(self.score)        print "Your score was:", total_score, 'out of a possible:', self.possiblescore, '\n'

You can, of course, keep going along these lines. I think a lot of the unnecessary complexity here stems from trying to divide labour in unusual ways, and trying to use classes for things where they aren't necessary (hint: a class is supposed to represent "a kind of thing", such that each object is "a thing of that kind". What's a Words? Why does a Round actually remember every round of the game?).

1. 1
2. 2
Rutin
21
3. 3
4. 4
frob
17
5. 5

• 9
• 12
• 9
• 33
• 13
• ### Forum Statistics

• Total Topics
632591
• Total Posts
3007252

×