Contents

Build a number guessing game with R and Shiny

Contents

This may feel like wordle for numbers but it is called Bulls and Cows. This is a game I played 20 years ago on a black and white LCD screen that looks like the one below. Give it a try and see if you could get on the leaderboard here.

Background

In the early 2000s, my cousin showed me this game on his digital dictionary, which was a thing back then. I got hooked as a kid, and now I am trying to build a similar game with Shiny.

How to play

  1. Click on the information button to view the instructions.

  1. Start with a level and start with guesses.

Goal: Guess an x-digit number with no repeating number from 0-9 using the least number of guesses.

After you put in your first guess, you will see:

  • n A: n out of x digits is correct and in the correct position.
  • n B: n out of x digits is correct but in the incorrect position.

For example, if the number is 1203 when you guessed 1234, the result will show 2A1B, with 1 and 2 being the right numbers in the correct position and 3 being one of the 4 numbers but in the incorrect position.

See guesses in action.

  1. After you guess the number correctly, you will see a congratulation pop-up.

  1. You can choose to save your record and it may see yourself on the leaderboard if the number of guesses you used is the top 10 least guesses used for that level.

Building the Game with Shiny

The game logic was first written as R code that runs in the Console. In 2020, I moved it to a shiny app but never completed the final touch on the UI or handling the special cases to improve the user experience.

On May 10th, I came across a snippet of a live presentation on developing a number guessing game with shiny by @schloerke and @kierisi and it reminded me of this project I had put on hold.

Although I already had a working game on Shiny and thought it only needed a few final touches, I have identified about 21 small features around the general UI, functionalities, and user experience. With the urge to launch the game as soon as I can, I was able to complete 18 features and launched it on May 12th.

Lessons learned

From working on the ‘final touches’ to launching the app. There were a lot of unexpected learning along the way.

lesson 1: the leaderboard display.

I used the reactable package for this. My goal was to add medals to only the top three entries on the table and leave no medals to other entries. However, this turns out to require a customized function for the colDef() as reactable requires emoji/pic for every row.

lesson 2: the pop-up intro from the information button.

I used the rintrojs package. This is a very cool package to use but the only hiccup was that you need to identify the elements with their class, not their id. The SO post explained this very well.

lesson 3: the reactive feedback from user input.

I used the shinyFeedback package. The package is straightforward to use but the use case created a few headaches. I would like to inform the user that each digit should be different and use should put in the specific digit for different levels.

With that said, I will need to have corresponding feedback for different levels. Also, I would not want to evaluate the input until the user is ready to guess. This is where a mind map of reactives could help. I ended up spending over 1-hour testing different scenarios and came to the final completed version.

lesson 4: explanation of the rules.

I have known the rules by heart for years and I did not remember reading any instructions from the original game. Therefore, it would not be a good idea for me to say if the instructions are clear. For that, my recommendation was to ask someone who hasn’t planned this game before to test and that is what I did. (If you find the current instructions hard to understand, think about the version before.)

lesson 5: The leaderboard data storage.

This was a hard lesson learned after the app is launched. I was very excited to see other people on the leaderboard after posting the app to Twitter. A few hours later, I somehow fat-fingered to restart an instance on shiny.io and the app cleared every new record!

The previous set up was that user will be able to save their record in a csv file in the app’s directory. I thought the reason was that I launched a new instance and messed it up and I realized that the app only allowed 1 person to play it at a time. So after fixing the concurrent players issue with promises I relaunched the app and thought everything will be fine now with my Ross Hanneman reference, hoping this was the end of it. But it was not, the new records disappeared again!!

After going through a good 10 mins of denial, I started digging into this issue, and guess what, this has been covered in the shiny.io manual. screenshot from shiny.io user guide

Upon going through the Persistent storage with Shiny article. I went with the googlesheets4 package to store leaderboard data on a Google sheet.

Lastly

Building the number guessing game with R and Shiny was fun and rewarding. There was lots of gotcha’s and learning along the way, even with a rather straightforward logic. I can’t imagine how much work there is to build a video game in general. Nevertheless, go play the game here. I would love to see new names on the leaderboard.