Skip to content

Commit

Permalink
Added typing speed test game
Browse files Browse the repository at this point in the history
  • Loading branch information
ThisIsSahaj committed Jun 10, 2024
1 parent 6a80129 commit b5ccdc3
Show file tree
Hide file tree
Showing 7 changed files with 437 additions and 0 deletions.
30 changes: 30 additions & 0 deletions Games/Typing_Speed_Test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# **Game_Name**

Typing Speed Test

<br>

## **Description 📃**
- The game shows a random quote from a famous movie/series that has to be typed in a specified time limit, as fast as possible. A higher typing speed would show a higher WPM value.


## **functionalities 🎮**
- Space: jump to next word (if the word is incomplete it will mark it as incorrect)
- Backspace: delete previous letter or jump to previous word
- Start: to generate a new quote and reset the timer to 30 seconds
- WPM: Words Per Minutes
<br>

## **How to play? 🕹️**
- Click the Start button
- A 30 timer will start counting backwards
- A random quote will be generated
- Use your keyboard to enter the quote
- A word will be counted as correct only if it is completely correct
<br>

## **Screenshots 📸**

<br>
[image](/Games/Typing_Speed_Test/assets/images/Typing_Speed_Test.png))

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions Games/Typing_Speed_Test/data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const data = [
"She did not tell them to clean up their lives, or go and sin no more. She did not tell them they were the blessed of the earth, its inheriting meek, or its glory-bound pure. She told them that the only grace they could have is the grace they could imagine. That if they could not see it, they could not have it.",


"If there is one thing Voldemort cannot understand, it is love. He didn't realize that love as powerful as your mother's for you leaves its own mark. Not a scar, no visible sign… to have been loved so deeply, even though the person who loved us is gone, will give us some protection forever. It is in your very own skin.",

"It is a curious thing, Harry, but perhaps those who are best suited to power are those who have never sought it. Those who, like you, have leadership thrust upon them, and take up the mantle because they must, and find to their own surprise that they wear it well.",

"In this world, everything is governed by balance. There's what you stand to gain and what you stand to lose. And when you think you've got nothing to lose, you become overconfident.",

"There are moments in life we should just be able to have a damn remote control, so you could pause it. Even if just for five minutes. But sometimes things happen with irreverent obscenity and there's nothing you can do to help it.",

"The bullet of an M16 shoots out at 2100 miles per hour. Faster than the speed of sound. So if they shot you in the heart, you won't even hear the bullet that killed you.",

"We've always defined ourselves by the ability to overcome the impossible. And we count these moments. These moments when we dare to aim higher, to break barriers, to reach for the stars, to make the unknown known. We count these moments as our proudest achievements. But we lost all that.",

"When I was a kid, it seemed like they made something new every day. Some, gadget or idea, like every day was Christmas. But 6 billion people, just imagine that. And every last one of them trying to have it all. This world isn't so bad.",

"Sometimes, you read a book and it fills you with this weird evangelical zeal, and you become convinced that the shattered world will never be put back together unless and until all living humans read the book.",

"It's estimated that human beings only use 10% of their brain's capacity. Imagine if we could access 100%. Interesting things begin to happen. With all this knowledge, you could unlock secrets that go beyond out limiters. I'm not even sure that mankind is ready for it."
];
44 changes: 44 additions & 0 deletions Games/Typing_Speed_Test/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Typing Speed</title>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" />
</head>
<body tabindex="0">
<!-- using tabindex so that we can use body.focus() -->
<h1>Test your <span style="color: orchid;"> Typing </span> <i>Speed</i> </h1>

<div class="game">
<div class="words"></div>
<div class="cursor"></div>
</div>

<div class="info">
<button>Start Game</button>
<div class="timer">30</div>
<div class="result"></div>
</div>
<div class="rules">
<h3>Rules</h3>
<p>1) Once game starts you will get 30 seconds to write the given sentence</p>
<br>
<p>2) A word will be counted as correct only if it is completely correct</p>
<br>
<p>3) If you press space, it will skip to the next word (if the word is incomplete it will mark it as incorrect)</p>
<br>
<p>4) Backspace doesn't work on long press, you need to press it for each word</p>
</div>
<div style="text-align: center;
font-size: 30px;
padding: 5px; "><a href="https://kunjgit.github.io/GameZone/"><i style="color:orchid;" class="fas fa-home home-icon"></i></a></div>
</div>
</body>
<script src="data.js"></script>
<script src="script.js"></script>
</html>


228 changes: 228 additions & 0 deletions Games/Typing_Speed_Test/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
const wordsDiv = document.querySelector('.words');
const body = document.querySelector('body');
const cursor = document.querySelector('.cursor');
const button = document.querySelector('button');
const timer = document.querySelector('.timer');
const result = document.querySelector('.result');
const gameTime = 30 * 1000;


// format each letter of a word
const formatWord = (word) => {
return `
<div class="singleWord"><span class="letter">${word.split('').join('</span><span class="letter">')}</span></div>
`
}

let addClass = (element, className) => {
element.className += ' ' + className;
}

let removeClass = (element, className) => {
element.className = element.className.replace(className, '');
}


const newGame = () => {

// get a paragraph from the data
const words = `${data[Math.floor(Math.random() * data.length)]}`

// to split all the words whenever space comes and return an array
const newWords = words.split(" ");

wordsDiv.innerHTML = " ";
let counter = 30;
result.innerHTML = '';



newWords.forEach(element => {
wordsDiv.innerHTML += formatWord(element);
});


const singleWord = document.querySelector('.singleWord');
const letter = document.querySelector('.letter');

addClass(singleWord, 'current');
addClass(letter, 'current');

const firstLetter = document.querySelector('.letter.current');
cursor.style.top = firstLetter.getBoundingClientRect().top + 'px';
cursor.style.left = firstLetter.getBoundingClientRect().left + 'px';

let countdownTimer = setInterval(() => {
counter--;
timer.textContent = counter;

if (counter < 0) {
clearInterval(countdownTimer);
timer.textContent = "Time's up!";
}
}, 1000);

setTimeout(() => {
gameOver();
}, gameTime);


// to focus on body, because it is focusing on the button
body.focus();

}


const gameOver = () => {
alert("Time's Up!");
timer.innerHTML = `GAME OVER!`
result.innerHTML = `Your WPM: ${getWpm()}`;
}


const getWpm = () => {

const words = [...document.querySelectorAll('.singleWord')];

const lastTypedWord = document.querySelector('.singleWord.current'); // the current element where game stopped
const lastTypedWordIndex = words.indexOf(lastTypedWord);

const typedWords = words.slice(0, lastTypedWordIndex);


// to get all the words inside the typedWords array
const correctWords = typedWords.filter(word => {

//get all letters in each word and make an array
const letters = [...word.children];
const incorrectLetters = letters.filter(curletter => curletter.className.includes('incorrect'));
const correctLetters = letters.filter(curletter => curletter.className.includes('correct'));


return incorrectLetters.length === 0 && correctLetters.length === letters.length;
});


return correctWords.length / gameTime * 60000;
}


const handleSpace = (expected, currentWord, currentLetter) => {
if (expected !== ' ') {
const lettersToInvalidate = [...document.querySelectorAll('.singleWord.current .letter:not(.correct)')];
lettersToInvalidate.forEach(letter => {
addClass(letter, 'incorrect');
});
}
removeClass(currentWord, 'current');
addClass(currentWord.nextElementSibling, 'current');

if (currentLetter) {
removeClass(currentLetter, 'current');
}
addClass(currentWord.nextElementSibling.firstChild, 'current')
}


const handleBackspace = (currentLetter, isFirstLetter, currentWord) => {
// if backspace at start of next word
if (currentLetter && isFirstLetter) {
// make previous word current
removeClass(currentWord, 'current');
addClass(currentWord.previousElementSibling, 'current');

// make last letter current
removeClass(currentLetter, 'current');
addClass(currentWord.previousElementSibling.lastChild, 'current');

removeClass(currentWord.previousElementSibling.lastChild, 'incorrect');
removeClass(currentWord.previousElementSibling.lastChild, 'correct');
}

// if backspace in middle of a word
if (currentLetter && !isFirstLetter) {
removeClass(currentLetter, 'current');
addClass(currentLetter.previousElementSibling, 'current');

removeClass(currentLetter.previousElementSibling, 'incorrect');
removeClass(currentLetter.previousElementSibling, 'correct');

}

// if backspace at the end of a word
if (!currentLetter) //therefore expected = space
{
addClass(currentWord.lastChild, 'current');
removeClass(currentWord.lastChild, 'incorrect');
removeClass(currentWord.lastChild, 'correct');
}
}


const moveCursor = () => {
const nextLetter = document.querySelector('.letter.current');
const nextWord = document.querySelector('.singleWord.current');

if (nextLetter) {
cursor.style.top = nextLetter.getBoundingClientRect().top + 'px';
cursor.style.left = nextLetter.getBoundingClientRect().left + 'px';
}
//if next is space
else {
cursor.style.top = nextWord.getBoundingClientRect().top + 7 + 'px';
cursor.style.left = nextWord.getBoundingClientRect().right + 'px';
}
}


body.addEventListener('keyup', ev => {
const key = ev.key;
const currentWord = document.querySelector('.singleWord.current');
const currentLetter = document.querySelector('.letter.current');

//if no currentLetter, then expected key will be space
const expected = currentLetter?.innerHTML || ' ';


//check whether the input is a letter or not
//if it's length is not equal to 1, it means it is 'Backspace'
//if key is empty ' ' it means it is the space key
const isLetter = key.length === 1 && key !== ' ';
const isSpace = key === ' ';
const isBackSpace = key === 'Backspace';
const isFirstLetter = currentLetter === currentWord.firstChild;




if (isLetter) {
if (currentLetter) {
addClass(currentLetter, key === expected ? 'correct' : 'incorrect');
removeClass(currentLetter, 'current');
if (currentLetter.nextSibling) {
addClass(currentLetter.nextSibling, 'current');
}
}
}

// if key is SPACE
if (isSpace) {
handleSpace(expected, currentWord, currentLetter);
}

// if key is BACKSPACE
if (isBackSpace) {
handleBackspace(currentLetter, isFirstLetter, currentWord);
}


// move cursor
moveCursor();


})


button.addEventListener('click', newGame);


Loading

0 comments on commit b5ccdc3

Please sign in to comment.