Compare commits
No commits in common. "5d85095ac13e0acc59fb736de2b9338b8c4c7dd0" and "6f358ec9774f3ae10f135a95676d92f1c9d92210" have entirely different histories.
5d85095ac1
...
6f358ec977
@ -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());
|
||||||
|
36
index.html
36
index.html
@ -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>
|
||||||
 
|
 
|
||||||
<b>
|
<b>
|
||||||
<span id="attempts">0</span> boards tried  
|
<span id="attempts">--</span> plates tried  
|
||||||
(<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
72
main.js
@ -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} — ${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;
|
||||||
|
24
style.css
24
style.css
@ -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;
|
||||||
|
85
worker.js
85
worker.js
@ -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":
|
||||||
|
Loading…
Reference in New Issue
Block a user