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? ⚔

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 🎮

  • 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🔨

  1. I followed a tutorial to build a Rogulike in Python.
  2. 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 💻

Python Roguelike Tutorial Revised

In the short amount of time that I spent on development I completed the first eight steps (0 to 7) out of 13:

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:

This is a screenshot after Step 3. No combat here: only dungeon generation and movement.

Progress after Part 4:

This is a screenshot after Step 3. No combat here yet, but now have the field-of-view.

Extra functions

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.

Left: the purple spot is the trigger tile. Right: How the dungeon looked after further generation and exploration.

Connecting to Substrate chains ⛓

  1. Substrate interface; and
  2. The SCALE codec.

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(
url="wss://kusama-rpc.polkadot.io/",
address_type=2,
type_registry_preset='kusama'
)

substrate.get_chain_head()

In this example we are pulling the hash from the Kusama network.

Left: code for getting latest Kusama block hash. Right: the first room show 2 orcs and the yellow field-of-view.

… 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.

Acknowledgements 🏅

About me🎯

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?❓

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store