Country guesser game

I’ve yet again made a geograhpy quiz game on tinyappthingy.com. This time with drag and drop! Four capitals, countries and flags are displayed each round, and your job is to drag and match these together to score points. Now it can -almost- be fun to learn about which country goes with which flag.

Country guesser game

I started out displaying the flags using flag emojis / unicode. Everything looked good while developing and testing the game in Firefox. But I soon discovered that unicode flags do not work at all in other browser like Chrome. What gives? Apparently Windows 10 does not support Flag emojis. And the reason Firefox managed to display flag emojis is that they ship a built-in font. So to have this game working on all platforms I switched to flag images. I decided to not bundle the images within the app but instead rely on a CDN:

https://cdnjs.com/libraries/flag-icon-css

This works great. Images are fetched dynamically from the CDN and displayed in an img tag. However, this raised another issue with the offline functionality of the game. I’ve included a service worker and manifest to make the game installable on iOS and Android devices as an PWA. Effectively, in offline mode the game breaks since it fetches images from a CDN.

Flag emojis to the rescue! As a fallback whenever there is an error fetching the flag image I display a flag emoji. Since this is only a fallback I’ve chosen to ignore the issue this will cause on Windows 10 (except Firefox). Here’s a snippet of how I’ve implemented the fallback:

function getSvgUrl(countryCode) {
    const codePoints = countryCode
      .toLowerCase();
    const url = `https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/4.1.5/flags/4x3/${codePoints}.svg`
    return url;
}

function getFlagEmoji(countryCode) {
    const codePoints = countryCode
        .toUpperCase()
        .split('')
        .map(char =>  127397 + char.charCodeAt());
    return String.fromCodePoint(...codePoints);
}


export const MovableFlag = ({handler, countryCode}: FlagProps) => {
  const flagId = `flag-${countryCode}`;
  
  function addUnicodeFallback(ev) {
    const element = ev.target as HTMLElement;
    const parent = element.parentNode;
    parent.removeChild(element);
    const unicodeFlag = document.createElement("span");
    unicodeFlag.className = "fallback-unicode";
    unicodeFlag.innerHTML = getFlagEmoji(countryCode);
    parent.appendChild(unicodeFlag);
  }

  return (
    <div className="movable movable-flag"
    key={flagId}
    id={flagId}
    onMouseDown={e => handler.pickupMouse(e)} 
    onTouchStart={e => handler.pickupTouch(e)}>
        <img src={getSvgUrl(countryCode)} onError={addUnicodeFallback} />
    </div>
  )
};

The key here is the onError attribute that allows us to fallback to flag emojis whenever there is an error fetching the image.

I guess there might be a way to pre fill the cache using the service worker, when the PWA’s installed. But that can be for later.

Geo Quiz Game

I’ve recently been doing some web development experiments to test new stuff in the ever expanding JavaScript Ecosystem, and made a small site using Preact, TypeScript, SWC, Playwright (the list goes on) and a custom static site generator (SSG) in Webpack. This, together with the small bundle size of Preact, makes the site fast to load. And any previous knowledge about React is pretty much transferrable to Preact. Technical stuff aside, I made a game.

Geo quiz game

Not a very fun game because you have to type in the name of every country in the world to win. But if you win, you will be treated well by some CSS eye candy.

One question that quickly came up while making it, was, well, like, which territories are considered countries and which are not. Because what do you do with Niue, a self-governing state in free-association with New Zealand, do you include it the game or not? So I kind of let the UN make that decision for me, and made the default option, only UN members.

Another issue that had to be solved was guessing. Preferably you don’t want a missing the to make the guess invalid. And some countries, or territories, or whatever, do include some special characters. Special in the sense that at least I’m not very used to them. So this is what I did to “sanitize” the guesses as much as possible:

export function normalizeName(name) {
    name = name.toLowerCase();
    name = name.normalize("NFD").replace(/[\u0300-\u036f]/g, "")
    name = name.replaceAll("the", "");
    name = name.replaceAll("of", "");
    name = name.replaceAll("-", "");
    name = name.replaceAll("federated", "");
    name = name.replaceAll("states", "");
    name = name.replaceAll("saint", "st");
    name = name.replaceAll(",", "");
    name = name.replaceAll(".", "");
    name = name.replaceAll("'", "");
    name = name.replaceAll("and", "");
    name = name.replaceAll(" ", "");
    return name;
  }

Basically, I remove some words and articles, remove special characters with name.normalize("NFD").replace(/[\u0300-\u036f]/g, ""), dot, commas. It allows users to write saint, st or even st..

Example:

Saint Barthélemy -> stbarlemy
The United States of America -> `unitedamerica
The Democratic Republic of the Congo -> democraticrepubliccongo

The downside is that the Federated States of United America is accepted as The United States of America, but I can live with that.

Software Development Timesaver #7

Often nowadays on GitHub you get these Dependabot alerts, and if you’re using Node you often have a vulnerability far down the dependency hierarchy. It is not that easy to assert just from the alert alone which dependency of your project that actually depends on the vulnerable dependency in question.

Dependabot alert

There is a handy command you can use for this:

npm ls <package_name>

For example, in the case of follow-redirects you get this output that clearly shows that follow-redirects is used by webpack-dev-server in your project:

λ npm ls follow-redirects
[email protected] C:\Projects\a-project
└─┬ [email protected]
  └─┬ [email protected]
    └─┬ [email protected]
      └── [email protected]

Software Development Timesaver #6

Another timesaver for Git!

git checkout -

The command lets you checkout the previous branch you were on. Perhaps you are perusing the feature/102-description-of-feature branch, and decide to checkout to master. You can simply use the git checkout - to get back.