aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.js116
-rw-r--r--src/manage.js130
-rw-r--r--src/timer.js89
-rw-r--r--src/utils.js182
4 files changed, 248 insertions, 269 deletions
diff --git a/src/main.js b/src/main.js
index a0ec6bc..7e9f988 100644
--- a/src/main.js
+++ b/src/main.js
@@ -2,14 +2,24 @@ import "notyf/notyf.min.css";
import "bulma/css/bulma.css";
import "@fortawesome/fontawesome-free/css/all.css";
import "./style.css";
-import { Manager, Timer } from "./utils";
-import { CourtManager, PlayerManager } from "./manage";
+import { Notyf } from "notyf";
+import { Timer } from "./utils";
import { Team, Game } from "./data";
+import { Manager, CourtManager, PlayerManager, GuestManager } from "./manage";
+
+export function getNotifier(seconds) {
+ return new Notyf({
+ duration: seconds * milliSecond,
+ position: { x: "center", y: "top" },
+ dismissible: true,
+ });
+}
export class GameManager extends Manager {
- t = new Timer();
+ timer = new Timer();
courts = new CourtManager();
players = new PlayerManager();
+ guests = new GuestManager();
constructor() {
super("Game", 12);
@@ -32,30 +42,23 @@ export class GameManager extends Manager {
return new Game(id, status, teamOne, teamTwo);
}
addBehaviour() {
- let description = this.isConfirmed() ? "Round " + this.round : "Proposal";
+ let confirmedStatus = this.data[0].status;
+ let description = confirmedStatus ? "Round " + this.round : "Proposal";
document.getElementById("Game_description").innerHTML = description;
}
- isConfirmed() {
- return this.data[0].status;
- }
- getBlockedGames() {
+ addBlockedGames() {
const inactiveCourts = this.courts.inactive();
console.log("Total reserved courts are " + inactiveCourts.length + ".");
- let games = [];
for (let court of inactiveCourts) {
- games.push(this.createItem(court.id, "RESERVED"));
+ this.data.push(this.createItem(court.id, "RESERVED"));
}
- return games;
}
- inactive(courts) {
- let games = [];
+ addInactiveGames(courts) {
for (let court of courts) {
- games.push(this.createItem(court.id));
+ this.data.push(this.createItem(court.id));
}
- return games;
}
- active(courts, players) {
- let games = [];
+ addActiveGames(courts, players) {
for (let index = 0; index < courts.length; index++) {
const startIndex = 4 * index;
const endIndex = startIndex + 4;
@@ -64,33 +67,67 @@ export class GameManager extends Manager {
const team_2 = new Team(courtPlayers[1].name, courtPlayers[2].name);
const game = new Game(courts[index].id, false, team_1, team_2);
game.print();
- games.push(game);
+ this.data.push(game);
}
- return games;
+ }
+ getPossibleGameCount() {
+ let activeRegularCount = this.players.active().length;
+ let activeGuestCount = this.guests.active().length;
+ let activePlayerCount = activeRegularCount + activeGuestCount;
+ console.log("There are a total of " + activePlayerCount + " players available.");
+ let activeCourtCount = this.courts.active().length;
+ console.log("There are a total of " + activeCourtCount + " courts available.");
+ let possibleMatches = Math.min(Math.floor(activePlayerCount / 4), activeCourtCount);
+ return possibleMatches;
+ }
+ selectPlayers(count) {
+ console.log("Required players are " + count);
+ let activePlayers = this.players.active();
+ const activeGuests = this.guests.active();
+ activePlayers = activePlayers.concat(activeGuests);
+ console.log("Active players are:");
+ console.log(
+ activePlayers
+ .map((i) => {
+ return i.name;
+ })
+ .join(",")
+ );
+ const shuffledPlayers = shuffle(activePlayers);
+ shuffledPlayers.sort((a, b) => a.totalPlayed - b.totalPlayed);
+ const selectedPlayers = shuffledPlayers.slice(0, count);
+ selectedPlayers.sort((a, b) => a.level - b.level);
+ console.log("Selected players are:");
+ console.log(
+ selectedPlayers
+ .map((i) => {
+ return i.name;
+ })
+ .join(",")
+ );
+ return selectedPlayers;
}
propose() {
console.log("Proposing new games!");
- let possibleMatches = getMatchCount(
- this.players.data.concat(this.players.g.data),
- this.courts.data
- );
+ let possibleMatches = this.getPossibleGameCount();
console.log("Total possible matches are " + possibleMatches + ".");
- this.data = this.getBlockedGames();
+ this.data = [];
+ this.addBlockedGames();
const activeCourts = this.courts.active();
const unusedCourts = activeCourts.slice(possibleMatches + 1);
- this.data = this.data.concat(this.inactive(unusedCourts));
+ this.addInactiveGames(unusedCourts);
const usedCourts = activeCourts.slice(0, possibleMatches);
let requiredPlayerCount = possibleMatches * 4;
- const selectedPlayers = this.players.propose(requiredPlayerCount);
+ const selectedPlayers = this.selectPlayers(requiredPlayerCount);
console.log("The matches are:");
- this.data = this.data.concat(this.active(usedCourts, selectedPlayers));
+ this.addActiveGames(usedCourts, selectedPlayers);
this.data.sort((a, b) => a.id - b.id);
this.render();
}
confirm() {
- if (this.isConfirmed()) {
- const notification = new Notyf();
- notification.error("Create a proposal first!");
+ let confirmedStatus = this.data[0].status;
+ if (confirmedStatus) {
+ getNotifier().error("Create a proposal first!");
return;
}
console.log("Confirm the proposal for round " + this.round + ".");
@@ -116,19 +153,12 @@ export class GameManager extends Manager {
}
}
-function getMatchCount(players, courts) {
- courts = courts.filter(function (c) {
- return c.status;
- });
- console.log("There are a total of " + courts.length + " courts available.");
- console.log(players);
- players = players.filter(function (p) {
- return p.status;
- });
- console.log("There are a total of " + players.length + " players available.");
- var possibleMatches = Math.floor(players.length / 4);
- possibleMatches = Math.min(possibleMatches, courts.length);
- return possibleMatches;
+function shuffle(array) {
+ for (let i = array.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [array[i], array[j]] = [array[j], array[i]];
+ }
+ return array;
}
function addGameBehaviour(g) {
diff --git a/src/manage.js b/src/manage.js
index 31e828d..ef48f8e 100644
--- a/src/manage.js
+++ b/src/manage.js
@@ -1,5 +1,70 @@
import { Court, Guest, Player } from "./data";
-import { shuffle, Manager, randomLevel, randomStatus } from "./utils";
+
+export class Manager {
+ constructor(description, maxCount) {
+ this.description = description;
+ this.maxCount = maxCount;
+ this.data = [];
+ this.count = this.data.length;
+ let data = JSON.parse(localStorage.getItem(this.description));
+ if (data === null || data.length === 0) {
+ this.generate();
+ return;
+ }
+ this.load(data);
+ }
+ generate() {
+ for (let i = 0; i < this.maxCount; i++) {
+ this.data.push(this.createItem(i));
+ }
+ console.log("Generated " + this.data.length + " " + this.description);
+ this.store();
+ this.render();
+ }
+ load(data) {
+ for (let i = 0; i < data.length; i++) {
+ this.data.push(this.loadItem(data[i]));
+ }
+ console.log("Loaded " + this.data.length + " " + this.description);
+ this.render();
+ }
+ store() {
+ let stringData = JSON.stringify(this.data);
+ localStorage.setItem(this.data[0].description, stringData);
+ }
+ render() {
+ let renderedHTML = this.data
+ .map((i) => {
+ return i.render();
+ })
+ .join("");
+ let elementId = this.data[0].description + "_list";
+ document.getElementById(elementId).innerHTML = renderedHTML;
+ this.addBehaviour();
+ }
+ addBehaviour() {
+ for (let idx = 0; idx < this.data.length; ++idx) {
+ const elementId = this.data[0].description + "_" + this.data[idx].id;
+ const p = document.getElementById(elementId);
+ p.addEventListener("click", () => {
+ this.data[idx].toggle();
+ this.store();
+ p.classList.toggle("is-success");
+ p.classList.toggle("is-danger");
+ });
+ }
+ }
+ active() {
+ return this.data.filter(function (c) {
+ return c.status;
+ });
+ }
+ inactive() {
+ return this.data.filter(function (c) {
+ return !c.status;
+ });
+ }
+}
export class CourtManager extends Manager {
constructor() {
@@ -15,6 +80,19 @@ export class CourtManager extends Manager {
}
}
+export function randomStatus() {
+ return Math.random() < 0.5;
+}
+
+function normalize(data) {
+ let factor = Number(document.getElementById("skill").value);
+ console.log("Normalize skill by a factor of " + factor + ".");
+ return data.map(function (p) {
+ p.skill = Math.ceil(p.skill / factor);
+ return p;
+ });
+}
+
export class GuestManager extends Manager {
constructor() {
super("Guest", 12);
@@ -30,16 +108,15 @@ export class GuestManager extends Manager {
}
active(factor) {
factor = typeof factor !== "undefined" ? factor : 1;
- let data = super.active();
- console.log("Normalize skill by a factor of " + factor + ".");
- let players = data.map(function (p) {
- p.skill = Math.ceil(p.skill / factor);
- return p;
- });
- return players;
+ return normalize(super.active());
}
}
+export function randomLevel() {
+ const max_level = 10;
+ return Math.floor(Math.random() * max_level + 1);
+}
+
export class PlayerManager extends Manager {
constructor() {
super("Regular", 71);
@@ -76,42 +153,7 @@ export class PlayerManager extends Manager {
}
active(factor) {
factor = typeof factor !== "undefined" ? factor : 1;
- let data = super.active();
- console.log("Normalize skill by a factor of " + factor + ".");
- let players = data.map(function (p) {
- p.skill = Math.ceil(p.skill / factor);
- return p;
- });
- return players;
- }
- propose(count) {
- console.log("Required players are " + count);
- let factor = Number(document.getElementById("skill").value);
- console.log("Skill normalized by a factor of " + factor + ".");
- let activePlayers = this.active(factor);
- const activeGuests = this.g.active(factor);
- activePlayers = activePlayers.concat(activeGuests);
- console.log("Active players are:");
- console.log(
- activePlayers
- .map((i) => {
- return i.name;
- })
- .join(",")
- );
- const shuffledPlayers = shuffle(activePlayers);
- shuffledPlayers.sort((a, b) => a.totalPlayed - b.totalPlayed);
- const selectedPlayers = shuffledPlayers.slice(0, count);
- selectedPlayers.sort((a, b) => a.level - b.level);
- console.log("Selected players are:");
- console.log(
- selectedPlayers
- .map((i) => {
- return i.name;
- })
- .join(",")
- );
- return selectedPlayers;
+ return normalize(super.active());
}
}
diff --git a/src/timer.js b/src/timer.js
new file mode 100644
index 0000000..7c70550
--- /dev/null
+++ b/src/timer.js
@@ -0,0 +1,89 @@
+const milliSecond = 1000;
+
+export class Timer {
+ pointer = 0;
+
+ constructor() {
+ this.mins = Number(sessionStorage.getItem("mins")) || 12;
+ this.running = Boolean(Number(sessionStorage.getItem("running"))) || false;
+ this.deadline =
+ Number(sessionStorage.getItem("deadline")) || new Date().getTime();
+ if (this.running) {
+ this.start(false);
+ } else {
+ this.reset();
+ }
+ addTimerBehaviour(this);
+ }
+ store() {
+ sessionStorage.setItem("mins", this.mins);
+ sessionStorage.setItem("running", Number(this.running));
+ sessionStorage.setItem("deadline", this.deadline);
+ }
+ set(m, s) {
+ const timer = document.getElementById("timer-display");
+ m = m < 10 ? "0" + m : m;
+ s = s < 10 ? "0" + s : s;
+ timer.value = `${m}:${s}`;
+ }
+ reset() {
+ clearInterval(this.pointer);
+ const mins = Math.floor(this.mins);
+ const secs = (this.mins - mins) * 60;
+ this.set(mins, secs);
+ this.running = false;
+ this.store();
+ }
+ update(ms) {
+ const m = Math.floor((ms % (milliSecond * 60 * 60)) / (milliSecond * 60));
+ const s = Math.floor((ms % (milliSecond * 60)) / milliSecond);
+ this.set(m, s);
+ }
+ refresh(p) {
+ const now = new Date().getTime();
+ const msToDeadline = p.deadline - now;
+ if (msToDeadline > 0) {
+ p.update(msToDeadline);
+ return;
+ }
+ p.reset();
+ getNotifier().error("Round completed");
+ }
+ start(fresh) {
+ if (fresh) {
+ const now = new Date().getTime();
+ const msToDeadline = this.mins * 60 * 1000;
+ this.deadline = now + msToDeadline;
+ }
+ this.running = true;
+ this.store();
+ this.pointer = setInterval(this.refresh, 1000, this);
+ }
+ change(value) {
+ this.mins += value;
+ if (this.mins < 0.5) {
+ this.mins = 0.5;
+ }
+ this.reset();
+ }
+}
+
+function addTimerBehaviour(t) {
+ document.getElementById("timer-start").addEventListener("click", () => {
+ if (t.running) return;
+ t.start(1);
+ });
+ document.getElementById("timer-stop").addEventListener("click", () => {
+ t.reset();
+ });
+ document.getElementById("timer-inc").addEventListener("click", () => {
+ if (!t.running) {
+ t.change(0.5);
+ }
+ });
+ document.getElementById("timer-dec").addEventListener("click", () => {
+ if (!t.running) {
+ t.change(-0.5);
+ }
+ });
+}
diff --git a/src/utils.js b/src/utils.js
deleted file mode 100644
index a8d4f07..0000000
--- a/src/utils.js
+++ /dev/null
@@ -1,182 +0,0 @@
-import { Notyf } from "notyf";
-
-const milliSecond = 1000;
-
-export class Timer {
- pointer = 0;
-
- constructor() {
- this.mins = Number(sessionStorage.getItem("mins")) || 12;
- this.running = Boolean(Number(sessionStorage.getItem("running"))) || false;
- this.deadline =
- Number(sessionStorage.getItem("deadline")) || new Date().getTime();
- if (this.running) {
- this.start(false);
- } else {
- this.reset();
- }
- addTimerBehaviour(this);
- }
- store() {
- sessionStorage.setItem("mins", this.mins);
- sessionStorage.setItem("running", Number(this.running));
- sessionStorage.setItem("deadline", this.deadline);
- }
- set(m, s) {
- const timer = document.getElementById("timer-display");
- m = m < 10 ? "0" + m : m;
- s = s < 10 ? "0" + s : s;
- timer.value = `${m}:${s}`;
- }
- reset() {
- clearInterval(this.pointer);
- const mins = Math.floor(this.mins);
- const secs = (this.mins - mins) * 60;
- this.set(mins, secs);
- this.running = false;
- this.store();
- }
- update(ms) {
- const m = Math.floor((ms % (milliSecond * 60 * 60)) / (milliSecond * 60));
- const s = Math.floor((ms % (milliSecond * 60)) / milliSecond);
- this.set(m, s);
- }
- refresh(p) {
- const now = new Date().getTime();
- const msToDeadline = p.deadline - now;
- if (msToDeadline > 0) {
- p.update(msToDeadline);
- return;
- }
- p.reset();
- getNotifier().error("Round completed");
- }
- start(fresh) {
- if (fresh) {
- const now = new Date().getTime();
- const msToDeadline = this.mins * 60 * 1000;
- this.deadline = now + msToDeadline;
- }
- this.running = true;
- this.store();
- this.pointer = setInterval(this.refresh, 1000, this);
- }
- change(value) {
- this.mins += value;
- if (this.mins < 0.5) {
- this.mins = 0.5;
- }
- this.reset();
- }
-}
-
-function addTimerBehaviour(t) {
- document.getElementById("timer-start").addEventListener("click", () => {
- if (t.running) return;
- t.start(1);
- });
- document.getElementById("timer-stop").addEventListener("click", () => {
- t.reset();
- });
- document.getElementById("timer-inc").addEventListener("click", () => {
- if (!t.running) {
- t.change(0.5);
- }
- });
- document.getElementById("timer-dec").addEventListener("click", () => {
- if (!t.running) {
- t.change(-0.5);
- }
- });
-}
-
-export class Manager {
- constructor(description, maxCount) {
- this.description = description;
- this.maxCount = maxCount;
- this.data = [];
- this.count = this.data.length;
- let data = JSON.parse(localStorage.getItem(this.description));
- if (data === null || data.length === 0) {
- this.generate();
- return;
- }
- this.load(data);
- }
- generate() {
- for (let i = 0; i < this.maxCount; i++) {
- this.data.push(this.createItem(i));
- }
- console.log("Generated " + this.data.length + " " + this.description);
- this.store();
- this.render();
- }
- load(data) {
- for (let i = 0; i < data.length; i++) {
- this.data.push(this.loadItem(data[i]));
- }
- console.log("Loaded " + this.data.length + " " + this.description);
- this.render();
- }
- store() {
- let stringData = JSON.stringify(this.data);
- localStorage.setItem(this.data[0].description, stringData);
- }
- render() {
- let renderedHTML = this.data
- .map((i) => {
- return i.render();
- })
- .join("");
- let elementId = this.data[0].description + "_list";
- document.getElementById(elementId).innerHTML = renderedHTML;
- this.addBehaviour();
- }
- addBehaviour() {
- for (let idx = 0; idx < this.data.length; ++idx) {
- const elementId = this.data[0].description + "_" + this.data[idx].id;
- const p = document.getElementById(elementId);
- p.addEventListener("click", () => {
- this.data[idx].toggle();
- this.store();
- p.classList.toggle("is-success");
- p.classList.toggle("is-danger");
- });
- }
- }
- active() {
- return this.data.filter(function (c) {
- return c.status;
- });
- }
- inactive() {
- return this.data.filter(function (c) {
- return !c.status;
- });
- }
-}
-
-export function shuffle(array) {
- for (let i = array.length - 1; i > 0; i--) {
- const j = Math.floor(Math.random() * (i + 1));
- [array[i], array[j]] = [array[j], array[i]];
- }
- return array;
-}
-
-export function randomLevel() {
- const max_level = 10;
- return Math.floor(Math.random() * max_level + 1);
-}
-
-export function randomStatus() {
- return Math.random() < 0.5;
-}
-
-export function getNotifier(seconds) {
- return new Notyf({
- duration: seconds * milliSecond,
- position: { x: "center", y: "top" },
- dismissible: true,
- });
-}