Posts by Al.

Source Code Makeover: Demon Kingdom, Part 2

This is a continuation of Part 1. I make a lot of the same changes as before, mostly removing duplicate code.

Single-Item Tuple Gotcha, Getting Rid of Redundant update() Call

Diff of these changes: Fixed single-item tuple syntax error and moved initial calls to update to the AnimatedSprite ctor.

Since the AnimatedSprite class’s update() method is always called after the Monster constructor, so we might as well get rid of that method and put its code directly in the constructor function.

Also, there was a slight bug with my last check-in. In Python, a tuple with just one item in it needs a trailing comma to be recognized as a tuple. (Otherwise it’ll just be seen as a value inside parentheses.) The values in the MONSTER_RATIOS variable need this comma added.

You can see this in the interactive shell:

>>> type( (42, 99) )
<type 'tuple'>
>>> type( (42) )
<type 'int'>
>>> type( (42,) )
<type 'tuple'>

Simplying the “final wave” Variables

Diff of these changes: Got rid of a lot of redundant code by adding a FINAL_WAVE_MONSTERS data structure and a populateFinalWave() function.

There are quite a few “finalWave” variables that have a for loop set up to add various monsters to a list. They look like this:

for i in range(21):
    if i - 4 <= 0:
        type = "bat"
        min = -1
        max = -100
    elif i - 13 <= 0:
        type = "plant"
        min = -20
        max = -70
    elif i - 17 <= 0:
        min = -30
        max = -60
        type = "tree"
    elif i >= 18:
        type = "genie"
        min = -30
        max = -60
    # monster adding code here

I can see what they were doing, but they do it in an overly complicated way. When i is between 0 and 4 then the type is “bat”, else if i is 13 or less (but greater than 4, because of the elif) then the type is “plant”.

But the if statements that check the value of i inside this loop aren’t necessary. It would be better to just have several loops without them, which makes the number of each type of monster much more obvious:

for i in range(5):
    type = 'bat'
    min = -1
    max = -100
    # monster adding code here
for i in range(9):
    type = 'plant'
    min = -20
    max = -70
    # monster adding code here
for i in range(4):
    type = 'tree'
    min = -30
    max = -60
    # monster adding code here
for i in range(3):
    type = 'genie'
    min = -30
    max = -60
    # monster adding code here

This code would be used for each “final wave” variable. But we can reduce this even further by just setting up a function with this code and a data structure for each final wave. The new FINAL_WAVE_MONSTERS variable will hold the data for each level’s final wave of monsters. The new populateFinalWave() function has this code typed out just once.

Put Sequential Variables into a Single List

Diff of these changes: Replaced the finalWaveN variables with a list.

We should put the values of the finalWave1, finalWave2, finalWave3, and so on into a single list varialbe, finalWaves. In this particular case, this doesn’t reduce the amount of code. But if we want to do something with this data in a future change, a list is much easier to work with.

Adding a Function to Replace Redundant Code

Diff of these changes: Got rid of redundant code by adding a populateRandomMonsters() function.

There’s a lot of code in the program that is a copy/pasted form of this:

for i in range(random.randint(10, 20)):
    type = random.choice(MONSTER_RATIOS[0])
    m = Monster(screen, *MONSTER_STATS[type]["image"])
    m.set_rect(random.randint( - 500, -1), random.randint(25, WINDOW_HEIGHT - 70 - SIDEBAR_HEIGHT))
    m.set_speed(MONSTER_STATS[type]["speed"])
    m.set_life(MONSTER_STATS[type]["life"])
    monsters1.add(m)

We can put this code in a single function, and replace all these redundant lines of code with a function call. The new populateRandomMonsters() function does the same thing as these loops.

Put Repeated Code in a Loop

Diff of these changes: Put duplicate code into a loop to populate monster sprite groups.

We see this code repeated for each level:

#Level 1
randomMonsters[0] = populateRandomMonsters(1)
finalWaves[0] = populateFinalWave(1)

By putting this code inside a for loop, we only need it typed out once.

Remove fireballsOff Variable

Diff of these changes: Got rid of fireballsOff SpriteGroup object.

(This check-in was actually a mistake on my part. I originally thought this code was pointlessly duplicated. But the separate fireballs and fireballsOff variables are set up so that the user cannot cast the fireball spell again until the previous fireballs have hit a monster or fallen past the edge of the screen. I’ll correct this in a future update.)

(I make this mistake again in the next check in for the ghosts and whirlwind spells. Diff of these changes: Got rid of whirlwindsOff and ghostsOff SpriteGroup objects as well.)

Regression Fix

Diff of these changes: Fixed a regression with doneText

While changing code, I added a new bug. This type of bug is commonly called a regression. This check-in fixes it.

Putting Duplicate Code for Each Level in a Single Loop

Diff of these changes: Collapsed the code that set the monsters object into a loop.

For each of the six levels there is a wave of monsters followed by a “final wave”. Rather than copy and paste the code for each level, we can put it into a single loop. (After level 3 and 6, we display the “done text” to the user.)

Fixing a Bug and Removing Debug Code

Diff of these changes: Fixed a couple bugs with the levelText and also an exception at the end of the game. and Took out some debug settings and code.

These check-ins were to fix a minor bug, and then a second check-in to remove some temporary debug code I accidentally checked in.

There are a few more changes that we can make in part 3. But so far we’ve reduced a program that had 773 lines of code down to 504 lines of code, which is a huge improvement! A good rule of thumb is that the less code there is, the easier it will be to understand and debug.

Share

Source Code Makeover: Demon Kingdom, Part 1

In this blog post, I’m taking a game off of Pygame.org and going through it to make it more readable and extend its functionality. This is an intermediate level tutorial and assumes some familiarity with Python. This can be pretty helpful if you know programming basics but want to know, “How can I write better code?” (And because someone always brings it up, I have this disclaimer: Of course, these changes are my own subjective idea of “better” and not necessarily changes that another developer would make.)

Demon Kingdom by Logi540 is a defense game where monsters walk from the left side of the screen. The player needs to attack them by clicking on them, and can pick up gems to use for spells. If any monster reaches the right side of the screen, the player loses. Download source code.

The main theme of my changes is:

  • Removing duplicate code. Duplicate code is bad because if you have to change it (to add features or fix bugs) you may forget to change it in every duplicated place.
  • Remove magic numbers. Magic numbers are hard-coded integer values which are bad because they don’t describe what they represent. A better alternative is to use a constant instead (these are the ALL-CAPS variables).
  • Put sequential variables in lists and use loops. Instead of having variables named like spam1, spam2, spam3, and so on, it’s better to have a single list variable, and have a loop run code on each item in the list. This usually leads to a decrease in duplicate code.
  • Get rid of unneeded variables. Removing code reaps tons of benefits: there’s less code a programmer has to read and understand, less code that a programmer has to look through when debugging, and less code (usually) means less bugs and “moving parts” that could break.

Here’s the inital check in of all the files. The file I’ll be modifying is named demonkingdom_makeover.py. This program requires Pygame to be installed to run. I recommend downloading the game, playing it a couple times, and looking through the source code before continuing with this article. For each section, open up the diff link to see what the exact changes I made were.

More… »

Share

Comments on John Resig’s “Programming Book Profits” (and on Self-Publishing)

John Resig is the talented creator of the jQuery JavaScript Library and the author of the excellent book Pro JavaScript Technique. In January of 2008, he wrote a blog post entitled Programming Book Profits where he lists several things he wish he knew when starting out writing a programming book.

I wanted to repeat some of the things he said in that post with my own commentary, coming from the perspective of someone who has self-published technical books rather than going through a traditional publisher. I’ve used CreateSpace.com to publish all three of my books, and I haven’t had any problems with them. A special thanks to John for giving me permission to use his article here.

A summary of my points:

  • Publishers don’t do all that much to promote your book, and don’t offer an advantage over self-publishing here.
  • Writing interesting blog posts is a much more effective way to get publicity than buying advertising.
  • Christmas will effortlessly triple your sales, but have your book out there well before the holidays.
  • I use CreateSpace.com as my self-publisher, and haven’t had problems with them. The books only sell through Amazon, and directing readers from my book’s site to the Amazon page using the Amazon affiliate program gets a little extra cash per sale.

When you negotiate a contract with a publisher, and you receive an advance, that’s an advance of your future profits. I had no idea why I never realized this until after I received my first statement and saw -$3000 listed as my payout. It makes a lot of sense, in retrospect – but it was just a silly thing that never quite clicked with me.

Advances are usually pretty low (I think Apress’ typical one was $5000 for a first-time author). In talking with authors at other publishers you can usually expect something in that range – maybe slightly higher.

One thing about self-publishing is that there is absolutely no advance. 100% of the work needs to be done upfront before you see a dime. I wrote my books as a side project while I kept my day job. I don’t currently have any plans to drop my job to write full time.

No one buys eBooks. You’d have to be pretty… special… in order to not be able to find a free ebook of Pro JavaScript Techniques.

I’ve made my books freely downloadable under a Creative Commons license, which I credit entirely with the commercial success of the books. Had I simply made them available for purchase on Amazon, I don’t think anybody would have taken a chance with them. Piracy of the books by readers is not a concern for me, so much as piracy of other people selling my books (I’ve sent one copyright infringement notice to Amazon when someone posted the rough draft of “Hacking Secret Ciphers” for sale as an ebook.)

More… »

Share

Text Adventure vs. MUD vs. Roguelike vs. Dwarf Fortress

A text-style game is a common project for beginner programmers. These can be fun to do, but also require spending time up-front to design it is worthwhile. Before you start designing your own game, look at the design decisions of a few different text-style game genres.

Text Adventures

Also known as interactive fiction or IF, a text adventure game were the first incarnations of these types of games. They are single-player, turn-based (the game paused while the player typed in commands), and presented the user with an English text description of each room the player was in. The player was often a single character with an inventory of items picked up in the rooms. Commands were simple English phrases like "open door" or "get lamp".

West of House
You are standing in an open field west
of a white house, with a boarded front
door.
There is a small mailbox here.
> open mailbox

While the player could die, often the player did not have stats such as hit points, money, or experience points. Text adventures are puzzle-based (such as finding different rooms or figuring out which items to use where), rather than based on progressing in stats or levels.

Text adventure games are more than just “Choose Your Own Adventure” programs, because they take place in open sandbox worlds that the player can freely explore.

These are the simplest types of games to make. In fact, you don’t even need a real programming language to make one of these games. There is software specifically for creating text adventure games.

The 1993 hit Myst is an example of a graphical version of this genre. These games became more sophisticated with the graphic adventure game genre (or “point-and-click adventure games”), the most notable coming from LucasArts. Specialized software for making graphic adventure games also exists, chief of which is Adventure Game Studio.

  • Single-player
  • Turn-based
  • Player directly controls a single character
  • English text descriptions (not ASCII art)
  • English phrases for commands
  • Inventory
  • No stats or levels
  • Puzzle-based and role-playing story elements

More… »

Share

New Forums for the Books

I’ve been meaning to add forums to the website where readers of the programming books could talk to each other and ask questions. I’ve held off on doing this for a while until I could figure out a way to handle spam. However, I’ve decided instead to set up a subreddit for all three books (in effect, making Reddit the host for the forums).

Feel free to email me any questions you have as always, but these forums are also now available to use:

/r/inventwithpython

Share

Multithreaded Python Tutorial with the “Threadworms” Demo

The code for this tutorial can be downloaded here: threadworms.py or from GitHub. This code works with Python 3 or Python 2, and you need Pygame installed as well in order to run it.

Click the animated gif to view a larger version.

This is a tutorial on threads and multithreaded programs in Python, aimed at beginning programmers. It helps if you know the basics of classes (what they are, how you define methods, and that methods always have self as the first parameter, what subclasses (i.e. child classes) are and how a method can be inherited from a parent class, etc.) Here’s a more in-depth classes tutorial.

The example used is a “Nibbles” or “Snake” style clone that has multiple worms running around a grid-like field, with each worm running in a separate thread.
More… »

Share

Switch to our mobile site