A Word Unscramble Game Built Using Python
A Python Based Word Unscramble Game
Developed by Gerard Ian M. Balaoro
The execution process of application is contained in main.py.
External modules and the PyGame package are imported first.
from config import *
from engine import *
from interface import *
import pygame as pg
The Game and Engine classes are initialized and the game interface is shown.
# Initialize Game Engine
ENGINE = Engine()
# Initialize Game Interface
instance = Game()
At this point, the property running
of the Game class is set to True
. While that is, show the user interface and run the game.
while instance.running:
# Show Start Screen
mode = instance.start_screen()
# If the user pressed 'i'
if mode == 'i' :
# Show Credits Screen
instance.credits()
continue
# If the user clicked the close button
elif mode == None:
break
# If the user selected a valid game mode
else:
# New Game, Pass Engine Instance, and mode configuration
# This will run until the game is over or escaped
instance.new(ENGINE, mode)
# Show Game Over Screen
instance.game_over()
Quit PyGame and destroy the window at the end.
pg.quit()
The source files of the application are arranged according to the diagram below.
.
├── ...
├── assets # Application Assets
│ ├── audio # Sounds / Music Files (*.wav)
│ ├── fonts # Font Files (*.ttf)
│ ├── images # Images (*.png)
│ └── source # Dictionary Files (.*txt)
├── config.json # User Configuration
├── config.py # Application Configuration
├── engine.py # Game Logic Engine Class
├── interface.py # PyGame Interface Class and Methods
├── main.py # Main / Entry Script
├── setup.py # Distutils Setup Script
├── sprites.py # Sprites / Game Object Classes
└── ...
The application interface powered by the PyGame Library are composed of two parts: the Game and Sprite classes.
The Game class is located at the interface.py file and serves as the primary provider and manager of the application’s interface.
game = Game()
When called, the class uses the values stored at the configuration to initialize the game window and the resources required by each of its components.
game.load()
Load Resources
Returns: None
game.new(engine, mode)
Start a New Game
From the engine instance passed, this method automatically retrieves 3 words from the dictionary using the
random.sample()
function and creates a new letter pool.It also sets the global variables
lives
andtime
.
Engine
: an instance of game enginedict
: Game mode, as defined in configurationNone
game.new()
Run the Game Proper
The play screen is shown and a global variable
playing
is set toTrue
. While is it, a loop that updates the screen elements such as the tiles and the other controls is executed until thelives
ortimer
has reached zero, or the user ends the game by closing window or pressing the escape key.
None
game.update()
Refresh Game Window
None
game.events()
Handles Game Events [ i.e. user input and key press ]
None
game.draw()
Draw Game Elements
None
game.start_screen()
Show Start Screen
dict
: Game mode, as defined in configurationstr
: Only if 'i'
is selected, which shows the credits screengame.credits()
Show Credits Screen
None
game.game_over()
Show Game Over Screen
None
game.wait_input()
Wait for User Input
Used for Static Screens (Start Menu, Game Over, etc.)
list
: List of accepted keysstr
: Key name, noneThe sprites.py contains pygame.sprite.Sprite
classes that are used throughout the interface
Letter(letter [, position = 1, length = 1, size = 80, margin = 55, button = False])
Produces a single letter tile
Image(name [, scale = 1, x = 0, y = 0])
Produces an image block
Text(text, size, color [, x = 0, y = 0, font = 'GothamNarrow-Medium.ttf'])
Produces a text block
Adapted from the work of Gareth Rees
Copyright (c) 2013. Under CC-BY-SA 3.0 License
Button(text, x, y [, size = 15, scale = 0.50, color = None, image = 'button.png', font = 'GothamNarrow-Medium.ttf', text_offset = (-1,-1)])
Produces a button
All media used on the Game class are loaded through the __init__()
and load
functions. Sources are declared at the configuration.
The Engine
class defined at the engine.py contains the core program logic of the application.
engine = Engine([, path = ''])
str
: Optional path to dictionary fileWhen called, the class automatically loads the default dictionary file from config.py if no path is passed.
engine.seed(path)
Read Dictionary Text File
The file contents are assigned to the global variable
dictionary
accessible in-class usingself.dictionary
and outside the class usingengine.dictionary
str
: Path to dictionary fileNone
engine.pick([, number = 3, indices = []])
Get List of Words from Dictionary
This method implements the method
random.sample()
to select words form the globaldictionary
and defines a global variablepicked
containing the selected words
int
: Number of words to picklist
: List of indiceslist
: List of wordsengine.search([, source = ''])
Find Anagrams from Dictionary
If no source is provider, the global variable
pool
will be used. This method also sets a global variablematchable
containing the anagrams found.Note that if
source
was passed, thematchable
variable will not be defined or updated.
str|list
: Characters to uselist
: List of wordsengine.combine([, number = 3, words = []])
Create a Scrambled Character Pool
Automatically calls
pick()
method, unless the variablewords
was passed. The pool characters are then assigned to a global variablepool
.If the variable
words
was passed, the globalpool
will not be defined or updated.
int
: Number of words, passed on to pick()
methodlist
list
: List of lettersengine.check(word, [, pool = []])
Check if word
can be formed using the characters from pool
and exists in the global variable dictionary
If
pool
was not passed, the method uses the global variablepool
str
list
bool
engine.score(word)
Calculates the Score of a Word using Scrabble Points
str
int
All constants and other objects that are used throughout the application are defined at the config.py. This file is imported in all of the scripts that constitute the program.
The config.json, if exists, overrides some values defined in config.py.
{
"dictionary" : "assets/source/dictionary.txt",
"strict" : true
}
At the beginning of config.py, the module attempts to load config.json values.
#: ====================================
#: LOAD CONFIG.JSON VALUES
#: ====================================
if os.path.exists('config.json'):
user = json.loads(open('config.json', 'r').read())
else:
user = {}
#: ====================================
#: INTERFACE
#: ====================================
TITLE = 'PyJumble' # Window Title
WIDTH = 900 # Window Width
HEIGHT = 600 # Window Height
FPS = 60 # Window Refresh Rate
BACKGROUND = 'assets/images/background.png' # Background Image
ICON = 'assets/images/icon.png' # Window Icon
#: ==============================================
#: DEFAULTS
#: ==============================================
DICTIONARY = user.get('dictionary', 'assets/source/dictionary.txt')
#: Used in Game Modes
LIVES = 3
TIME = 60
SCRAMBLED_WORDS = 3
INSTRUCTIONS = 'CREATE WORDS USING THE LETTERS PROVIDED ABOVE'
#: ====================================
#: GAME MODES
#: ------------------------------------
#: lives/time: 0 = Infinite
#: key: Selection Key on Start Screen
#: exact_match: Entries must use all the letters from the anagram
#: scrambled_words: Number of words from the dictionary to scramble
#: instructions: Instructions
#: ====================================
MODES = [
{
'name': 'BASIC',
'key': 'b',
'lives': 3,
'time': 0,
'exact_match': False,
'scrambled_words': SCRAMBLED_WORDS,
'instructions': INSTRUCTIONS
}
]
#: ====================================
#: AUDIO FILES
#: ====================================
AUDIO = {
'enter': 'assets/audio/swap.wav', # Enter/Backspace/Esc Key Press
'click': 'assets/audio/swap.wav', # Alpha Key Press
'success': 'assets/audio/match.wav', # Correct Answer
'fail': 'assets/audio/error.wav', # Wrong Answer
'start': 'assets/audio/start.wav', # Start of a New Game
'end': 'assets/audio/over.wav', # End of Game
'menu': 'assets/audio/yippee.wav', # Background Music on Start Screen
'game': 'assets/audio/happytune.wav', # Background Music on Game Screen
}
#: ====================================
#: STRICT MODE
#: ------------------------------------
#: Deduct points on duplicate entries
#: ====================================
STRICT = user.get('strict', True)
This application requires the PyGame package. Install it by using pip by running the command:
pip install pygame
See their documentation for information on installing the package without pip.
Run the main script.
python main.py
Note: This version of the program has only been tested in Python 3.4 to 3.7
The cx_Freeze package is used to compile executable binaries and create installers. Currently, only Windows distributables are supported. The package uses Python 3.6 binaries during build, as such Python 3.6 is required. Problems were encountered during install or build when using other Python versions.
The build configuration is defined in setup.py. For more information, read cx_Freeze documentation.
Install cx_Freeze using pip by running the command:
py -3.6 -m pip install cx_Freeze
Build Windows Binaries (32-bit)
py -3.6 setup.py build
Build Windows Installer (MSI)
py -3.6 setup.py bdist_msi