- Common Loki Misconfigurations
- Iterating Through a List in Ink
- Debugging Misconfigured Container Networks
- Minimum Viable EC2 in Terraform
- Storylets in Ink
- Interactive Fiction Tooling Overview
- In-Place Resizing for Digitalocean Droplets
- Unity Demonstrates the Importance of FOSS
- Target Labels in Prometheus
- My View of AI is the Same
- Verify DNS Ownership with TXT Records
- Sane Droplet Defaults
- Editing Made Easy with Vim
- Gatsby Gotchas
- Concatinating Default AWS Tags in Terraform
- Easily Updating the Default Github Branch
- Lifetimes in Rust
- Checking for Bad Links
- Maybe TypeScript and React is Bad
- Static Asset Management in React
- Bundler Down Time
- Using React Context for Localization
- JS Implementation of a Sticky Footer
- Custom Aliases
- Trying Out the 7drl Challenge
- Trash Opinions
- Building Your First Program in Rust
- Fixing mongod reports errors related to opening a socket
- Improving Open Source Maintenance
- Technical Interviewing Tips
- Housekeeping Note
- Dynamic Programming Basics
- The Oddity of Naming Conventions in Programming Languages
- An Experiment Using Machine Learning, Part 3
- Debugging with grep
- An Experiment Using Machine Learning, Part 2
- An Experiment Using Machine Learning, Part 1
- The Value of while
- National Day of Civic Hacking
- OpenAI and the Future of Humanity
- Creating a Whiteboard App in Django
- Creating Meaningful, Organized Information
- Towards A Critique of Social Media Feeds
- Setting up Routes in Django
- Developing a Messaging Component for Code for SF
- Dream Stream 2.0
- Keyed Collections in Javascript: Maps and Sets
- Blog Soft Relaunch
- Scraping with Puppeteer
- Looking Ahead to Dream Stream 2.0
- Solving West of Loathing's Soupstock Lode Puzzle
- Installing Ubuntu
- Interview with David Jickling Evaluation
- Compare Text Evaluation
- Dream Stream Evaluation
Trying Out the 7drl Challenge
I’ve played NetHack for about as long as I can remember (for the record I’ve had four successful ascensions, and one gut wrenching botched ascension where I offered the amulet of Yendor to the wrong deity). NetHack helped fuel my interest in computer programming. When I started learning some C and C++ in high school, being able to examine all those .c and .h files really helped make everything I was learning feel far less abstract, and more real (Incidentally, the NetHack code base is super interesting. Alexei Pepers gave an amazing talk titled Tech Tourist Mode: A Guided Tour of the NetHack Codebase that I cannot recommend enough).
Fast forward to one week ago. I saw on Twitter Bob Nystrom produce a slick, compressed piece of C code for generating roguelike dungeons (RIP Ginny). What I liked about the dungeons that were generated is they were wonderfully simple: they consisted of a series of interlocking rooms, no connecting passageways or open world areas in sight! I thought this was the perfect sort of source material for a quick game jam idea. Then I checked the seven day roguelike challenge page. It turned out that it was starting that very day! To me it felt like a signal from the universe to go and do this thing. So I went for it.
I have no experience developing games. The closest I ever came is once while learning to do object oriented programming, a created a class of objects for a deck of ordinary playing cards. I created an interface so that you can do all the ordinary things you do with cards, but no enforcement of rules for any actual games, leaving that to the human being interacting with the program I wrote. Because I had no experience making games, this meant that I would just figure out how to do things on my own regardless of whether it made sense or not.
I chose to once again work in Rust. This time I had something specific in mind with my choice of Rust, I wanted to use the Termion crate. Termion offers a really nice interface for writing interactive TTY applications.
First Challenge: Displaying a Dungeon on the Screen
Usually in Rust if you want to display a string in terminal output a println!
macro will suffice, or for error messages eprintln!
. However for a game interface you need to enter into raw mode in the terminal, and at that point you are generally using the write!
and writeln!
macros. Failure to track the differences between these two macros, and also that the ANSI escape design is one based, results in a lot of off by one errors, and I spent a lot of time fixing those.
Second Challenge: Introducing Player Movement
Player movement is managed with a hash map that contains tuples with cursor coordinates as the key, and the character at that coordinate as the value. The nice thing about this setup is that you can feed dungeons to the game as a string. However I suspect this approach would have caused me problems down the line as future development occured. As I tried to add more features to the game I really began to understand all the additional information I needed to track.
At any rate, player movement consisted of tracking the player location on the grid, and swapping the player @
symbol with the moved into location.
Third Challenge: Introducing Collision Detection
The initial collision detection that I implemented was simply for walls and doors. I created a hash set with those symbols, if the space the player tries to move into a space with a char
contained in the hash set, the move is denied. If I had implemented enemy movement and combat this would have required an extra case to handle, but in principle it would not have been any more complicated, it just would have required more items in the hash set, or even better, to invert the whole thing and have a set of valid spaces, and resolution for types that are not in the set.
Fourth Challenge: Introducing Interactions Between the Player and the Environment
Trying to add player interactions is where I ended up hitting my limit with the 7drl challenge. I created a player struct, and some methods for it. The first method I implemented was to add items to the player’s inventory. However this ended up running afoul of the borrow rules in a way that wasn’t as simple as passing a value as a reference. I look forward to fixing this problem, but it wasn’t something I really had time to address in the allotted time when I encountered it last night before going to bed.
Conclusion
As expected, I didn’t create a finished game, but I learned a lot in the process.
- I learned how to use a powerful TTY API, and how to create more powerful interfaces for the terminal
- I developed a greater appreciation for the importance of code organization for a project with the complexity of a roguelike game
- I pushed myself towards having to work with some of the more complicated parts of Rust. While working on this I was developing robust struct and implementation methods, adding traits to those structs, and using smart pointers for cases where you need to work with data whose size cannot be known at compile time.
From that perspective this exercise was a great success, although if I try this again next year I suspect I will just try to use the libtcod library so I can actually finish something.