Resurecting pokeguess.trickey.solutions
Several years ago I built a pokemon guessing game for my daughter, The project was a chance for me to learn a little bit about cloudflare workers, This is a blog post about me revisiting that first workers project.
You can play the game here.
I hope the game is fairly self explanatory. When the page loads you should be presented with a that has an obscured rectangle, that rectangle is hiding an image of a randomly selected pokemon. You can choose to reveal up to 3 sections of the image before staking your guess.
If the image alone is not enough, you can also get a hint which will reveal the "Type" that the pokemon belongs to
The game is crude, basic and my some what lacking front end skills mean it's not exactly pretty! However I still use it as a demonstration of how we can nicely harnesses some neat concepts and abilitys that make cloudflare workers so cool for generatingdynamic, customised responses as quicklky as if you were loading something static from the cache.
I could have put all the display logic in the client side and called back to an api for data about the pokemon, maybe one day, I'll covnert it to react instead /shrug.
For now it runs as a stand alone cloudflare worker script, and I think it still does a neat job of demonstrating an application doing things "server side" but in totally serverless way!
Picking the poke #
At the time of creation there were up to 807 pokemon,
so the first thing our worker code does is randomly select a pokemon to use for this round - simple JS. (Math.random() * 807)
we also need that number to be formated in a consistant way so that it's always three didgets so we also have some lpad going on too.
function pickRandomPokemon() {
return Number(lpad(Math.floor((Math.random() * 807) + 1),3));
}
Getting the data #
Now that we have the ID of the pokemon we are going to use, we now need to get the data about this sepcific pokemon.
This high level data we hold about pokemon will change very rarely, but we expect to reading data a lot (everytime somebody plays a round of the game)
This means that cloudflare KV (Key Vale) cache is an ideal candidate for this kind of data as it harnesses cloudflares globably distributed cache so will have minimal latency for the worker to be get the data it needs to start preparing the experience. In preperation for this i have created a KV namespace called POKEKV
and populated it with data about each pokemon. The script used to populate the KV store can be found in this related post...
By binding our worker to the POKEKV namespace, we can now add a binding to rapidly access the data about our pokemoon.
async function getPokeDetailsFromKv(pokeId)
{
var pokepromise = POKEKV.get(`Poke${pokeId} `)
var pokedetails = await pokepromise
return(JSON.parse(pokedetails))
}
Shuffling options #
When we generate the game, we are going to present he player with 3 options to guess from 1 which is the correct answer and three that are incorrect. As such our wokrer is also going to need to be able to shuffle an array to make sure the three otions are always presented in a random order, this is the simple shuffle function that was used
function shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
Displaying the images #
The visual heart of this game is the images that are used to illustrate the pokemon being guessed at
The images I have used in this demo game are all sourced from a public pokemon CDN - this is a post about how the content was downloaded using a simple powershell script
The images are then uploaded to some static asset storage, which is it's self a cloudflare pages project that you can learn more about here.
n.b. For more advanced use cases, cloudflare does have an image optimization product suite that you can explore.
with the images in our pre-prepared asset store, our html just needs to alter the file name for use with the ID of the pokemon e.g for Charmeleon (005) our html just has to reference this image source https://assets.trickey.solutions/pokeassets/005.png
Generating dynamic HTML at the edge #
The players experience of the game is from the html, js and css generated and delivered to the device.
The server side logic takes a base html template (soted as string variabe in the worker script) and then does a .toString().replace()
comand to subsititue out placeholders with our dynamically generated values
html.toString().replace(/(PLACEHOLDTEXT)/g,dynamicValue))
I'm limiting the details of how the find and replace was applied because I think that if i was redoing this from scratch again now, I would use the html re-writer api
The key thing to take away is that workers give us an ability to run server side logic, obtain data from caches and generate dynamic html documents really really really fast, and with litterally no infrastructure consideration