Fix up selecting first player and some errors in the number generation.
This commit is contained in:
parent
b37f273b05
commit
8afe512062
@ -4,3 +4,22 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ready {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ready-button {
|
||||||
|
font-size: 2em;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ready-button.active {
|
||||||
|
font-size: 2em;
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
@ -15,3 +15,24 @@ function updatePlayerDom() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
document.querySelector("#ready-button").addEventListener("click", async (ev) => {
|
||||||
|
let nowReady = ev.target.textContent === "Not ready";
|
||||||
|
us.ready = nowReady;
|
||||||
|
|
||||||
|
ev.target.classList.toggle("active");
|
||||||
|
ev.target.textContent = nowReady ? "Ready" : "Not ready";
|
||||||
|
|
||||||
|
socket.emit("message", {
|
||||||
|
type: "SYNC",
|
||||||
|
author: ID,
|
||||||
|
ready: nowReady,
|
||||||
|
name: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (allPlayersReady()) {
|
||||||
|
await startPregame();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -3,6 +3,7 @@ const ID = window.crypto.randomUUID();
|
|||||||
const TIMEOUT = 30_000;
|
const TIMEOUT = 30_000;
|
||||||
|
|
||||||
let players = {};
|
let players = {};
|
||||||
|
let us = null;
|
||||||
|
|
||||||
const WAITING = 0;
|
const WAITING = 0;
|
||||||
const PRE_GAME = 1;
|
const PRE_GAME = 1;
|
||||||
@ -38,6 +39,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
});
|
});
|
||||||
// Create self
|
// Create self
|
||||||
players[ID] = new Player(ID, name);
|
players[ID] = new Player(ID, name);
|
||||||
|
us = players[ID];
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("message", async (data) => {
|
socket.on("message", async (data) => {
|
||||||
@ -64,7 +66,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "RANDOM":
|
case "RANDOM":
|
||||||
random.processCooperativeRandom(data);
|
await random.processCooperativeRandom(data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -131,16 +133,7 @@ async function sync(data) {
|
|||||||
players[data.author].ready = data.ready;
|
players[data.author].ready = data.ready;
|
||||||
|
|
||||||
if (allPlayersReady()) {
|
if (allPlayersReady()) {
|
||||||
game_state = PRE_GAME;
|
await startPregame();
|
||||||
// Decide turn order. "Master" begins a cooperative rng process.
|
|
||||||
if (ID === Array.min(...Object.keys(players))) {
|
|
||||||
random.coopRandom(Object.keys(players).length, "first-player");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for value to populate
|
|
||||||
let player1 = await random.get("first-player");
|
|
||||||
|
|
||||||
console.log(player1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,3 +146,13 @@ function allPlayersReady() {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function startPregame() {
|
||||||
|
console.log("All players ready.");
|
||||||
|
|
||||||
|
game_state = PRE_GAME;
|
||||||
|
|
||||||
|
let player1 = await random.get(Object.keys(players).length, "first-player");
|
||||||
|
|
||||||
|
console.log(player1);
|
||||||
|
}
|
||||||
|
@ -5,7 +5,7 @@ class RandomSession {
|
|||||||
this.cipherKeys = {};
|
this.cipherKeys = {};
|
||||||
this.ourKey = CryptoJS.lib.WordArray.random(32).toString();
|
this.ourKey = CryptoJS.lib.WordArray.random(32).toString();
|
||||||
// 32-bit as JavaScript does funny stuff at 64-bit levels.
|
// 32-bit as JavaScript does funny stuff at 64-bit levels.
|
||||||
this.ourNoise = CryptoJS.lib.WordArray.random(4).toString();
|
this.ourNoise = CryptoJS.lib.WordArray.random(4);
|
||||||
this.finalValue = null;
|
this.finalValue = null;
|
||||||
this.resolvers = [];
|
this.resolvers = [];
|
||||||
}
|
}
|
||||||
@ -17,33 +17,37 @@ class RandomSession {
|
|||||||
|
|
||||||
class Random {
|
class Random {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.locked = false;
|
|
||||||
this.sessions = {};
|
this.sessions = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
get(sessionId) {
|
async get(n, sessionId) {
|
||||||
// Spin until lock frees.
|
if (this.sessions[sessionId] === undefined) {
|
||||||
while (this.locked);
|
this.initialiseSession(n, sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
let promise;
|
||||||
|
await navigator.locks.request(`random-${sessionId}`, () => {
|
||||||
|
console.log("in lock now");
|
||||||
if (this.sessions[sessionId].finalValue === null) {
|
if (this.sessions[sessionId].finalValue === null) {
|
||||||
let session = this.sessions[sessionId];
|
let session = this.sessions[sessionId];
|
||||||
let resolver;
|
let resolver;
|
||||||
let promise = new Promise((resolve) => {
|
promise = new Promise((resolve) => {
|
||||||
resolver = resolve;
|
resolver = resolve;
|
||||||
});
|
});
|
||||||
session.resolvers.push(resolver);
|
session.resolvers.push(resolver);
|
||||||
return promise;
|
|
||||||
} else {
|
} else {
|
||||||
return new Promise((resolve) => {
|
promise = new Promise((resolve) => {
|
||||||
resolve(this.sessions[sessionId].finalValue);
|
resolve(this.sessions[sessionId].finalValue);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a cooperative random session.
|
* Start a cooperative random session.
|
||||||
*/
|
*/
|
||||||
coopRandom(n, sessionId) {
|
initialiseSession(n, sessionId) {
|
||||||
let session = new RandomSession(n);
|
let session = new RandomSession(n);
|
||||||
if (sessionId === undefined) {
|
if (sessionId === undefined) {
|
||||||
sessionId = window.crypto.randomUUID();
|
sessionId = window.crypto.randomUUID();
|
||||||
@ -60,7 +64,7 @@ class Random {
|
|||||||
cipherText: session.cipherText(),
|
cipherText: session.cipherText(),
|
||||||
});
|
});
|
||||||
|
|
||||||
return sessionId;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,28 +72,13 @@ class Random {
|
|||||||
*
|
*
|
||||||
* @param data Packet received
|
* @param data Packet received
|
||||||
*/
|
*/
|
||||||
processCooperativeRandom(data) {
|
async processCooperativeRandom(data) {
|
||||||
// Step 0: extract relevant information from data
|
// Step 0: extract relevant information from data
|
||||||
let session = this.sessions[data.session];
|
let session = this.sessions[data.session];
|
||||||
const stage = data.stage;
|
const stage = data.stage;
|
||||||
|
|
||||||
if (session === undefined) {
|
if (session === undefined) {
|
||||||
// Step 1: generate and encrypt our random value. 8 bytes = 64 bit integer
|
session = this.initialiseSession(data.range, data.session);
|
||||||
const noise = CryptoJS.lib.WordArray.random(8).toString();
|
|
||||||
console.log(`our noise: ${noise}`);
|
|
||||||
|
|
||||||
session = new RandomSession(data.range);
|
|
||||||
this.sessions[data.session] = session;
|
|
||||||
|
|
||||||
// Step 2: send our random value and wait for all responses
|
|
||||||
socket.emit("message", {
|
|
||||||
type: "RANDOM",
|
|
||||||
author: ID,
|
|
||||||
session: data.session,
|
|
||||||
stage: "CIPHERTEXT",
|
|
||||||
range: data.range,
|
|
||||||
cipherText: session.cipherText(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stage === "CIPHERTEXT") {
|
if (stage === "CIPHERTEXT") {
|
||||||
@ -117,22 +106,22 @@ class Random {
|
|||||||
Object.keys(players).length - 1
|
Object.keys(players).length - 1
|
||||||
) {
|
) {
|
||||||
// Lock out wait calls as they may resolve to never-ending promises.
|
// Lock out wait calls as they may resolve to never-ending promises.
|
||||||
this.locked = true;
|
await navigator.locks.request(`random-${data.session}`, () => {
|
||||||
|
let total = parseInt(session.ourNoise, 16);
|
||||||
let total = 0;
|
|
||||||
|
|
||||||
for (let participant of Object.keys(session.cipherKeys)) {
|
for (let participant of Object.keys(session.cipherKeys)) {
|
||||||
total += CryptoJS.AES.decrypt(
|
let decrypted = CryptoJS.AES.decrypt(
|
||||||
session.cipherTexts[participant],
|
session.cipherTexts[participant],
|
||||||
session.cipherKeys[participant]
|
session.cipherKeys[participant]
|
||||||
);
|
).toString();
|
||||||
|
|
||||||
|
total += parseInt(decrypted, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
session.finalValue = total % session.range;
|
session.finalValue = total % session.range;
|
||||||
|
|
||||||
this.resolve(data.session);
|
this.resolve(data.session);
|
||||||
|
});
|
||||||
this.locked = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
static/js/shim.js
Normal file
3
static/js/shim.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Array.prototype.min = function () {
|
||||||
|
return this.reduce((min, val) => (min < val ? min : val));
|
||||||
|
};
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
|
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/shim.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/index.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/index.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/player.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/player.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/dom.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/dom.js') }}"></script>
|
||||||
@ -20,5 +21,9 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="ready">
|
||||||
|
<button id="ready-button">Not ready</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
Reference in New Issue
Block a user