Rogue is the Best Project

My pitch for Rogue being the best for both beginners and old crusty coders like me.

By Zed A. Shaw

Rogue is the Best Project

I've been working on a Roguelike that's turned into my new favorite obsession, and I think you would enjoy making one too. I can't think of a single project I've made in the last 20 years that's been this challenging and enjoyable. Part of this is the nostalgia of working on a style of game I played as a kid, with a language I used as a kid. Despite that I think there is something special about Rogue that makes it an amazing project for anyone who wants to get better at programming, have fun coding, and tackle challenging problems.

Therefore, allow me to convince you to make a Roguelike, and give you advice on how to start. I promise you'll have fun and you don't even need to be a game developer to do it. Everything that makes Rogue work is understandable by anyone with basic programming skills. Sure, your Rogue may suck, but an evening hacking on Rogue is better than 10 days sitting in meetings at $JOB.

NOTE: If games aren't your thing then I have another essay where I describe a bunch of projects you can spend a lot of time in. It's a very extensive list that is more than just a listicle. It gives full project descriptions, links to educational material to use, and other similar projects.

What is Rogue

Rogue is a game released in 1980 that ran on old computers with terrible graphics. Computers could do basic graphics--mostly 2, 8, or 16 color pixel art--but text was definitely the most supported display system. Rogue's big innovation was using text characters to depict a game world to the player and unique game mechanics that are copied by many games today. Here's some of Rogue's innovations (or quirks depending on your view):

Roguelikes and Roguelites

When people make their own version of Rogue they usually call it a "Roguelike" or a "Roguelite" depending on how closely it resembles Rogue. This classification is very broad with games like Hades being considered a Roguelike, and Moonring being a more closely matched Roguelike. There's even an annual celebration of called the Roguelike Celebration and you can watch the 2024 session on their Youtube channel.

If you'd like to try some modern Rogue style games check out some of these:

If you're looking to get started then try out Moonring first. It's not a randomly generated world, but it has many of the elements of rogue in a slightly more modern package, but still features "classic style" visuals. If you want the full Rogue experience then I'd suggest trying NetHack but without the GUI layer.

You Could Make a Rogue

The first thing you should notice is these games are all over the map in complexity, graphic quality, style, and tone. You've got games like Dwarf Fortress which is a colony simulation game with a medieval setting; NetHack which is a classically text based adventure game but with coop network play; Moonring which is a single player game with advanced graphics but still turn based gameplay; and all the way on the other end there's Hades with advanced graphics, sound, and action combat rather than turns. The wide range of styles in the genre means that there's room for anyone's ideas and skill levels. Your roguelike could be a simple Vampire Survivors clone with ASCII art or a space adventure with actual pixel graphics.

This wide open genre means you have freedom to create your idea, but the most important part of this openness is that nobody cares about your graphics. A thing that people love about Roguelikes is the focus on game play, mechanics, and story rather than "realism." Take a game like Moonring. The art in Moonring is superb but I wouldn't say it's graphically advanced or realistic at all. Moonring has style and visual punch that makes the mechanics and gameplay better, but you could strip all of that out and it would still be a great game. Other games like Omega, NetHack, and the original Dwarf Fortress all have ASCII characters only but those games are still amazing to play.

That means you can totally suck at graphics programming and still make one of these games. Think about what makes a "game" for a minute. You have some kind of visual display that presents to the user the state of a complex world they're pretending to believe in. The graphics in a game like Hades would require quite a lot of code and art, but the mechanics and gameplay of Hades--or any game--is really just data and code to control that data. Once you remove the graphics many games are nothing more than a database application, and most any programmer can (or should be able to) make one of those.

What I've found while working on my little Rogue game is that there's really nothing in it that requires advanced programming skills. If you did know advanced programming topics you'd do better at it, but the majority of things you'd have to write to make a Rogue are all things a normal person can figure out. Can you draw a grid and do stuff to the grid? Awesome, you can write a Rogue. Can you come up with a couple of functions that use two data components to make enemies fight? There you go, you've figure out the Roguelike genre.

That doesn't mean it's easy or simple, it means that nothing in a Roguelike is magic or deep algorithms. There's really only one important algorithm (Dijkstra's) and one architecture style and after that you're good. Thankfully both of those are ancient and easily learned or simply copied from online sources (like mine).

Entity-Component-System is Not Magic

Take for example the Entity-Component-System (ECS) pattern, which is probably one of the most important patterns to learn when making a game. If you watch Youtube videos or read blogs about this pattern they speak in mystical terms about how amazing it is for "cache locality" and all the amazing loops that will go faster because you used it but boy is it hard to learn and you better get ready because this is pure performance tuned magic baby!

Yeah, ECS is just the Controller and Model part of Model-View-Controller. That's it. In fact, you could probably implement all of an ECS system with only SQLite3 if your game isn't real-time. I'm serious about this. I almost did that but wanted to make my own ECS. Would be cool though.

Let's break the Entity-Component-System down to what it actually is:

Entity
This is simply a unique identifier, usually an integer. Yes. It's not an object or a struct or any data. It's only a way to identify Components in the game.
Components
These are database tables or sets of columns of a database table, but really it's the data. In my game it's a bunch of mostly dumb structs...you know, like database tables. Yes, that's all this is and I don't know why everyone describing ECS makes it seem so complex.
Systems
These are queries on the components, and code to work on the query results...you know...like a Controller in every other application on the planet. In fact, the Components are simply the Model from MVC, and the Entity is how you identify the Model to work with.

When you view ECS as a style of MVC you may realize the real power of ECS because it's the same reason why every other application domain invented MVC:

Over decades of creating software programmers realized that separating the View from the Data by way of a Controller makes it easier to change the software as requirements change, and keeps things organized.

Sure, if you write your ECS system carefully then it'll get some performance boosts since you can blast through solid arrays of Components, but that's really a tangential benefit that comes from having an easily modifiable architecture with a separation of concerns. Again, this isn't magic or complicated, but game dev people really like making ECS seem like it is magic.

To prove this point I wrote one in 127 lines of C++ code and mine even includes an ability to send messages to components on event queues. It's not crazy advanced but for my little Roguelike it's all I need, and probably all most anyone needs. Will DinkyECS win a performance test against the more established libraries? Hello no, but you could make DinkyECS even if you didn't know C++, and that's a more important goal for me. Also, ECS can't be magic if I can make one with so little code. If ECS was magic then it'd take years to make one, not an evening.

How to Learn Complicated Things

Let's say you want to learn to paint portraits. Painting requires understanding a tightly knit constellation of topics that are interconnected:

  1. Drawing
  2. Perspective
  3. Value Structure
  4. Color Theory
  5. Composition
  6. Actually putting paint on canvas

You could learn to paint by grabbing 10 buckets of paint and repeatedly attempting to paint as many portraits as possible. If you could keep this up then maybe in about 4 years you'd be able to paint a decent portrait, but sustaining that method of learning will be tough. You'd have to struggle through so many bad paintings before you saw progress.

A better way to approach a complex topic like painting is to study one part at a time while trying to apply that study to full sessions. For example, you would spend a few months learning to draw what you see well enough to be close to realistic--not perfect but good enough--then try to do some paintings in monochrome to practice drawing but also Value Structure, Putting Paint on Canvas, and Composition. Once you were pretty good at only painting in monochrome then you could add in color, but a better tactic is to spend a few weeks learning to mix colors you see. Simply spending a few weeks mixing color charts with a palette knife will set you up to apply this color mixing to full color paintings.

The idea is to separate out a piece of this vast topic to focus on it so that you can use that piece without having to think about it. Need to mix colors? Spend a week learning how to mix them really well. Need to draw what you see? Spend a few months learning to draw better. At the same time, take these "point topics" and periodically attempt to use them in full sessions that need to coordinate all of painting at once. Keep doing this and eventually you'll be able to paint without thinking about each piece.

Rogue Provides this Focus

Rogue is this idea for game development because it's a fully formed game that doesn't require any graphics or art skills. Can you find a character on your keyboard that looks like a sword? Great, you've got enough art skills to make a Roguelike. With that removed from the equation you can focus on other important aspects of game development like data structures, algorithms, game play, and mechanics.

This is the other reason why almost anyone could make a Roguelike. You really only need to know how to code a bit to be able to make one because there's no graphics, but these games are still interesting and fun despite that lack of graphics. You could even say that the challenge of making an interesting game without graphics helps you focus on arguably the more important things that make a game fun.

The Three Key Components

If I want you to try to make your own Rogue than I better give you some pointers of important topics to study if you want to make one. I've found that there are only three foreign concepts you need to make your own Roguelike game. Each of these are core features of the game that you'll need:

1. Dijkstra's Algorithm

Dijkstra's Algorithm is an efficient way to find the distance to one square from any other squares in your map. This algorithm shows up so many times that I'd almost say Rogue is a way to learn this algorithm. The things you can do with this one algorithm are insane:

  1. Enemy pathing to the player, but also the enemy can have multiple goals. You can set the player, staying away from the player for range attacks, avoiding hazards, and trying to collect gold all as goals.
  2. Lighting can be done by making a map with each light as a target in the Dijkstra map, then you convert the number to a luminance value for that square.
  3. Sound detection by enemies and line of sight calculations. You simply wait until the number near enemies reaches a threshold, and then the enemy attacks because the player made noise. You can even adjust this based on the player's stealth skills.
  4. You can use a Dijkstra map to create sudden flooding waters, burning rooms, projectiles, and even explosions.
  5. Auto-explore features where people can hit space bar and the player moves through the map.
  6. Enemies running away from the player intelligently (not only running into a corner).
  7. Mouse based pathing where players can click on locations to move or perform actions like range attacks, then you use the map to show where that goes.
  8. Best of all you can use it to do your map generation. I did this in about 200 lines of code by inverting the map then running the pathing from each room to "dig tunnels." The rooms became walls and the walls became one big room. Then I set a target door for each room, ran the pathing, and after I'd connected all the rooms I had carved out all of the space. Once I was done I flipped the space back and I had complex tunnels and ragged paths between all rooms.

Best of all the algorithm is not that hard to implement and there's many implementations already for most languages. Here's how I did it:

  1. I studied the descriptions of the algorithm to be sure I knew how it should work.
  2. I found a simple example on Github written in Python.
  3. I gradually "transliterated" the Python to similar C++ code, while studying the description of the algorithm.
  4. As the C++ implementation progressed I wrote a test to confirm it was working the same as the Python. I did this by having the Python version output a .json file with a grid and a result, then loaded that in the test and check that my C++ version worked.
  5. Once my transliteration worked I went back and cleaned it up to match with standard C++ practices until it didn't really look too much like the original Python.

1. Drawing to the Screen

The next important feature you'll need is obviously drawing the game to a Terminal screen. In my game I use FTXUI but I process its output and render the results to an SFML window. You do not have to do this. I'm mostly doing it to be weird and have fun. For you I think you should simply use the basic curses or ncurses library. This is a very old terminal "graphics" library that will let you draw to the Terminal screen in color. It's supported by almost every programming language out there, and is a simple system to learn.

Here's a list of the curses libraries in many languages:

If curses/ncurses is too hardcore than you can check out these TUI (Text User Interface) libraries:

I'm actually using FTXUI to do mine so feel free to use one yourself, but using curses is also a lot of fun and educational. You may want to do a first one with curses then use a TUI so you understand the basics of the TUI.

3. Entity-Component-System

The ECS of your game will implement the majority of the game's functionality because it provides your primary processing architecture. You'll construct the game's data with Components, identify individual entities by their Entity ID, and process them using various system functions. To understand the ECS concept there's some specific misunderstandings to conquer, and the best way to do that is to show you with a plain old SQL table.

Imagine I have a table that looks like this:

idhpdmgpos_xpos_ymot_dxmot_dy
15050010
23301810100-1

In this table I have an Entity with id=1 and an Entity with id=23. Each of these would be a character or thing in your game. For example, id=1 might be the Player and id=23 might be a Goblin.

Next you have multiple columns that represent different stats about that entity. We have the Player (id=1) hp, damage (dmg), their position (pos_x/pos_y), and their motion (mot_dx/mot_dy) direction. Next row is the same but for the Goblin. These columns are your Components, and notice I said plural "Components"? That's because in your code you'll represent these columns in individual structs for easier processing (I'll show you this soon).

The final piece of the puzzle is the Systems, and those are table queries plus a function to process the query results. Let's say I need to process each entity hitting the player. I would do a query in SQL that might look like this:

SELECT id, hp, damage FROM ecs_table where id != 1

Then in my code I take each result and use it to damage the player. I might have some pseudo code like this:


for id, hp, damage in results:
  player.hp -= damage

That's mostly all you do, but in your code you can do a few things to optimize this so you only process entities that have those columns (Components) active. First, you'll create small classes or structs that contain only the fields you want as small components. Next, you'll store these components in a way that allows you to query any combination of 1 or two components together. Finally, you'll only process components that actually exist in these combinations. Pseudo code for this might be:

player_id = query(Player)
player_combat = query(player_id, Combat)
player_position = query(player_id, Position)

for entity_id, combat, position in query(Combat, Position):
  if entity_id != player_id and neary(player_position, position):
    player_combat.hp -= combat.damage # enemy attacks the player

How to Approach the Project

I recommend that you approach your rogue by doing a short pass to work on a few key features. Try this list as a possible start, which focuses on getting something on the screen and then the base data structures you need for the rest of the game:

  1. Create a simple map with a text editor using '#' characters and your '@' that's about 20x20.
  2. Use this manually created map to work on your display with curses or a TUI. If you can get this to work then you'll be able to see everything else you make next.
  3. Dijkstra map will then allow you to create almost everything else from random maps to enemy paths.
  4. Once you have a Dijkstra algorithm plotting out a grid with pathing numbers you should get your display to show them.
  5. If you can display a Dijkstra map with your player as the target then you can work on pathing, which means it's now time to implement your ECS.
  6. Create a simplified ECS that can do only combat, positions, and motion. This is all you need to move an enemy to the player and fight. The components will probably be named Combat, Position, and Motion. The systems will query those and use the Dijkstra map to move enemies to the player.

At this point you should have enough core features working that you can continue to evolve the game in the direction you want. I think for your first Rogue try to keep it simple and to the point. Maybe create a simple classic Rogue with a dungeon, some enemies, and a few unique weapons. Once you have that all working you could start a new one with new ideas, or keep working on this one. I'm a big fan of making many little projects to build confidence, but putting yourself into one giant project for a sustained period is also educational.

Stay Tuned for Part 2

This essay was extremely difficult to write and already too long, so rather than overload it with even more information I'm going to work on a part 2. Part 2 will go deeper into how to make the base of a Roguelike and feature example code to get you started. Until then, try it on your own and see how you do.

And, if you want to watch me work on mine live you can follow my Twitch where I livestream my fun hacking every day at 8am EST (or there abouts). You can also check out my project's code at my personal git hosting if you're curious how I'm doing it. Keep in mind that this code is in C++ but I do try to keep it small and understandable so that it can fit into the C++ course I'm developing.


More from Learn Code the Hard Way

Rogue is the Best Project

My pitch for Rogue being the best for both beginners and old crusty coders like me.

TechnologyPublished Jan 1, 2025

Very Deep Not Boring Beginner Projects

A list of projects that anyone with basic programming knowledge can do in any language, but have a lot of depth and aren't boring to do.

OpinionPublished Oct 1, 2024

C++ Is An Absolute Blast

Where I try to explain why I feel like C\+\+ is so much fun, and to correct some misinformation.

TechnologyPublished Oct 1, 2024

Just Use MSYS2 You Say?

Debunking idiots on HackerNews who think a total beginner can just 'Use MSYS2' on Windows.

TechnologyPublished Jul 16, 2024