Skip to content

Instantly share code, notes, and snippets.

@frankstepanski
Last active February 16, 2021 00:48
Show Gist options
  • Save frankstepanski/15faffa12266b6d7c202cc334abca368 to your computer and use it in GitHub Desktop.
Save frankstepanski/15faffa12266b6d7c202cc334abca368 to your computer and use it in GitHub Desktop.
jQuery-enabled Quiz App Game
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" name="description" content="Quiz App">
<title>Quiz App</title>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/4.2.0/normalize.min.css">
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<link rel="stylesheet" href="main.css">
</head>
<body>
<div class="container">
<main>
<!-- inline styling this instead of CSS because it should never be viewable to anyone except our JS, which uses this content as mini-templates for questions
and answers -->
<div class="start-page" style="display: none;">
<h1>Quiz App</h1>
<p>This app tests your ability to guess the right answer to four questions. The correct answers have been chosen at random.</p>
<p><em>Good luck friend!</em></p>
<form name="game-start">
<button type="submit">start</button>
</form>
</div>
<div class="question-page" style="display: none;">
<h3><span class="question-count"></span> : <span class="question-text"></span></h3>
<form name="current-question">
<ol type="A" class="choices"></ol>
<button type="submit">Submit</button>
<button class="restart-game">Start over</button>
</form>
</div>
<div class="answer-feedback-page" style="display: none;">
<div class="feedback-container">
<div class="feedback-header"></div>
<p class="feedback-text"></p>
<button class="see-next"></button>
</div>
</div>
<div class="final-feedback-page" style="display: none;">
<h1>Results</h1>
<p class="results-text"></p>
<button class="restart-game">Start over</button>
</div>
</main>
</div>
<script src="https://code.jquery.com/jquery-3.1.0.slim.min.js" integrity="sha256-cRpWjoSOw5KcyIOaZNo4i6fZ9tKPhYYb6i5T9RSVJG8=" crossorigin="anonymous"></script>
<script type="text/javascript" src="app.js"></script>
</body>
</html>
// State object
var state = {
questions: [
{
text: "Which number am I thinking of?",
choices: ["1", "2", "3", "4"],
correctChoiceIndex: 0
},
{
text: "What about now, can you guess now?",
choices: ["1", "2", "3", "4"],
correctChoiceIndex: 1
},
{
text: "I'm thinking of a number between 1 and 4. What is it?",
choices: ["1", "2", "3", "4"],
correctChoiceIndex: 2,
},
{
text: "If I were a number between 1 and 4, which would I be?",
choices: ["1", "2", "3", "4"],
correctChoiceIndex: 3,
},
{
text: "Guess what my favorite number is",
choices: ["1", "2", "3", "4"],
correctChoiceIndex: 0,
}
],
praises : [
"Wow. You got it right. I bet you feel really good about yourself now",
"Correct. Which would be impressive, if it wasn't just luck",
"Oh was I yawning? Because you getting that answer right was boring me to sleep",
"Hear all that applause for you because you got this question right? Neither do I."
],
admonishments: [
"Really? That's your guess? WE EXPECTED BETTER OF YOU!",
"Looks like someone wasn't paying attention in telepathy school, geesh!",
"That's incorrect. You've dissapointed yourself, your family, your city, state, country and planet, to say nothing of the cosmos"
],
score: 0,
currentQuestionIndex: 0,
route: 'start',
lastAnswerCorrect: false,
feedbackRandom: 0
};
// State modification functions
function setRoute(state, route) {
state.route = route;
};
function resetGame(state) {
state.score = 0;
state.currentQuestionIndex = 0;
setRoute(state, 'start');
};
function answerQuestion(state, answer) {
var currentQuestion = state.questions[state.currentQuestionIndex];
state.lastAnswerCorrect = currentQuestion.correctChoiceIndex === answer;
if (state.lastAnswerCorrect) {
state.score++;
}
selectFeedback(state);
setRoute(state, 'answer-feedback');
};
function selectFeedback(state) {
state.feedbackRandom = Math.random();
};
function advance(state) {
state.currentQuestionIndex++;
if (state.currentQuestionIndex === state.questions.length) {
setRoute(state, 'final-feedback');
}
else {
setRoute(state, 'question');
}
};
// Render functions
function renderApp(state, elements) {
// default to hiding all routes, then show the current route
Object.keys(elements).forEach(function(route) {
elements[route].hide();
});
elements[state.route].show();
if (state.route === 'start') {
renderStartPage(state, elements[state.route]);
}
else if (state.route === 'question') {
renderQuestionPage(state, elements[state.route]);
}
else if (state.route === 'answer-feedback') {
renderAnswerFeedbackPage(state, elements[state.route]);
}
else if (state.route === 'final-feedback') {
renderFinalFeedbackPage(state, elements[state.route]);
}
};
// at the moment, `renderStartPage` doesn't do anything, because
// the start page is preloaded in our HTML, but we've included
// the function and used above in our routing system so that this
// application view is accounted for in our system
function renderStartPage(state, element) {
};
function renderQuestionPage(state, element) {
renderQuestionCount(state, element.find('.question-count'));
renderQuestionText(state, element.find('.question-text'));
renderChoices(state, element.find('.choices'));
};
function renderAnswerFeedbackPage(state, element) {
renderAnswerFeedbackHeader(state, element.find(".feedback-header"));
renderAnswerFeedbackText(state, element.find(".feedback-text"));
renderNextButtonText(state, element.find(".see-next"));
};
function renderFinalFeedbackPage(state, element) {
renderFinalFeedbackText(state, element.find('.results-text'));
};
function renderQuestionCount(state, element) {
var text = (state.currentQuestionIndex + 1) + "/" + state.questions.length;
element.text(text);
};
function renderQuestionText(state, element) {
var currentQuestion = state.questions[state.currentQuestionIndex];
element.text(currentQuestion.text);
};
function renderChoices(state, element) {
var currentQuestion = state.questions[state.currentQuestionIndex];
var choices = currentQuestion.choices.map(function(choice, index) {
return (
'<li>' +
'<input type="radio" name="user-answer" value="' + index + '" required>' +
'<label>' + choice + '</label>' +
'</li>'
);
});
element.html(choices);
};
function renderAnswerFeedbackHeader(state, element) {
var html = state.lastAnswerCorrect ?
"<h6 class='user-was-correct'>correct</h6>" :
"<h1 class='user-was-incorrect'>Wrooonnnngggg!</>";
element.html(html);
};
function renderAnswerFeedbackText(state, element) {
var choices = state.lastAnswerCorrect ? state.praises : state.admonishments;
var text = choices[Math.floor(state.feedbackRandom * choices.length)];
element.text(text);
};
function renderNextButtonText(state, element) {
var text = state.currentQuestionIndex < state.questions.length - 1 ?
"Next" : "How did I do?";
element.text(text);
};
function renderFinalFeedbackText(state, element) {
var text = "You got " + state.score + " out of " +
state.questions.length + " questions right.";
element.text(text);
};
// Event handlers
var PAGE_ELEMENTS = {
'start': $('.start-page'),
'question': $('.question-page'),
'answer-feedback': $('.answer-feedback-page'),
'final-feedback': $('.final-feedback-page')
};
$("form[name='game-start']").submit(function(event) {
event.preventDefault();
setRoute(state, 'question');
renderApp(state, PAGE_ELEMENTS);
});
$(".restart-game").click(function(event){
event.preventDefault();
resetGame(state);
renderApp(state, PAGE_ELEMENTS);
});
$("form[name='current-question']").submit(function(event) {
event.preventDefault();
var answer = $("input[name='user-answer']:checked").val();
answer = parseInt(answer, 10);
answerQuestion(state, answer);
renderApp(state, PAGE_ELEMENTS);
});
$(".see-next").click(function(event) {
advance(state);
renderApp(state, PAGE_ELEMENTS);
});
$(function() { renderApp(state, PAGE_ELEMENTS); });
* {
box-sizing: border-box;
font-family: 'Roboto', sans-serif;
}
main {
max-width: 960px;
margin: 0 auto;
}
p {
max-width: 400px;
}
.container {
padding: 0 60px;
padding-top: 90px;
}
.user-was-correct::before {
content: "Shhhh!!!!! (";
}
.user-was-correct::after {
content: ")";
}
.user-was-incorrect {
font-size: 50px;
color: red;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment