Skip to main content

Command Palette

Search for a command to run...

Add Database to Display Highscore in CLI quiz App

Published
•6 min read•View as Markdown
Add Database to Display Highscore in CLI quiz App
A

Final year undergrad @KLE technological university, Intern @Deevia softwares, Neog'22

I created 2 CLI Quiz app while doing the Level0 course of neogcamp. After finishing the course I was curious, what if I add a database to a CLI app and store username and their score to display Top 5 high scores.

I'm also pretty new to using databases so I just used a JSON file.

If you are new to the database concepts like me then a database is nothing but a simple file where data is stored and we can access it whenever we want(we are storing data to a file that follows JSON format)

Let's start with creating a function that updates username, score and also displays Top 5 high scores.

const updateAndShowHighScore = (score, userName) => {
  //read the Json File

  //Update it 

  //Display Top 5
}

To read a file I'm using an inbuilt Node package called fs short for the File system. We will read the file Synchronously i.e. code will not execute next line until the whole JSON file is read.

Node packages are a set of functions that someone has written and you can use them instead of creating functions from scratch.

const fs = require('fs') //inbuilt in node so no npm install 
const updateAndShowHighScore = (score, userName) => {
  //read the Json File
  let data = fs.readFileSync('name of the file');
  console.log(data);
  //Update it 

  //Display Top 5
}

//In the console we get:
//<Buffer 5b 0a 20 20 7b 0a 20 20 20 20 22 6e .....bytes>

readFileSync doesn't automatically give us JSON, it just gives us raw data. So now we have to parse the data and convert it to JSON format( Read More )

const fs = require('fs') //inbuilt in node so no npm install 
const updateAndShowHighScore = (score, userName) => {
  //read the Json File
  let data = fs.readFileSync('name of the file');
  let dataJson = JSON.parse(data)
  console.log(dataJson);
  //Update it 

  //Display Top 5
}
//In the console we get:
[
 {
   "name":"Temp Person", //for example
   "score":4
 }
]//This is what is saved in the JSON file

The next step is to update the JSON file with username and score. First, we will push an object which has a name and score and then will write it to a JSON file. For push to work, we need to declare an empty array in the JSON file.

//JSON file 
[]
const fs = require('fs') //inbuilt in node so no npm install 
const updateAndShowHighScore = (score, userName) => {
  //read the Json File
  let data = fs.readFileSync('name of the file');
  let dataJson = JSON.parse(data)
  console.log(dataJson);
  //Update it 
  dataJson.push({
       "name":userName,
       "score": score
    })
  fs.writeFileSync('JSON file name',dataJson,/*option to replace data*/null,/*white spaces*/1)
  //Display Top 5
}

In "writeFile" also we are using Sync so that the Top 5 high scores should not be calculated before the user data is written to the JSON File. Let's see what is added to the JSON file(Whenever there is an API call after fs.writeFile or fs.readFile then it's better we do it asynchronously )

//JSON file
[object object]

Imagine a world where programming language understands what we are doing and does just that, 😔humanity is not there yet, Ya but why did we get [object object] while we should have gotten an array with the first element as an object with user data

Hmm, what's wrong🤔?

The problem is [object Object] is the default string representation of an object. As fs.writeFileSync accepts only strings we have to convert the object into a JSON string( Read More )

const fs = require('fs') //inbuilt in node so no npm install 
const updateAndShowHighScore = (score, userName) => {
  //read the Json File
  let data = fs.readFileSync('name of the file');
  let dataJson = JSON.parse(data)
  console.log(dataJson);
  //Update it 
  dataJson.push({
       "name":userName,
       "score": score
    })
  let stringDataJson = JSON.stringify(dataJson)
  fs.writeFileSync('JSON file name',stringDataJson ,/*option to replace data*/null,/*white spaces*/1)
  //Display Top 5
}

Now we have successfully read and updated the JSON file. The last step would be to display high scores. The logic for this would look like this:

//create a copy of JSON file data
for(let i=0;i<5;i++){
  //find a candidate who has highscore

  //Display the candidate 

  //Delete that candidate from the copied array so that the next maximum scored candidate is chosen to display 
}

One of the logic involves deleting the high scored candidate information, for that reason we cannot use the original array i.e. dataJson, let's clone it.

let tempDataJson = [...dataJson];

Here I'm using a spread operator to clone the array( Read more about why I did not use = operator ).

Now we have to find a candidate who has a high score for that we will create a variable named maxScore and assign the first elements score to it.

We will use another for loop wherein if any other candidate score is more than maxScore then we will assign maxScore to that candidate score.

5218331.jpg

So you see at the end of the loop we get the highest score. We will also create a variable that stores the index of the highest score candidate so that we can display the candidate info later.

for (let i = 0; i < 5; i++) {
  let maxScore = tempDataJson[0].score;
  for (let j = 0; j < tempDataJson.length; j++) {
    //find max score candidate
    if (tempDataJson[j].score > max) {
      maxScore = tempDataJson[j].score;
      maxElementIndex = j;
    } else {
      maxScore = maxScore;
    }
  }
  //display candidate information
  console.log(
    `High Score Rank ${i + 1}: ${
      tempDataJson[maxElementIndex].name
    } with score ${tempDataJson[maxElementIndex].score}`
  );
  tempDataJson.splice(maxElementIndex, 1);
}
  1. we need top 5 high score holders so i < 5
  2. tempDataJson.splice(maxElementIndex, 1) means to remove the 1 element at index = maxElementIndex

Now if I run this code, the output would be displaying one candidate information and the rest would be logged as undefined

why?

Because the quiz is played only once and we have only information of one candidate, so to avoid undefined we will handle it with some if-else statements.Like this:

if (tempDataJson < 5) {
  for (let i = 0; i < tempDataJson.length; i++) {
    let maxScore = tempDataJson[0].score;
    for (let j = 0; j < tempDataJson.length; j++) {
      if (tempDataJson[j].score > max) {
        maxScore = tempDataJson[j].score;
        maxElementIndex = j;
      } else {
        maxScore = maxScore;
      }
    }
    console.log(
      `High Score Rank ${i + 1}: ${
        tempDataJson[maxElementIndex].name
      } with score ${tempDataJson[maxElementIndex].score}`
    );
    tempDataJson.splice(maxElementIndex, 1);
  }
} else {
  for (let i = 0; i < 5; i++) {
    let maxScore = tempDataJson[0].score;
    for (let j = 0; j < tempDataJson.length; j++) {
      if (tempDataJson[j].score > max) {
        maxScore = tempDataJson[j].score;
        maxElementIndex = j;
      } else {
        maxScore = maxScore;
      }
    }
    console.log(
      `High Score Rank ${i + 1}: ${
        tempDataJson[maxElementIndex].name
      } with score ${tempDataJson[maxElementIndex].score}`
    );
    tempDataJson.splice(maxElementIndex, 1);
  }
}

Here is the link to my Avatar the last air-bender Quiz where I have implemented this. Link

If your attention has permitted you to stay till here then Thank you. Follow me before you forget that you liked this article, goodbye:)

Credits

  1. Nested loop Meme - Link
  2. Work vector created by stories - www.freepik.com
  3. Technology vector created by stories - www.freepik.com