DEV Community

Pascal Dennerly
Pascal Dennerly

Posted on • Originally published at skillscheck.co.uk on

Gostars - Creating Star Names

#go

When we want to create a new Gostars game, we want to enter the minimum of parameters. Specifically, we want to create a game by setting the size of the universe and density of stars but not the names of individual stars.

So how do we generate readable names from scratch?

Generating the names

Random strings

Let’s try creating totally random strings. Start with 26 letters and pick them at random until you get bored. Here’s some code that will do just that, select letters at random for random sized words. Give it a go here.

Here’s some words that I generated:

Pthc
Dnlbn
Ugfb
Vndmm
Ikvji
Leafd
Krxpzaelp
Ldwnps
Pmcnaxr
Rcucryh

These do certainly look alien, maybe a little too much! Leafd and Krxpzaelp look decent enough but I don’t know that I can pronounce any of the rest. This doesn’t seem friendly for our players.

Random phonemes

What if we could generate English sounding words by picking random ‘sounds’. By this I mean graphemes. Great idea, let’s try that - but it is a pain finding a complete list of graphemes! After a lot of looking I eventually found that the best resource is this.

The next tool to use does something similar to selecting random letters. Given a set of graphemes, select random ones a random number of times. The code to do this is here. You’ll need to supply a data file containing a grapheme on each line. Run it like this:

go run graphemetxt.go -source data.txt

Let’s take a look at what kind of names are generated:

guskngcklff
nbquwhcggrch
lkghged
seghssghcc
btgufflkghst
rgschdpn
jzgzwhsssfgh
lfzzrpsggguked
sejscftbbgezfpn
gueuthss

I’m not sure that’s any better.

Markov generator

Here we’ll break out the big guns. Markov chains look at an existing body of data and randomly select the next ‘state’ based on its probability of following the current one. In our case, each letter will be a state.

A quick search of the internet revealed a handy little library that will help us out here. Here is a program that will read in a data file with a new name per line to build a model of how names are constructed. To use it, type the following in to the command line:

go run tools/textgen/textgen.go -source <your data file>

We need some source data to seed the Markov Chain. For this I did a search for place names in the UK, I chose a list of English nouns and place names (counties and towns). As long as the place names are 1 per line, this will server as our data.

You can set the number of words with the words parameter. There is another parameter too, the ‘prefix’. This is used to set how far ‘back’ back in the chain the algorithm looks when deciding what letter (state) to pick next. I’m still learning how this affects the output but using 2 gave some interesting output:

Implain-landear
Adamod
Mouningendroold
Anchal
Olelughtemplail
Ariabervaging
Hdrack
Entivult
Rimbe
Usholynx

That’s much better! Quite alien but somehow readable.

Some interesting features of this tool are:

  • When we meet a newline, it’s the end of the word so pick a new location in the chain
  • We filter out the original words by adding them to a set of known words
  • Duplicate words are removed by only storing them in our set too

Using map keys will work very well for a set.

Deploying the names

Now we have a large list of names, how do we get them in to our game? So this is where we take advantage of the fact that we’re usingBuffalo. It icludes a tool, packr, that allows you to embed static resources in to the binary that you produce with buffalo build. So first of all, we need to produce a list of names (you can find them here). So how do we make them available to the program?

Let’s start with how we will use the names when we need them. The first version of cut of Gostars created new stars when you created the game. When a client does a POST against /games, the handler looks at the size and star density of the universe defined in the request fields and generates a random number of stars at random positions.When we generate the star, we need to look ip a name from our list, preferably randomly. Otherwise every game would have the same star names. How do we solve this? Well, it turns out that Go has a solution to this. When you range over map keys, Go will present them in a random order. To simplify our code as much as possible, I’m thinking we need to provide a type that will let us get an arbitrary number of these names from the map keys. Take a look at names.go for a type that will do this.

The next question is, how do we populate our nameList?When you are writing a Buffalo application, you don’t jump in to main, you entry point as a developer is actions.App(). This is where all the initialisation of resources happens. We need to create a package variable of type nameList and instantiated it in App(), passing in a string with all of the data in the file we created earlier. To do this, we create use a packr.Box that refers to the data directory in our repo. When we run buffalo build, the packr tool will scan the source code and detect where we call packr.NewBox(...) and store the contents of this directory as data in the binary.To access files in this directory, we need to look them up in the box that they are stored in. For our star names, we just look up starnames.txt from the box and pass this string to our nameList.

When we create the stars, we have access to the static data generated by our Markov Chain tool and can draw on them quickly when we need them.

I hope this is useful.

Top comments (0)