— Hit the start button to get the first quote —
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
The Hitchhikers Guide to the Typing Machine
</head>
<body>
The Hitchhikers Guide
to the Typing Machine
</body>
</html>
— Hit the start button to get the first quote —
Congratulations! You are ready to write about the whole galaxy!
Completed quotes:
- ...
body div.container {
width: 800px;
margin: auto;
}
/* === The Header Section === */
header {
display: flex;
}
header div:first-child {
width: 600px;
}
header div:last-child {
width: 200px;
}
header img {
width: 100%;
}
header h1 {
font-size: 42px;
}
/* === The Content Section === */
div.content {
display: flex;
}
div.content div {
width: 600px;
}
div.content aside {
width: 200px;
}
footer {
text-align: center;
border-top: 1px dotted gray;
padding-top: 1em;
margin-top: 2em;
}
/* === The Stats Section === */
#stats {
border: 1px dotted gray;
border-radius: 3%;
margin: 0.8em;
padding: 0.5em;
}
/* === The Main Game Section === */
#main-game {
text-align: center;
margin-bottom: 4em;
}
#current-quote {
font-size: 1.2em;
}
#input {
width: 90%;
border-radius: 10px;
padding: .7em;
font-size: 1.2em;
}
#main-game div.action-button-container {
margin-top: 1em;
}
#main-game div.action-button-container button {
font-size: 1.5em;
padding: .3em;
margin: 0 .4em;
}
.correct {
background-color: #afa;
}
.incorrect {
background-color: #faa;
}
const quotes = [
"Don't panic!",
"Time is an illusion. Lunchtime doubly so.",
"Would it save you a lot of time if I just gave up and went mad now?",
"The ships hung in the sky in much the same way that bricks don't.",
"I'd far rather be happy than right any day.",
"Space is big. You just won't believe how vastly, hugely, mind-bogglingly big it is.",
"I mean, you may think it's a long way down the road to the chemist's, but that's just peanuts to space.",
"For a moment, nothing happened. Then, after a second or so, nothing continued to happen.",
"Ford... you're turning into a penguin. Stop it.",
"A towel is about the most massively useful thing an interstellar hitchhiker can have.",
"The Answer to the Great Question... Of Life, the Universe and Everything... Is... Forty-two",
"So long, and thanks for all the fish.",
"Anyone who is capable of getting themselves made President should on no account be allowed to do the job.",
"We demand rigidly defined areas of doubt and uncertainty!",
"That's just perfectly normal paranoia. Everyone in the Universe has that.",
"If I asked you where the hell we were, would I regret it?",
]
const stats = {
words: 0,
characters: 0,
time: 0,
fastest: {
quote: '',
time: 0,
},
achievements: {
ftl: {
label: '',
explanation: '',
unlocked: false
},
dontpanic: {
label: '',
explanation: '',
unlocked: false
},
fourtytwo: {
label: '',
explanation: '',
unlocked: false
},
},
reset: function () {
this.words = 0
this.characters = 0
this.time = 0
this.fastest.quote = ''
for (const key in this.achievements) {
this.achievements[key].unlocked = false
}
}
}
let uncompleted = []
let timeStart
let typingErrors
// little helper function to get a random integer
function randInt(max) {
return Math.floor(Math.random() * max);
}
function resetQuotes () {
let quotePool = [...quotes]
// use the following for debugging, to get a quick test sentence first
//uncompleted.push('Test sentence.')
while (quotePool.length > 0) {
let i = randInt(quotePool.length)
let [quote] = quotePool.splice(i, 1)
uncompleted.push(quote)
}
}
function resetCompletedQuotes () {
$( '#completed ul' ).children().remove()
}
function resetGame () {
resetCompletedQuotes()
resetQuotes()
stats.reset()
$( '#input' )
.removeClass('correct')
.removeClass('incorrect')
.attr('disabled', 'true')
.val('')
$( '#current-quote' ).html('— Hit the start button to get the first quote —')
}
function nextQuote () {
$( '#success' ).text('')
$( '#current-quote' ).text(uncompleted[0])
$( '#input' )
.removeClass('correct')
.removeClass('incorrect')
.val('')
.removeAttr('disabled')
.focus()
timeStart = Date.now()
typingErrors = 0
}
function processInput () {
$input = $( '#input' )
quote = uncompleted[0]
value = $input.val()
if ( quote.startsWith( value ) ) {
$input.addClass('correct')
$input.removeClass('incorrect')
} else {
// only count a typing error if the sentence was not already incorrect
if (! $input.hasClass('incorrect')) {
typingErrors++
}
$input.addClass('incorrect')
$input.removeClass('correct')
}
if ( quote === value ) {
let timeEnd = Date.now()
seconds = ( timeEnd - timeStart ) / 1000
$input.attr('disabled', 'true')
$( '#success' ).text('Wonderful! You completed this quote in '+seconds+' seconds with '+typingErrors+' typing errors.')
$( '#completed ul' ).append( $( ''+quote+' ' ) )
uncompleted.splice(0, 1)
}
// now check if this was the last quote
if ( uncompleted.length === 0 ) {
$( '#start' ).remove()
$( '#reset' ).remove()
$( '#game-completed' ).show( 'slow' )
}
}
$( document ).ready(function () {
resetGame()
$( '#reset' ).on('click', resetGame)
$( '#start' ).on('click', nextQuote)
$( '#input' ).on('input', processInput).val('')
})
You could:
Minimal effort for this exercise: some styling
If you want to go for substantial extensions and changes, this can already count towards your final project.