Skip to content

Commit

Permalink
zetamac clone
Browse files Browse the repository at this point in the history
  • Loading branch information
Your Name authored and dannyridel committed Jul 4, 2024
1 parent 8349936 commit ce4ab66
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 16 deletions.
24 changes: 14 additions & 10 deletions routes/public.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ module.exports = (app, mongo) => {
res.render(VIEWS + 'public/robots.ejs', { pageName: 'robots.txt' });
});

app.get('/zetamac', (req, res) => {
res.render(VIEWS + 'public/zetamac.ejs', { isAuthenticated: req.isAuthenticated(), });
});

// PUBLIC POST
app.post('/register', (req, res, next) => {
req.body.username = req.body.username.toLowerCase();
Expand Down Expand Up @@ -400,17 +404,17 @@ module.exports = (app, mongo) => {
app.post('/contact', (req, res) => {
req.isAuthenticated()
? sendDiscordWebhook(
req.body.comment,
req.user.username,
req.user.ign,
req.body.questionId
)
req.body.comment,
req.user.username,
req.user.ign,
req.body.questionId
)
: sendDiscordWebhook(
req.body.comment,
'N/A',
'User not signed in.',
req.body.questionId
);
req.body.comment,
'N/A',
'User not signed in.',
req.body.questionId
);
req.flash('successFlash', 'Thanks for your feedback!');
if (req.body.redirect) {
res.redirect(req.body.redirect);
Expand Down
13 changes: 9 additions & 4 deletions views/partials/navigationPrivate.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,18 @@
</div>
</li>
<li class="nav-item me-3">
<a class="nav-link" href="/whoWeAre">
About
<a class="nav-link" href="/references">
References
</a>
</li>
<li class="nav-item me-3">
<a class="nav-link" href="/references">
References
<a class="nav-link" href="/zetamac">
Zetamac Mode
</a>
</li>
<li class="nav-item me-3">
<a class="nav-link" href="/whoWeAre">
About
</a>
</li>
</ul>
Expand Down
5 changes: 5 additions & 0 deletions views/partials/navigationPublic.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@

<div class="collapse navbar-collapse" id="navbar">
<ul class="navbar-nav me-auto">
<li class="nav-item me-3">
<a class="nav-link" href="/zetamac">
Zetamac Mode
</a>
</li>
<li class="nav-item me-3">
<a class="nav-link" href="/whoWeAre">
About
Expand Down
6 changes: 4 additions & 2 deletions views/partials/navigationV2.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,11 @@
</li>
<% } %>

<li><a class="font-medium hover:opacity-50 transition-opacity" href="/whoWeAre">About</a></li>

<li><a class="font-medium hover:opacity-50 transition-opacity" href="/references">References</a></li>

<li><a class="font-medium hover:opacity-50 transition-opacity" href="/zetamac">Zetamac Mode</a></li>

<li><a class="font-medium hover:opacity-50 transition-opacity" href="/whoWeAre">About</a></li>
</ul>

<%# Right group: search, log in, sign up %>
Expand Down
264 changes: 264 additions & 0 deletions views/public/zetamac.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
<%- include("../partials/header") -%>

<% if(isAuthenticated) { %>
<%- include("../partials/navigationPrivate") -%>
<% } else { %>
<%- include("../partials/navigationPublic") -%>
<% } %>

<h1 class="my-5 container display-2 text-center">Zetamac on Mutorials</h1>

<div class="jumbotron container">
<h2>Arithmetic Game</h2>
<div id="init">
<p>The Arithmetic Game is a fast-paced speed drill where you are given two minutes to
solve as many
arithmetic problems as you can.</p>
<div id="initConfig">
<% const CONFIG={ Addition: { symbol: "+" , range: [2, 100] }, Subtraction: {
symbol: "-" , range: [2, 100], additionalOptions: [{ name: "allow negative" ,
id: "allowNegative" , checked: false, }, { name: "same as Addition" ,
id: "sameAsAddition" , checked: true, }] }, Multiplication: { symbol: "×" ,
range: [2, 100] }, Division: { symbol: "÷" , range: [2, 100], additionalOptions:
[{ name: "same as Multiplication" , id: "sameAsMultiplication" , checked: true,
}] } }; %>
<% ["Addition", "Subtraction" , "Multiplication" , "Division" ].forEach((op)=> {
%>
<div id="<%= op.toLowerCase() %>">
<label>
<input type="checkbox" checked id="<%= op.toLowerCase() %>_enabled">
<%= op %>
</label>
<br>
<ul class="subOptions" id="<%= op.toLowerCase() %>_options">
<li>Range: (
<input type="number" id="<%= op.toLowerCase() %>_min1"
value="<%- CONFIG[op].range[0] %>"
class="form-control d-inline-block numOptions">
to
<input type="number" id="<%= op.toLowerCase() %>_max1"
value="<%- CONFIG[op].range[1] %>"
class="form-control d-inline-block numOptions">
)
<%- CONFIG[op].symbol %>
(
<input type="number" id="<%= op.toLowerCase() %>_min2"
value="<%- CONFIG[op].range[0] %>"
class="form-control d-inline-block numOptions">
to
<input type="number" id="<%= op.toLowerCase() %>_max2"
value="<%- CONFIG[op].range[1] %>"
class="form-control d-inline-block numOptions">
)
</li>
<% if (CONFIG[op].additionalOptions) { %>
<% CONFIG[op].additionalOptions.forEach((option)=> { %>
<li>
<label>
<input type="checkbox"
id="<%= op.toLowerCase() %>_<%= option.id %>"
<%=option.checked ? "checked" : "" %>>
<%= option.name %>
</label>
</li>
<% }); %>
<% } %>
</ul>
</div>
<% }); %>
time: <input type="number" id="gameTime" value="120"
class="form-control d-inline-block numOptions"> seconds
<br>
<br>
<button class="btn btn-primary" onclick="startGame()">start</button>
</div>
</div>
<div id="game" hidden>
<p id="time">Time left: <span id="timeLeft"></span> seconds</p>
<p id="score">Score: <span id="scoreValue">0</span></p>
<p>Problem:</p>
<div id="problem" class="problem">
<span id="problemValue"></span><input type="number" id="answer"
class="form-control d-inline-block numOptions problem" style="width:10rem">
</div>
<button class="btn btn-primary" onclick="reset()">cancel game</button>
</div>
<div id="results" hidden>
<br>
<h3>Game Over!</h3>
<p>Your answered <span id="finalScore"></span> questions in <span id="finalTime"></span>
seconds</p>
<button class="btn btn-primary" onclick="startGame()">play again</button>
<button class="btn btn-primary" onclick="reset()">change settings</button>
</div>
</div>

<script>
const SYMBOLS = { addition: "+", subtraction: "-", multiplication: "×", division: "÷" };
const opFuncs = {
addition: (a, b) => a + b,
subtraction: (a, b) => a - b,
multiplication: (a, b) => a * b,
division: (a, b) => a / b
};
let opConfig = {
addition: {
enabled: true,
range: [[], []],
},
subtraction: {
enabled: true,
range: [[], []],
allowNegative: false,
sameAsAddition: false
},
multiplication: {
enabled: true,
range: [[], []],
},
division: {
enabled: true,
range: [[], []],
sameAsMultiplication: false
}
};
for (let op in opConfig) {
document.getElementById(`${op}_enabled`).addEventListener("change", () => {
opConfig[op].enabled = document.getElementById(`${op}_enabled`).checked;
document.getElementById(`${op}_options`).hidden = !opConfig[op].enabled;
});
let configMap = {
"_min1": [0, 0],
"_max1": [0, 1],
"_min2": [1, 0],
"_max2": [1, 1],
};
for (let key in configMap) {
let element = document.getElementById(op + key);
opConfig[op].range[configMap[key][0]][configMap[key][1]] = parseInt(element.value);
element.addEventListener("change", () => {
opConfig[op].range[configMap[key][0]][configMap[key][1]] = parseInt(element.value);
})
}
for (let additionalOption in opConfig[op]) {
if (additionalOption == "enabled" || additionalOption == "range") continue;
let element = document.getElementById(`${op}_${additionalOption}`);
if (additionalOption.startsWith("sameAs")) {
document.getElementById(`${op}_options`).firstElementChild.hidden = true;
}
element.addEventListener("change", () => {
opConfig[op][additionalOption] = element.checked;
if (additionalOption.startsWith("sameAs")) {
document.getElementById(`${op}_options`).firstElementChild.hidden = opConfig[op][additionalOption];
}
});
}
}
window.generateQuestion = function (config) {
let op = Object.keys(config)[Math.floor(Math.random() * Object.keys(config).length)];
let range1 = config[op].range[0];
let range2 = config[op].range[1];
let symbol = SYMBOLS[op];
let problem;
let answer;
let num1 = Math.floor(Math.random() * (range1[1] - range1[0] + 1)) + range1[0];
let num2 = Math.floor(Math.random() * (range2[1] - range2[0] + 1)) + range2[0];
if (op == "addition") {
problem = `${num1} ${symbol} ${num2} = `;
answer = opFuncs[op](num1, num2);
}
else if (op == "subtraction") {
if (config[op].allowNegative && num1 < num2) {
problem = `${num2} ${symbol} ${num1} = `;
answer = opFuncs[op](num2, num1);
}
else {
problem = `${num1} ${symbol} ${num2} = `;
answer = opFuncs[op](num1, num2);
}
}
else if (op == "multiplication") {
problem = `${num1} ${symbol} ${num2} = `;
answer = opFuncs[op](num1, num2);
}
else if (op == "division") {
problem = `${num1 * num2} ${symbol} ${num2} = `;
answer = opFuncs[op](num1 * num2, num2);
}
return { problem, answer };
}
window.startGame = function () {
let gameConfig = structuredClone(opConfig);
let gameTime = document.getElementById("gameTime").value;
let score = 0;
for (let op in gameConfig) {
if (!gameConfig[op].enabled) { delete gameConfig[op]; }
}
if (Object.keys(gameConfig).length == 0) {
alert("Please enable at least one operation");
return;
}
document.getElementById("init").hidden = true;
document.getElementById("game").hidden = false;
document.getElementById("scoreValue").innerText = 0;
let startTime = Date.now();
window.timer = setInterval(() => {
let timeLeft = gameTime - Math.floor((Date.now() - startTime) / 1000);
document.getElementById("timeLeft").innerText = timeLeft;
if (timeLeft <= 0) {
clearInterval(window.timer);
document.getElementById("game").hidden = true;
document.getElementById("results").hidden = false;
document.getElementById("finalScore").innerText = score;
document.getElementById("finalTime").innerText = gameTime;
}
}, 100);
document.getElementById('answer').focus();
let question = generateQuestion(gameConfig);
document.getElementById("problemValue").innerText = question.problem;
document.getElementById("answer").addEventListener("input", (event) => {
if (parseInt(event.target.value) == question.answer) {
score++;
document.getElementById("scoreValue").innerText = score;
question = generateQuestion(gameConfig);
document.getElementById("problemValue").innerText = question.problem;
document.getElementById("answer").value = "";
}
});
}
window.reset = function () {
clearInterval(window.timer);
document.getElementById("init").hidden = false;
document.getElementById("game").hidden = true;
document.getElementById("results").hidden = true;
}
</script>

<style>
.subOptions {
list-style-type: none;
}
.numOptions {
width: 5rem;
}
.problem {
text-align: center;
font-size: 3rem;
height: 3rem;
}
</style>

<%- include("../partials/footer") -%>

0 comments on commit ce4ab66

Please sign in to comment.