Adventures In Pseudorandomness

Introduction

This all started with a discord bot I was building for friends. I was thinking of neat features to add when I found someone post a “star field” in another discord server. I thought it would be fun to have a algorithm that could generate random star fields on demand. Achieving this was fairly simple but got me thinking, is it possible to force the algorithm to generate a star field from a seed value?

I need my space

First off what does one of these star fields look like?

starfield

I had to take a picture because mark down does not play nice with empty spaces. As you can see they are fairly simple with a bunch of small stars then a few emojis for planets and space ships. The trick here is to make sure the background stars spawn more often than the planets. We can achieve this with a dictionary and applying “weights” to each element we want to spawn. Then loop over the list and compare the weight to a random integer selected 1 to 100. If the weight is greater than the integer we print a star!

    stars = {':sunny:':1, ':rocket:':1, ':full_moon:':1, ':earth_americas:':1, '✦':20, ' ゚':25, '*':30, ',': 35, '.':35, '             ':80} #Elements with a higher weight will spawn more often.

    field = ''

    for y in range(6):
        for x in range(6):
            for z, q in stars.items(): #Iterate over our list of stars and space
                if q >= random.randint(0, 100): #Check if our star has spawned or not
                    field += str(z)
                else:
                    field += str('   ') #If the star did not spawn just print empty space
        field += str('\n\n\n\n\n')

Seeds And “Predictability”

Now suppose we want to create the same star field from a given seed. How do we achieve this? This is the same concept behind how minecraft world generation works. Achieving this in python is actually frustratingly simple. All we need to add to our code is the following:

random.seed(seed)

See? Told you it was easy. Here’s how it looks all put together:

import random

def space(arg=None): #Function to generate a star field

    if arg == None: #If no seed is passed to the function we will create a random one
        seed = random.randint(0, 99999999999999)
        random.seed(seed)
    else: #If a seed is passed we will use it to generate our random numbers (Which will be the same every time if this seed is used. Even across linux and windows!)
        seed = arg
        random.seed(seed)

    stars = {':sunny:':1, ':rocket:':1, ':full_moon:':1, ':earth_americas:':1, '✦':20, ' ゚':25, '*':30, ',': 35, '.':35, '             ':80}

    field = ''

    for y in range(6): #Build a 6 x 6 grid of stars. Discord has a 2000 char limit on messages D:
        for x in range(6):
            for z, q in stars.items():
                if q >= random.randint(0, 100): #All calls to random will inherit the seed we selected
                    field += str(z)
                else:
                    field += str('   ')
        field += str('\n\n\n\n\n')

    field += '\nSeed: ' + str(seed)

    print(field)


space(1220035984966)

Now every time we pass 1220035984966 to our algorithm we will get the same “random” starfield!

starfield

Thanks to https://twitter.com/tiny_star_field for the inspiration!

Full Code can be found here: https://github.com/BuckarewBanzai/Random-Star-Field

 
comments powered by Disqus