Compare commits

..

No commits in common. "5d85095ac13e0acc59fb736de2b9338b8c4c7dd0" and "6f358ec9774f3ae10f135a95676d92f1c9d92210" have entirely different histories.

5 changed files with 55 additions and 164 deletions

View File

@ -1,4 +1,5 @@
function myFunction(elmnt) { function myFunction(elmnt) {
console.log(elmnt.style.backgroundColor);
if (elmnt.style.backgroundColor == "white") { if (elmnt.style.backgroundColor == "white") {
elmnt.style.backgroundColor = "hsl(120, 100%, 75%)"; elmnt.style.backgroundColor = "hsl(120, 100%, 75%)";
} else { } else {
@ -59,6 +60,7 @@ function contains_digits(rows) {
return true; return true;
} }
function generate_rows_check() { function generate_rows_check() {
console.log(rows);
var rows = new Array(generate_row(), generate_row(), generate_row()); var rows = new Array(generate_row(), generate_row(), generate_row());
while (!contains_digits(rows)) { while (!contains_digits(rows)) {
var rows = new Array(generate_row(), generate_row(), generate_row()); var rows = new Array(generate_row(), generate_row(), generate_row());

View File

@ -24,49 +24,37 @@
</label> </label>
<label> <label>
<input type="radio" name="win-type" value="full-board"> <input type="radio" name="win-type" value="full">
Full board Full board
</label> </label>
</fieldset> </fieldset>
<fieldset class="input-container"> <fieldset class="input-container">
<legend>Workers</legend> <legend>Workers</legend>
<input id="workers" type="number" min="1" value="1">
<label>
Amount:
<input id="workers" type="number" min="1" value="1" style="width: 70px;">
</label>
<label>
Batch size:
<input id="batch-size" type="number" min="1" value="1000" style="width: 100px;">
</label>
</fieldset> </fieldset>
</div> </div>
<div id="numbers-container"> <div>
<fieldset class="input-container"> <fieldset id="numbers-container" class="input-container">
<legend>Numbers</legend> <legend>Numbers</legend>
<input class="number-input" type="number" min="1" max="90" autocomplete="off"> <input type="number" min="1" max="90">
</fieldset> </fieldset>
</div> </div>
<div id="results"> <div id="results">
<button id="pause">Start</button> <button id="pause">Pause</button>
&emsp; &emsp;
<b> <b>
<span id="attempts">0</span> boards tried &emsp; <span id="attempts">--</span> plates tried &emsp;
(<span id="speed">0.00</span>/sec) (<span id="speed">--</span>/sec)
</b> </b>
<div id="result-list"></div>
</div> </div>
<div> <fieldset>
<fieldset> <legend>Log</legend>
<legend>Log</legend> <div id="log"></div>
<div id="log"></div> </fieldset>
</fieldset>
</div>
</main> </main>
</body> </body>
</html> </html>

72
main.js
View File

@ -1,18 +1,11 @@
let paused = false; let paused = false;
let autoStart = true;
let workers = []; let workers = [];
let totalTime = 0; let totalTime = 0;
let startedAt;
let totalAttempts = 0; let totalAttempts = 0;
let names = [];
fetch("names.json").then(res => res.json()).then(json => names = json);
function showStats() { function showStats() {
const time = totalTime + (Date.now() - startedAt);
document.getElementById("attempts").innerText = totalAttempts; document.getElementById("attempts").innerText = totalAttempts;
document.getElementById("speed").innerText = (totalAttempts / time).toFixed(2); document.getElementById("speed").innerText = (totalAttempts / totalTime).toFixed(2);
} }
function log(text, workerId) { function log(text, workerId) {
@ -38,38 +31,13 @@ function resetWorkers() {
} }
function runWorkers() { function runWorkers() {
const numbers = [].map.call(document.getElementsByClassName("number-input"), input => input.valueAsNumber)
.filter(value => !isNaN(value));
if (numbers.length < 4) return;
if (paused && !autoStart) return;
setPaused(false);
startedAt = Date.now();
const selectedWinType = document.querySelector("input[name=win-type]:checked");
const winType = selectedWinType.value;
const winTypeLabel = selectedWinType.parentElement.innerText.trim();
resetWorkers(); resetWorkers();
const amount = document.getElementById("workers").valueAsNumber; const amount = document.getElementById("workers").valueAsNumber;
const batchSize = document.getElementById("batch-size").valueAsNumber;
log(`Creating ${amount} workers`); log(`Creating ${amount} workers`);
log(`* Win type: ${winType}`);
log(`* Numbers: ${numbers.join(", ")}`);
const usedNames = [];
for (let i = 0; i < amount; i++) { for (let i = 0; i < amount; i++) {
let name;
do
name = names[Math.floor(Math.random() * names.length)];
while (usedNames.includes(name));
usedNames.push(name);
const worker = new Worker("worker.js"); const worker = new Worker("worker.js");
worker.addEventListener("message", message => { worker.addEventListener("message", message => {
switch (message.data.type) { switch (message.data.type) {
@ -77,6 +45,7 @@ function runWorkers() {
if (!paused) worker.postMessage({ type: "run" }); if (!paused) worker.postMessage({ type: "run" });
break; break;
case "stats": case "stats":
totalTime += message.data.time;
totalAttempts += message.data.attempts; totalAttempts += message.data.attempts;
showStats(); showStats();
@ -84,16 +53,6 @@ function runWorkers() {
case "log": case "log":
log(message.data.text, message.data.id); log(message.data.text, message.data.id);
break; break;
case "winner":
document.getElementById("result-list").innerHTML +=
`<div>
<span class="winner">Winner:</span> <b>${message.data.name}</b>
<br>
<small>(${winTypeLabel} &mdash; ${numbers.join(", ")})</small>
</div>`;
setPaused(true);
autoStart = true;
case "terminate": case "terminate":
worker.terminate(); worker.terminate();
workers.splice(workers.indexOf(worker), 1); workers.splice(workers.indexOf(worker), 1);
@ -101,32 +60,16 @@ function runWorkers() {
} }
}); });
worker.postMessage({ type: "init", id: i + 1, numbers, winType, name, batchSize }); worker.postMessage({ type: "init", id: i + 1 });
workers.push(worker); workers.push(worker);
} }
} }
function setPaused(value) {
paused = value;
for (const worker of workers) {
worker.postMessage({ type: paused ? "stop" : "run" });
}
document.getElementById("pause").innerText = paused ? "Start" : "Pause";
if (paused)
totalTime += (Date.now() - startedAt);
startedAt = Date.now();
}
document.getElementById("numbers-container").addEventListener("keydown", event => { document.getElementById("numbers-container").addEventListener("keydown", event => {
// Add new input field on enter // Add new input field on enter
if (event.key === "Enter") { if (event.key === "Enter") {
const input = document.createElement("input"); const input = document.createElement("input");
input.type = "number"; input.type = "number";
input.className = "number-input";
input.min = 1; input.min = 1;
input.max = 90; input.max = 90;
@ -174,8 +117,13 @@ document.getElementById("numbers-container").addEventListener("keydown", event =
}); });
document.getElementById("pause").addEventListener("click", event => { document.getElementById("pause").addEventListener("click", event => {
setPaused(!paused); paused = !paused;
autoStart = false;
for (const worker of workers) {
worker.postMessage({ type: paused ? "stop" : "run" });
}
event.target.innerText = paused ? "Start" : "Pause";
}); });
document.getElementById("workers").value = navigator.hardwareConcurrency ?? 1; document.getElementById("workers").value = navigator.hardwareConcurrency ?? 1;

View File

@ -18,40 +18,16 @@ main {
.input-container { .input-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-wrap: wrap;
gap: 0.5rem; gap: 0.5rem;
background-color: #EEE; background-color: #EEE;
margin: 0.5rem; margin: 0.5rem;
} }
#numbers-container .input-container {
max-height: 800px;
display: flex;
flex-direction: row;
}
#numbers-container input {
flex-basis: calc(50% - 4px);
}
#numbers-container {
width: 400px;
}
#results { #results {
margin-top: 1rem; margin-top: 1rem;
width: 400px; width: 400px;
} }
#result-list div {
margin-top: 1rem;
line-height: 1;
}
#result-list .winner {
color: #2E7D32;
}
#log { #log {
height: 200px; height: 200px;
width: 400px; width: 400px;

View File

@ -1,20 +1,17 @@
importScripts("seedrandom.js"); importScripts("seedrandom.js");
importScripts("generator.js"); importScripts("generator.js");
let workerId; console.log("worker");
let workerName;
let winType;
let numbers;
let batchSize;
let nameIndex = 0; let workerId;
let currentInput = "";
let attempts = 0; let attempts = 0;
let startedAt; let startedAt;
let statsInterval; let statsInterval;
let guessInterval; let guessInterval;
function getBoard(name) { function getNumbers(name) {
Math.seedrandom(name); Math.seedrandom(name);
let numbers = []; let numbers = [];
@ -24,50 +21,15 @@ function getBoard(name) {
} }
const activatedCols = generate_rows_check(); const activatedCols = generate_rows_check();
const board = [[], [], []]; const activatedNumbers = [];
for (let row = 0; row < 3; row++) { for (let row = 0; row < 3; row++) {
for (const col of activatedCols[row]) { for (const col of activatedCols[row]) {
board[row].push(numbers[(col - 1) * 3 + row]); activatedNumbers.push(numbers[(col - 1) * 3 + row]);
} }
} }
return board; return activatedNumbers;
}
function hasWonRow(row, numbers) {
return row.every(number => numbers.includes(number));
}
function getRowsWon(board, numbers) {
return board.filter(row => hasWonRow(row, numbers)).length;
}
function hasWon(wonRows, winType) {
switch (winType) {
case "row":
return wonRows >= 1;
case "two-rows":
return wonRows >= 2;
case "full-board":
return wonRows >= 3;
}
}
function guess() {
for (let i = 0; i < 100; i++) {
const name = workerName + nameIndex++;
attempts++;
const board = getBoard(name);
const wonRows = getRowsWon(board, numbers);
if (hasWon(wonRows, winType)) {
self.postMessage({ type: "winner", name });
self.postMessage({ type: "log", text: `Found winner: ${name}`, id: workerId });
}
}
} }
function sendStats() { function sendStats() {
@ -82,6 +44,30 @@ function resetStats() {
startedAt = Date.now(); startedAt = Date.now();
} }
function generateNextInput(input) {
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
if (input.length === 0)
return alphabet[0];
for (let i = input.length - 1; i >= 0; i--) {
const index = alphabet.indexOf(input[i]);
if (index < alphabet.length - 1) {
return input.substring(0, i) + alphabet[index + 1] + alphabet[0].repeat(input.length - i - 1);
}
}
return alphabet[0] + input;
}
function guess() {
currentInput = generateNextInput(currentInput);
attempts++;
// TODO
}
function run() { function run() {
statsInterval = setInterval(sendStats, 1000); statsInterval = setInterval(sendStats, 1000);
guessInterval = setInterval(guess, 0); guessInterval = setInterval(guess, 0);
@ -92,14 +78,9 @@ function run() {
} }
function stop() { function stop() {
if (!statsInterval && !guessInterval) return;
clearInterval(statsInterval); clearInterval(statsInterval);
clearInterval(guessInterval); clearInterval(guessInterval);
statsInterval = null;
guessInterval = null;
sendStats(); sendStats();
self.postMessage({ type: "log", text: "Stopping worker", id: workerId }); self.postMessage({ type: "log", text: "Stopping worker", id: workerId });
@ -109,10 +90,6 @@ self.onmessage = message => {
switch (message.data.type) { switch (message.data.type) {
case "init": case "init":
workerId = message.data.id; workerId = message.data.id;
workerName = message.data.name;
winType = message.data.winType;
numbers = message.data.numbers;
batchSize = message.data.batchSize;
self.postMessage({ type: "ready" }); self.postMessage({ type: "ready" });
break; break;
case "run": case "run":