SubRogue: the build so far
tl;dr: here’s what I’ve actually coded. It ain’t much but it’s honest work.
In this blog I’ll cover what I’ve coded so far. It really isn’t much but I figure it is worth sharing anyway!
What is SubRogue? ⚔
It is a Roguelike game that connects to a blockchain. The game is only a proof-of-concept that shows the path forwards for creating more complex blockchain games. The end goal being an MMORPG on the blockchain.
I outlined the build plan in a previous blog (“SubRogue”) and I have roughly followed that. Instead of going with JavaScipt I went with Python instead since I have more experience with it.
Let’s jump into what I’ve done.
Design Goals 🎮
Just a quick reminder of what I’m aiming for. Here are the design goals:
- Rogue-like game that connects to a Substrate blockchain.
- Uses on-chain randomness for procedural generation of maps and spawning of items / enemies.
- Simple mechanics, but complex enough to be an entertaining challenge.
The build: steps to replicate🔨
At a high level, here are the two main things that I did:
- I followed a tutorial to build a Rogulike in Python.
- I integrated the Polkascan’s Python Substrate interface and SCALE codec.
The first point links to instructions for building a simple Rogulike game in Python, while the latter enables connections to a Substrate-based blockchain in order to retrieve data. What isn’t yet supported in the Polkascan library is the sending of transactions which is why development efforts are on-hold since mid-January when I tweeted out my progress:
Python Roguelike 💻
One of the best well known Python tutorials is hosted on Rogue Basin. That tutorial works for Python 2, but the author hasn’t updated it. Fortunately someone from the Roguelike dev community has created a version for Pythong 3.5+:
In the short amount of time that I spent on development I completed the first eight steps (0 to 7) out of 13:
- Part 0 — Setting Up
- Part 1 — Drawing the ‘@’ symbol and moving it around
- Part 2 — The generic Entity, the render functions, and the map
- Part 3 — Generating a dungeon
- Part 4 — Field of view
- Part 5 — Placing enemies and kicking them (harmlessly)
- Part 6 — Doing (and taking) some damage
- Part 7 — Creating the Interface
By the end of part 7 you have a playable game. The player (“@”) can explore the dungeon and kill enemies. The code also includes a field-of-view such that the player can only see a part of the dungeon at any time.
Progress after Part 3:
Progress after Part 4:
While the tutorial is a great start to building a simple and playable game, it was not designed to be a blockchain game so there are a few things that need to be coded afresh.
Determinism — the tutorial relies upon calls to in-built random function, but anti-cheating mechanisms require determinism. This required writing a simple function to take a hash and output a value within a specific range.
My solution is to (roughly) take the modulus of a hash output. This assumes the hash function produces outputs over a uniform distribution.
def hasher_range(range_min, range_max, seed):
# want to get a pseudo-random number in some range(min, max) hash_the_seed = hasher(seed) # blake2b hash to integer
modulus = range_max - range_min + 1
fn_output_pre = hash_the_seed % modulus
fn_output = fn_output_pre + range_min return fn_output
I found this code online, but it was missing the “+1" in the calculation of the modulus. Without “+1” the modulus never hits max range size, which seems wrong.
Dynamic Generation—the generation of the dungeon occurs at the start of the game and while the map is not revealed to the player, it would be easy for someone to figure this out and then see the hidden parts (cheating). To get around this, only a part of the dungeon should be generated from a single hash.
To include dynamically generated dungeons in SubRogue I created a new type of tile that triggers further dungeon generation. The tile is triggered when a player steps on it.
This piece of code is also important for building large dungeons. It doesn’t make sense to create a huge dungeon and store it in memory. See my previous blog what I’m thinking about: On Infinite Multi-User Dungeons.
Connecting to Substrate chains ⛓
There are two Python libraries that you need to import in order to get data from a Substrate chain. Both libraries are written and maintained by the Polkascan team:
This is actually the easy part. Import both libraries then include the necessary code to pull the latest block hash which is then used to seed the random generation for the dungeon.
Here’s the important piece of code I needed:
substrate = SubstrateInterface(
In this example we are pulling the hash from the Kusama network.
… and that’s what I’ve done so far.
This method of getting hashes is passive, so there is nothing that ties the player to a particular hash. This means that they can ignore any hash which does lead to favourably risks and rewards. To combat this, the hashes need to come from transactions that proof that a player retrieved a hash at a particular time. In a previous blog, I outlined a number of problems with my simple SubRogue implementation.
I may end up changing the project to JS in order to make sending transactions easier. There is better support for transactions as Parity are the ones who maintain the Substrate JS code.
I’d like to give thanks to the following people from feedback on my previous blog or for engaging in discussion about building SubRogue.
- Killari, Clement from an yet unnamed project.
- Andy and Daniel (from Xaya).
- Ronan of Ethernal World.
- Bill, Logan and Bruno (from W3F).
- Arjan Zijderveld from Polkascan.
One of the main projects of the foundation is the Polkadot network. A next generation blockchain platform. To read more about the innovation that Polkadot is bringing to the blockchain industry I invite you to read the following blog post: link.
Questions / Comments?❓
You can create a reply to me here on Medium, or reach out to me on Twitter: @EAThomson.