DEV Community

Cover image for I introduced the word guessing game in my vocabulary app
Emtiaj Hasan
Emtiaj Hasan

Posted on

I introduced the word guessing game in my vocabulary app

A few years ago, I published a vocabulary-learning assistance app. Imagine you found an unknown word, you just googled it to find its meaning and continued what you were doing. However, what if you wanted to memorize it so that you can use it in future?

That is what my app can help. This app lets you create your own dictionary, make a vocabulary to a flashcard, and go through the process of the Leitner System aka spaced repetition, so that you can learn it effectively. Not only this, but you can also create a group and build and learn collaboratively.

Check it out on Android App or access the Web App. It is also a Progressive Web App (PWA) i.e., it can be installed on iOS giving you a native experience.

Exciting New Feature: Word Guessing Game!

After a few weeks of hard work, I'm thrilled to introduce a new version of the app featuring a word guessing game! In this exciting update, users are presented with a series of meanings and must guess the correct word for each one. Every day, a new game is generated to challenge vocabulary skills. With every correct guess, the score increases. Plus, if all the words are guessed correctly, an additional game can be unlocked to play on the same day.

For the tech-savvy, here are the back-end and front-end pull requests.

The Journey

The biggest challenge was to generate meanings randomly from the user-created vocabulary list. Fortunately, Postgres has a feature to select rows randomly. And guess what? I used it!

select meaning
from "Definition"
        tablesample bernoulli (10);
Enter fullscreen mode Exit fullscreen mode

I had to apply proper filtering to get meanings belonging to the user cohort. But, as using the Bernoulli sampling, Postgres generates data randomly, and I don’t want to show the last fifteen days’ meanings to the user, I needed to do a tweak.

The idea is pretty simple. Generate using the Bernoulli sampling but the final result should skip previously selected meanings. It can be easily achieved to store the current selection to a cache service, and the query needs a bit of adjustment to filter out those.

Redis Alternative

I do not have the luxury of using Redis as you know, I wanted to avoid extra expenditure. And, Postgres rescued again!

Postgres has a concept of UNLOGGED table, in which data is not written to WAL, long story short, kinda Redis-like feature. Therefore, I created an UNLOGGED table to store a user’s last fifteen days guessing game-related data.

The final query looks like this.

Remove Old Data

If you notice the query to fetch data from the GuessingGame table to feed into another query mentioned above, you will see there is no time-related filtering. It looks like if a meaning is shown to a user, it will never be displayed to that user. But, my requirement was to avoid showing only the last fifteen days.

But, it works fine. Because, I created a cron job, which runs every hour to delete rows older than 15 days. In this way, I ensure to keep only fifteen days of older data in the GuessingGame table.

A Bit of an Extra Challenge

So far, a user gets meanings from his/her dictionary. To make the game more challenging, I fetch meaning from an external source. WordsApi has a cool collection of vocabulary and they have an API to fetch words randomly.

Now, every day, a user can get meanings from his own dictionary as well as from a different source, which makes it more enjoyable and challenging.

Front-end Implementation

Well, I wrote some codes to fetch data and feed those data to the SwiperJS so that the user can navigate to each card smoothly.

Guessing Game Showcasing

For each correct guess, a satisfactory sound gets played and a simple animation increases the count.

Despite my self-confessed lack of UI design skills, I'm proud of how these features turned out!

Here are codes to apply animation!

@keyframes bounce {
   0%,
   20%,
   50%,
   80%,
   100% {
       transform: translateY(0);
   }
   40% {
       transform: translateY(-30px);
   }
   60% {
       transform: translateY(-15px);
   }
}


.animate-count {
   display: inline-block;
   animation: bounce 1s ease-out;
}
Enter fullscreen mode Exit fullscreen mode
animateCount(index: number): void {
   const element = document.getElementsByClassName('correct-count')[index];
   element.classList.add('animate-count');
   element.addEventListener(
       'animationend',
       () => {
           element.classList.remove('animate-count');
       },
       { once: true },
   );
},
Enter fullscreen mode Exit fullscreen mode

I can keep going to share every detail, but let’s finish it. I hope you will enjoy the new features! Don’t forget to leave a review in the Play Store! Happy learning!

Top comments (0)