Skip to content

Commit

Permalink
Merge pull request #4918 from sanayamahajan-23/Typing_Test
Browse files Browse the repository at this point in the history
add the typing-test game
  • Loading branch information
kunjgit authored Jul 28, 2024
2 parents f64e004 + d405d64 commit e89e2fb
Show file tree
Hide file tree
Showing 7 changed files with 688 additions and 48 deletions.
30 changes: 30 additions & 0 deletions Games/Typing_Test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# **Game_Name**

Typing Test

<br>

## **Description 📃**
- The game shows a random paragrapn 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: deletes the letter
- Try Again
- WPM: Words Per Minutes
<br>

## **How to play? 🕹️**
- Start typing
- A 60 timer will start counting backwards
- A random paragraph will be generated if clicked on try again
- Use your keyboard to enter characters.
- A word will be counted as correct only if it is completely correct
<br>

## **Screenshots 📸**

<br>
![image](../../assets/images/Typing_Test.png)

44 changes: 44 additions & 0 deletions Games/Typing_Test/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Typing Test</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<input type="text" class="input">
<div class="box">
<div class="text">
<p>I inadvertently went to See's Candy last week (I was in the mall looking for phone repair), and as it turns out, See's Candy now charges a dollar -- a full dollar -- for even the simplest of their wee confection offerings. I bought two chocolate lollipops and two chocolate-caramel-almond things. The total cost was four-something. I mean, the candies were tasty and all, but let's be real: A Snickers bar is fifty cents. After this dollar-per-candy revelation, I may not find myself wandering dreamily back into a See's Candy any time soon.
I've rented a car in Las Vegas and have reserved a hotel in Twentynine Palms which is just north of Joshua Tree. We'll drive from Las Vegas through Mojave National Preserve and possibly do a short hike on our way down. Then spend all day on Monday at Joshua Tree. We can decide the next morning if we want to do more in Joshua Tree or Mojave before we head back.
</p>
</div>
<div class="content">
<ul class="result">
<li class="time">
<p>Time Left:</p>
<span><b>60</b>s</span>
</li>
<li class="mistake">
<p>Mistakes:</p>
<span>0</span>
</li>
<li class="wpm">
<p>WPM:</p>
<span>0</span>
</li>
<li class="cpm">
<p>CPM:</p>
<span>0</span>
</li>
</ul>
<button>Try Again</button>
</div>
</div>
</div>
<script src="js/paragraph.js"></script>
<script src="js/script.js"></script>
</body>
</html>
22 changes: 22 additions & 0 deletions Games/Typing_Test/js/paragraph.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

99 changes: 99 additions & 0 deletions Games/Typing_Test/js/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// script.js

const typingText = document.querySelector(".text p");
const field = document.querySelector(".container .input");
const timeTag = document.querySelector(".time span b");
const mistakeTag = document.querySelector(".mistake span");
const cpmTag = document.querySelector(".cpm span");
const wpmTag = document.querySelector(".wpm span");
const tryAgain = document.querySelector("button");
let charIndex = 0;
let mistakes = 0;
let isTyping = false;
let timer;
let maxTime = 60;
let timeLeft = maxTime;

function randomParagraph() {
let randIndex = Math.floor(Math.random() * paragraphs.length); // Get a random paragraph
typingText.innerHTML = ""; // Clear previous paragraph

paragraphs[randIndex].split("").forEach(span => {
let spanTag = `<span>${span}</span>`;
typingText.innerHTML += spanTag;
});
typingText.querySelectorAll("span")[0].classList.add("active");
// Focusing input field on keydown or click event
document.addEventListener("keydown", () => field.focus());
typingText.addEventListener("click", () => field.focus());
}

function initTyping() {
const characters = typingText.querySelectorAll("span");
let typedChar = field.value.split("")[charIndex];
if(charIndex<characters.length -1 && timeLeft > 0 ){
if (!isTyping) {
timer = setInterval(initTimer, 1000);
isTyping = true;
}

if (typedChar == null) { // If typed character is null or presses backspace
if (charIndex > 0) {
charIndex--;
if (characters[charIndex].classList.contains("incorrect")) {
mistakes--; // Decrements mistakes only if class is incorrect
}
characters[charIndex].classList.remove("correct", "incorrect");
}
} else {
if (characters[charIndex].innerText === typedChar) {
// If user types character correctly then class becomes correct otherwise incorrect with mistakes incremented
characters[charIndex].classList.add("correct");
} else {
mistakes++;
characters[charIndex].classList.add("incorrect");
}
charIndex++;
}

characters.forEach(span => span.classList.remove("active"));
if (charIndex < characters.length) {
characters[charIndex].classList.add("active");
}
let wpm = Math.round((((charIndex-mistakes)/5)/(maxTime-timeLeft)) * 60);
//if wpm value is less than 0,empty or infinity then setting its value to 0
wpm=wpm<0 || !wpm || wpm === Infinity ? 0: wpm;
wpmTag.innerText=wpm;
mistakeTag.innerText = mistakes;
cpmTag.innerText = charIndex - mistakes;
}else{

clearInterval(timer);
}
}

function initTimer() {
if (timeLeft > 0) {
timeLeft--;
timeTag.innerText = timeLeft;
} else {
clearInterval(timer);
field.disabled = true; // Optional: Disable input when time runs out
alert("Time's up!");
}
}
function reset()
{
randomParagraph();
field.value="";
clearInterval(timer);
timeLeft=maxTime;
charIndex=mistakes=isTyping =0;
timeTag.innerText = timeLeft;
wpmTag.innerText=0;
mistakeTag.innerText =mistakes;
cpmTag.innerText = 0;
}
randomParagraph();
field.addEventListener("input", initTyping);
tryAgain.addEventListener("click", reset);
125 changes: 125 additions & 0 deletions Games/Typing_Test/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap');
*{
margin:0;
padding:0;
box-sizing:border-box;
font-family:'Poppins',sans-serif;
}
body{
display:flex;
align-items:center;
justify-content:center;
min-height: 100vh;
background: #c4c4ff;
}
.container{
width:770px;
background:#e6e6fa;
padding:35px;
border-radius: 10px;
}
.container .input{
z-index: -999;
opacity: 0;
position:absolute;
}
.container .box{
padding:13px 20px 0;
border-radius:10px;
border: 1px solid #ccc;
}
.box .text{
max-height:255px;
overflow-y:auto;
}
.text::-webkit-scrollbar{
width:0;
}
.text p{
font-size:21px;
text-align:justify;
letter-spacing:1px;
word-break:break-all;
}
.text p span{
position:relative;
}
.text p span.correct{
color: #56964f;
}
.text p span.incorrect{
color:#cb3439;
background:#ffc0cb;
outline: 1px solid #fff;
border-radius:4px;
}
.text p span.active{
color:#17a2b8;
}
.text p span.active::before{
content:"";
position:absolute;
left:0;
bottom:0;
height:2px;
width:1000%;
background:#17a2b8;
animation:blink 1s ease-in-out infinite;
}
@keyframes blink{
50%{
opacity: 1;
}
}
.box .content{
display:flex;
margin-top:17px;
padding: 12px 0;
align-items:center;
border-top:1px solid #ccc;
justify-content:space-between;
}
.content .result{
display:flex;
width:calc(100% - 140px);
justify-content:space-between;
}
.content button{
border:none;
outline:none;
width:105px;
padding:8px 0;
color:#fff;
cursor:pointer;
font-size:16px;
border-radius:5px;
background:#c4c4ff;
transition:transform 0.3s ease;
}
.content button:active{
transform:scale(0.97);
}
.result li{
height:22px;
list-style:none;
display:flex;
align-items:center;
}
.result li span{
display:block;
font-size:20px;
margin-left:10px;
}
.result li p{
font-size:19px;
}
.result li:not(:first-child){
padding-left:22px;
border-left:1px solid #a5a5a5;
}
.result li:not(:first-child) span{
font-weight:500;
}
.result li b{
font-weight:500;
}
Loading

0 comments on commit e89e2fb

Please sign in to comment.