I Made You a Baby Rogue in Python

A first attempt at a very simple Rogue in Python for beginners to study and learn from. This may become the basis of the new 6th Edition of LPTHW.

By Zed A. Shaw

I Made You a Baby Rogue in Python

I had this crazy idea to rewrite section 3 of Learn Python the Hard Way to teach OOP using Rogue. To test this idea I created an implementation of a simple curses based Rogue in Python.

What is Rogue?

Rogue is a highly influential game from the 80s that's rendered entirely in the terminal using text characters like @ and #. It had many unique features that turned out be incredibly fun, which is why you see those features in so many games today, usually called "Roguelikes." A key feature of Rogue is when you die you keep the items on your "toolbelt." That makes the next run through the dungeon slightly easier, allowing you to get better gear before dying again and repeating the process. Combine that with randomized enemies and levels and you get yourself an infinitely playable game.

What's also interesting about Rogue is that the lack of graphics seems to not matter. People quickly look past the use of text characters and figure out what everything means without a lot of visual feedback. I'd even go so far as to say that Rogue is proof you don't need fancy graphics and color to make a great game.

That's also why Rogue is a common "fun project" for many programmers. Rogue is entirely designed by the programmer as it's all algorithms that create mechanics. This is possible because many things are simplified in the game. Need collision? Just check if the square has something. Need combat? Did the player move into an occupied square? Need pathing? Just use Dijkstra's algorithm and you have everything you need. There's no graphics to worry about, no real-time motion, no lerping smoothly between time frames, just pure code.

I also think just about anyone could make a Rogue game. Can you figure out the curses library? Can you make a 2D array? Then that's mostly what you need. No game engines, 3D graphics, linear algebra, complex trigonometry, just you, a grid, and time. Sure your game

Why?

I've talked before about how Rogue is a great beginner project but I actually didn't test it. I sort of knew it was based on how easily I created one in C++, but I didn't actually make one with the express purpose of teaching. That's usually a different process from making one that I'll develop. To rectify this I created the Curse You Python Rogue project to make sure it actually is something a beginner could accomplish.

The whole implementation took me about 4 hours plus another 4-8 hours to rewrite it and clean it up. The biggest change in the rewrite was switching to numpy for the grid data and operations. Numpy is simply the easiest way to work the grid in the game, and it's also a good opportunity to learn Numpy. Included in this implementation is:

  1. A hunt-and-kill maze generator that includes Room "punched" into the maze for variety.
  2. A pathing algorithm based on Dijkstra's algorithm to path enemies to the player.
  3. A collision system for..collision.
  4. A combat system.
  5. One enemy and a way to randomly spawn as many enemies as you like.

The whole thing ends up being about 350 lines of Python in a single file, and I build it up in stages from a starting point that's only 82 lines of Python.

Based on this I think it might be possible for someone who's learned the basics of Python to tackle this as a project. It'd require a good guide through it, but that's sort of the point of my course.

What About OOP?

Currently the way I teach OOP is to show students how to build their own OOP with just dicts and closures. This solves the normal problem of OOP being taught "tautologically." If you've ever read a description of OOP you know what I mean:

Object Oriented Programming is a style of programming that structures the code into Objects and Classes, that are also Objects and have methods that are on objects. Oh and the methods are Objects. It's so simple!

By showing how all of OOP is nothing more than dicts and closures (plus a bunch of syntactic sugar) you get around the tautology explanations and people actually know what's going on. Similar to how I explain loops now by showing people how to make their own with goto and if-statements.

While this approach works, it suffers from the problem that it's still not obvious why you would do this, or even if it's useful. The idea with the tiny Rogue project is to give people a concrete example of actually using OOP to make something real, and to show them how evaluate when and why to use OOP to make something.

How?

I implemented this first draft of the Curse You Python Rogue in a sequence starting from a simple first implementation. If you read from phase_01.py to phase_13.py then you'll have a basic Rogue that has combat, collision, maze generation, and enemies. I'm not too sure if I like this approach though as it's mostly an exercise in refactoring rather than how to make this kind of game. On the other hand, this does show how to take a piece of code that's not OOP and turn it into one.

Next Steps

I'm next doing to implement the same thing using a simple little ECS (Entity-Component-System) design to test if that's viable as an optional way to do it. I'd like to use ECS as the lesson on "Inheritance vs. Composition" since I've found ECS to be one of the best uses of composition (and I'm kind of kicking myself for not realizing that earlier).


More from Learn Code the Hard Way

I Made You a Baby Rogue in Python

A first attempt at a very simple Rogue in Python for beginners to study and learn from. This may become the basis of the new 6th Edition of LPTHW.

AnnouncementPublished Jul 25, 2025

An Efficient Go Study Guide

I've been learning Go recently and found the documentation is horribly organized so I made this list that reorganizes it into a logical study guide.

AnnouncementPublished Jul 14, 2025

Announcing Painting for Programmers

Announcing my free drawing and painting course on Youtube specifically aimed at programmers.

AnnouncementPublished May 14, 2025

I Preserve the Old Ways...I Guess?

I've realized that I seem to be preserving the old way to code, and I don't know how to feel about that.

OpinionPublished Jan 27, 2025