Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add the typing-test game #4918

Merged
merged 6 commits into from
Jul 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading