mags-banko/main.js
2025-04-12 15:09:50 +02:00

142 lines
3.7 KiB
JavaScript

let paused = false;
let workers = [];
let totalTime = 0;
let totalAttempts = 0;
function showStats() {
document.getElementById("attempts").innerText = totalAttempts;
document.getElementById("speed").innerText = (totalAttempts / totalTime).toFixed(2);
}
function log(text, workerId) {
const time = new Date().toLocaleTimeString("en-GB");
let html = `<time>${time}</time> `;
if (workerId) html += `<span class="worker-id">[${workerId}]</span> `;
html += `${text}<br>`;
document.getElementById("log").innerHTML += html;
document.getElementById("log").scrollTo(0, document.getElementById("log").scrollHeight);
}
function resetWorkers() {
log("Terminating workers");
for (const worker of workers) {
worker.postMessage({ type: "terminate" });
}
totalTime = 0;
totalAttempts = 0;
}
function runWorkers() {
const numbers = [].map.call(document.getElementsByClassName("number-input"), input => input.valueAsNumber)
.filter(value => !isNaN(value));
const winType = document.querySelector("input[name=win-type]:checked").value;
resetWorkers();
const amount = document.getElementById("workers").valueAsNumber;
log(`Creating ${amount} workers`);
log(`* Win type: ${winType}`);
log(`* Numbers: ${numbers.join(", ")}`);
for (let i = 0; i < amount; i++) {
const worker = new Worker("worker.js");
worker.addEventListener("message", message => {
switch (message.data.type) {
case "ready":
if (!paused) worker.postMessage({ type: "run" });
break;
case "stats":
totalTime += message.data.time;
totalAttempts += message.data.attempts;
showStats();
break;
case "log":
log(message.data.text, message.data.id);
break;
case "terminate":
worker.terminate();
workers.splice(workers.indexOf(worker), 1);
break;
}
});
worker.postMessage({ type: "init", id: i + 1, numbers, winType });
workers.push(worker);
}
}
document.getElementById("numbers-container").addEventListener("keydown", event => {
// Add new input field on enter
if (event.key === "Enter") {
const input = document.createElement("input");
input.type = "number";
input.className = "number-input";
input.min = 1;
input.max = 90;
event.target.parentElement.appendChild(input);
input.focus();
return;
}
// Remove empty input field on backspace
if (event.key === "Backspace" || event.key === "Delete") {
if (event.target.value !== "" || document.querySelectorAll("#numbers-container input").length < 2)
return;
if (event.target.previousElementSibling.localName === "input")
event.target.previousElementSibling.focus();
else
event.target.nextElementSibling.focus();
event.target.parentElement.removeChild(event.target);
event.preventDefault();
return;
}
// Move between inputs on arrow up/down
if (event.key === "ArrowUp" || event.key === "ArrowDown") {
event.preventDefault();
const elem = event.key === "ArrowUp"
? event.target.previousElementSibling
: event.target.nextElementSibling;
if (!elem || elem.localName !== "input") return;
elem.focus();
return;
}
// Disallow non-digits
const allowed = [/^Digit/, /^Arrow/, /Tab/];
if (!event.altKey && !event.ctrlKey && !allowed.some(regex => regex.test(event.code))) {
event.preventDefault();
}
});
document.getElementById("pause").addEventListener("click", event => {
paused = !paused;
for (const worker of workers) {
worker.postMessage({ type: paused ? "stop" : "run" });
}
event.target.innerText = paused ? "Start" : "Pause";
});
document.getElementById("workers").value = navigator.hardwareConcurrency ?? 1;
for (const container of document.getElementsByClassName("input-container")) {
container.addEventListener("change", runWorkers);
}