From 944fc2715e967a51e4ccca49d87e987ee2727bc2 Mon Sep 17 00:00:00 2001 From: Karan Jayachandra Date: Thu, 13 Nov 2025 21:48:40 +0100 Subject: Transitioned to npm --- src/court.mjs | 53 ++++++++++++++++ src/game.mjs | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/guest.mjs | 69 +++++++++++++++++++++ src/main.js | 20 +++++++ src/player.mjs | 150 ++++++++++++++++++++++++++++++++++++++++++++++ src/style.css | 12 ++++ src/timer.js | 88 +++++++++++++++++++++++++++ src/utils.mjs | 51 ++++++++++++++++ 8 files changed, 629 insertions(+) create mode 100644 src/court.mjs create mode 100644 src/game.mjs create mode 100644 src/guest.mjs create mode 100644 src/main.js create mode 100644 src/player.mjs create mode 100644 src/style.css create mode 100644 src/timer.js create mode 100644 src/utils.mjs (limited to 'src') diff --git a/src/court.mjs b/src/court.mjs new file mode 100644 index 0000000..713c488 --- /dev/null +++ b/src/court.mjs @@ -0,0 +1,53 @@ +import { Manager } from "./utils.mjs"; + +class Court { + constructor(id, status) { + this.id = id; + this.status = typeof status !== "undefined" ? status : true; + this.name = "Court " + (id + 1); + } + toggle() { + this.status = !this.status; + this.print(); + } + print() { + let status = this.status ? "active" : "inactive"; + console.log(this.name + " is currently " + status); + } + render() { + let color = this.status ? "is-success" : "is-danger"; + let type = `class="button is-medium ${color}"`; + return ``; + } +} + +export class CourtManager extends Manager { + maxCourtCount = 12; + + constructor() { + super("court", []); + console.log("Loading court data."); + let data = JSON.parse(localStorage.getItem(this.description)); + if (data === null || data.length != this.maxCourtCount) { + console.log("Court data unavailable: " + data); + this.generate(); + return; + } + for (let i = 0; i < this.maxCourtCount; i++) { + this.listData.push(new Court(data[i].id, data[i].status)); + } + console.log("Loaded " + this.listData.length + " courts."); + this.render(); + this.addBehaviour(); + } + generate() { + console.log("Generating court data."); + for (let i = 0; i < this.maxCourtCount; i++) { + this.listData.push(new Court(i)); + } + console.log("Generated data for " + this.listData.length + " courts"); + this.store(); + this.render(); + this.addBehaviour(); + } +} diff --git a/src/game.mjs b/src/game.mjs new file mode 100644 index 0000000..c8931ac --- /dev/null +++ b/src/game.mjs @@ -0,0 +1,186 @@ +import { Notyf } from 'notyf'; +import { Manager } from "./utils.mjs"; +import { CourtManager } from "./court.mjs"; +import { PlayerManager } from "./player.mjs"; + +class Team { + constructor(playerOne, playerTwo) { + this.playerOne = playerOne; + this.playerTwo = playerTwo; + } + print() { + console.log(this.playerOne + " and " + this.playerTwo); + } + render() { + let p1 = `${this.playerOne}`; + let p2 = `${this.playerTwo}`; + return p1 + p2; + } +} + +class Game { + constructor(id, teamOne, teamTwo, status) { + this.id = id; + this.teamOne = teamOne; + this.teamTwo = teamTwo; + this.status = typeof status !== "undefined" ? status : false; + } + print() { + let teamOne = this.teamOne.playerOne + " and " + this.teamOne.playerTwo; + let teamTwo = this.teamTwo.playerOne + " and " + this.teamTwo.playerTwo; + console.log(teamOne + " is playing against " + teamTwo); + } + render() { + let blockedState = this.teamOne.playerOne === "RESERVED"; + let type = blockedState ? `class="is-danger is-dark"` : ``; + return `${ + this.id + 1 + }${this.teamOne.render()}${this.teamTwo.render()}`; + } +} + +function generateDummyGames(courts, description) { + let team = new Team(description, description); + let games = []; + for (const court of courts) { + let game = new Game(court.id, team, team); + games.push(game); + } + return games; +} + +export class GameManager extends Manager { + courts = new CourtManager(); + players = new PlayerManager(); + + constructor() { + super("game", []); + this.round = Number(localStorage.getItem("round")) || 0; + console.log("Loading game data."); + let data = JSON.parse(localStorage.getItem(this.description)); + if (data === null || data.length === 0) { + console.log("Game data unavailable: " + data); + this.generate(); + return; + } + for (let i = 0; i < data.length; i++) { + let id = Number(data[i].id); + let teamOne = new Team( + data[i].teamOne.playerOne, + data[i].teamOne.playerTwo + ); + let teamTwo = new Team( + data[i].teamTwo.playerOne, + data[i].teamTwo.playerTwo + ); + let status = Boolean(data[i].status); + this.listData.push(new Game(id, teamOne, teamTwo, status)); + } + console.log("Loaded " + this.listData.length + " games."); + this.render(); + } + isConfirmed() { + return this.listData[0].status; + } + generate() { + console.log("Generating the dummy round."); + this.listData = generateDummyGames(this.courts.listData, "---"); + console.log("Loaded " + this.listData.length + " dummy round."); + for (let i = 0; i < this.listData.length; i++) { + this.listData[i].status = true; + } + console.log(this.listData); + this.store(); + this.render(); + } + addBehaviour() { + let description = this.isConfirmed() ? "Round " + this.round : "Proposal"; + document.getElementById("game_description").innerHTML = description; + } + getBlockedGames() { + const inactiveCourts = this.courts.inactive(); + console.log("Total reserved courts are " + inactiveCourts.length + "."); + return generateDummyGames(inactiveCourts, "RESERVED"); + } + inactive(courts) { + return generateDummyGames(courts, "---"); + } + active(courts, players) { + let games = []; + for (let index = 0; index < courts.length; index++) { + const startIndex = 4 * index; + const endIndex = startIndex + 4; + const courtPlayers = players.slice(startIndex, endIndex); + const team_1 = new Team(courtPlayers[0].name, courtPlayers[3].name); + const team_2 = new Team(courtPlayers[1].name, courtPlayers[2].name); + const game = new Game(courts[index].id, team_1, team_2); + game.print(); + games.push(game); + } + return games; + } + propose() { + console.log("Proposing new games!"); + let possibleMatches = getMatchCount( + this.players.listData, + this.courts.listData + ); + console.log("Total possible matches are " + possibleMatches + "."); + this.listData = this.getBlockedGames(); + const activeCourts = this.courts.active(); + const unusedCourts = activeCourts.slice(possibleMatches + 1); + this.listData = this.listData.concat(this.inactive(unusedCourts)); + const usedCourts = activeCourts.slice(0, possibleMatches); + let requiredPlayerCount = possibleMatches * 4; + const selectedPlayers = this.players.propose(requiredPlayerCount); + console.log("The matches are:"); + this.listData = this.listData.concat( + this.active(usedCourts, selectedPlayers) + ); + this.listData.sort((a, b) => a.id - b.id); + this.render(); + } + confirm() { + if (this.isConfirmed()) { + const notification = new Notyf(); + notification.error("Create a proposal first!"); + return; + } + console.log("Confirm the proposal for round " + this.round + "."); + this.round += 1; + localStorage.setItem("round", this.round); + for (let i = 0; i < this.listData.length; i++) { + this.listData[i].status = true; + } + // Need to update the number of games played here + this.store(); + this.render(); + document.getElementById("timer-start").click(); + const notification = new Notyf(); + notification.success("Round confirmed!"); + } + reset() { + localStorage.removeItem("round"); + localStorage.removeItem(this.description); + localStorage.removeItem(this.courts.description); + document.getElementById("timer-stop").click(); + window.location.reload(); + const notification = new Notyf(); + notification.error("Session has been reset!"); + } +} + +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; +} diff --git a/src/guest.mjs b/src/guest.mjs new file mode 100644 index 0000000..ba9e8cc --- /dev/null +++ b/src/guest.mjs @@ -0,0 +1,69 @@ +import { Manager } from "./utils.mjs"; + +export class Guest { + constructor(id, name, level, status, totalPlayed) { + this.id = id; + this.status = typeof status !== "undefined" ? status : false; + this.name = name; + this.level = typeof level !== "undefined" ? level : 1; + this.totalPlayed = typeof totalPlayed !== "undefined" ? status : 0; + } + toggle() { + this.status = !this.status; + this.print(); + } + print() { + let status = this.status ? "active" : "inactive"; + console.log(this.name + " is currently " + status); + } + render() { + let color = this.status ? "is-success" : "is-danger"; + let type = `class="button is-medium ${color}"`; + return ``; + } +} + +export class GuestManager extends Manager { + constructor() { + super("guest", []); + console.log("Loading guest data."); + let data = JSON.parse(localStorage.getItem(this.description)); + if (data === null || data.length === 0) { + console.log("Guest data unavailable: " + data); + this.generate(); + return; + } + for (let i = 0; i < data.length; i++) { + let id = Number(data[i].id); + let name = data[i].name; + let level = data[i].level; + let status = data[i].status; + let totalPlayed = data[i].totalPlayed; + this.listData.push(new Player(id, name, level, status, totalPlayed)); + } + console.log("Loaded " + this.listData.length + " players."); + this.render(); + } + generate() { + console.log("Generating guest data."); + let maxPlayerCount = 12; + for (let i = 0; i < maxPlayerCount; i++) { + let level = i < 3 ? 1 : ( i < 6 ? 3 : 7); + let p = new Player(i, "Player " + i, level, false, 0); + this.listData.push(p); + } + console.log("Generated data for " + this.listData.length + " guest"); + this.store(); + this.render(); + } + 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; + } +} \ No newline at end of file diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..91ac386 --- /dev/null +++ b/src/main.js @@ -0,0 +1,20 @@ +import 'notyf/notyf.min.css' +import 'bulma/css/bulma.css' +import '@fortawesome/fontawesome-free/css/all.css' +import './style.css' + +import { GameManager } from "./game.mjs"; + +// Court and player handling +let g = new GameManager(); + +// Game handling +document.getElementById("propose").addEventListener("click", () => { + g.propose(); +}); +document.getElementById("confirm").addEventListener("click", () => { + g.confirm(); +}); +document.getElementById("reset").addEventListener("click", () => { + g.reset(); +}); diff --git a/src/player.mjs b/src/player.mjs new file mode 100644 index 0000000..adf874d --- /dev/null +++ b/src/player.mjs @@ -0,0 +1,150 @@ +import { GuestManager } from "./guest.mjs"; +import { shuffle, Manager } from "./utils.mjs"; + +class Player { + constructor(id, name, level, status, totalPlayed) { + this.id = id; + this.status = typeof status !== "undefined" ? status : false; + this.name = name; + this.level = typeof level !== "undefined" ? level : 1; + this.totalPlayed = typeof totalPlayed !== "undefined" ? status : 0; + } + toggle() { + this.status = !this.status; + this.print(); + } + print() { + let status = this.status ? "active" : "inactive"; + console.log(this.name + " is currently " + status); + } + render() { + let color = this.status ? "is-success" : "is-danger"; + let type = `class="button is-medium ${color}"`; + return ``; + } +} + +function randomLevel() { + const max_level = 10; + return Math.floor(Math.random() * max_level + 1); +} + +function randomStatus() { + return Math.random() < 0.5; +} + +function parseLineToPlayer(data) { + var info = data.split(","); + var id = Number(info[0].trim()); + var name = info[1].trim() + " " + info[2].trim(); + var level = Number(info[3].trim()); + return new Player(id, name, level, true, 0); +} + +export class PlayerManager extends Manager { + // g = new GuestManager(); + + constructor() { + super("regular", []); + console.log("Loading player data."); + let data = JSON.parse(localStorage.getItem(this.description)); + if (data === null || data.length === 0) { + console.log("Player data unavailable: " + data); + this.generate(); + return; + } + for (let i = 0; i < data.length; i++) { + let id = Number(data[i].id); + let name = data[i].name; + let level = data[i].level; + let status = data[i].status; + let totalPlayed = data[i].totalPlayed; + this.listData.push(new Player(id, name, level, status, totalPlayed)); + } + console.log("Loaded " + this.listData.length + " players."); + this.render(); + this.addBehaviour(); + addLoadBehaviour(this); + } + generate() { + console.log("Generating player data."); + let maxPlayerCount = 71; + for (let i = 0; i < maxPlayerCount; i++) { + let p = new Player(i, "Player " + i, randomLevel(), randomStatus(), 0); + this.listData.push(p); + } + console.log("Generated data for " + this.listData.length + " players"); + this.store(); + this.render(); + } + import(data) { + var lines = data.split("\n"); + var players = []; + for (var i = 1; i < lines.length; i++) { + if (lines[i] == undefined || lines[i].trim() == "") { + continue; + } + players.push(parseLineToPlayer(lines[i])); + } + console.log("Loaded " + players.length + " Players"); + for (var i = 0; i < players.length; i++) { + players[i].print(); + } + this.listData = players; + this.store(); + this.render(); + } + 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 + "."); + const activePlayers = this.active(factor); + 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; + } +} + +// TODO Add load behaviour to constructor +export function addLoadBehaviour(p) { + const f = document.querySelector("#player-load input[type=file]"); + f.addEventListener("change", () => { + const file = f.files[0]; + let importData; + console.log("Loading data from " + file.name); + const reader = new FileReader(); + reader.onload = function (e) { + importData = reader.result; + p.import(importData); + }; + reader.readAsText(file); + }); +} diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..8e3b713 --- /dev/null +++ b/src/style.css @@ -0,0 +1,12 @@ +.button-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + grid-gap: 15px; +} +#timer-display { + text-align: center; + width: fit-content; +} +table { + font-size: 1.5em; +} \ No newline at end of file diff --git a/src/timer.js b/src/timer.js new file mode 100644 index 0000000..09189c0 --- /dev/null +++ b/src/timer.js @@ -0,0 +1,88 @@ +let minsPerRound = Number(sessionStorage.getItem("minsPerRound")) || 12; +let timerRunningFlag = Number(sessionStorage.getItem("timerRunningFlag")) || 0; +let deadline = + Number(sessionStorage.getItem("deadline")) || new Date().getTime(); +let clock = 0; + +function setTimer(m, s) { + let timer = document.getElementById("timer-display"); + m = m < 10 ? "0" + m : m; + s = s < 10 ? "0" + s : s; + timer.value = `${m}:${s}`; +} + +function setSessionData() { + sessionStorage.setItem("deadline", deadline); + sessionStorage.setItem("minsPerRound", minsPerRound); + sessionStorage.setItem("timerRunningFlag", timerRunningFlag); +} + +function resetTimer() { + clearInterval(clock); + let mins = Math.floor(minsPerRound); + let secs = (minsPerRound - mins) * 60; + setTimer(mins, secs); + timerRunningFlag = 0; + setSessionData(); +} + +function updateTimer(milliseconds) { + const m = Math.floor((milliseconds % (1000 * 60 * 60)) / (1000 * 60)); + const s = Math.floor((milliseconds % (1000 * 60)) / 1000); + setTimer(m, s); +} + +function refreshTimer() { + const now = new Date().getTime(); + const millisecondsToDeadline = deadline - now; + if (millisecondsToDeadline > 0) { + updateTimer(millisecondsToDeadline); + return; + } + resetTimer(); + const notification = new Notyf({ + duration: 0, + position: { x: "center", y: "top" }, + dismissible: true, + }); + notification.error("Round completed"); +} + +function startTimer(fresh) { + if (fresh) { + let now = new Date().getTime(); + const millisecondsToDeadline = minsPerRound * 60 * 1000; + deadline = now + millisecondsToDeadline; + } + timerRunningFlag = 1; + setSessionData(); + clock = setInterval(refreshTimer, 1000); +} + +window.onload = function () { + if (timerRunningFlag) startTimer(0); + else resetTimer(); + + document.getElementById("timer-start").addEventListener("click", () => { + if (timerRunningFlag != 0) return; + startTimer(1); + }); + + document.getElementById("timer-stop").addEventListener("click", () => { + resetTimer(); + }); + + document.getElementById("timer-inc").addEventListener("click", () => { + if (timerRunningFlag == 0) { + minsPerRound += 0.5; + resetTimer(); + } + }); + + document.getElementById("timer-dec").addEventListener("click", () => { + if (timerRunningFlag == 0 && minsPerRound != 0) { + minsPerRound -= 0.5; + resetTimer(); + } + }); +}; diff --git a/src/utils.mjs b/src/utils.mjs new file mode 100644 index 0000000..06a2519 --- /dev/null +++ b/src/utils.mjs @@ -0,0 +1,51 @@ +export class Manager { + constructor(description, listData) { + this.description = description; + this.listData = listData; + this.count = listData.length; + } + store() { + let stringData = JSON.stringify(this.listData); + localStorage.setItem(this.description, stringData); + } + render() { + let renderedHTML = this.listData + .map((i) => { + return i.render(); + }) + .join(""); + let elementId = this.description + "_list"; + document.getElementById(elementId).innerHTML = renderedHTML; + this.addBehaviour(); + } + addBehaviour() { + for (let idx = 0; idx < this.listData.length; ++idx) { + const elementId = this.description + "_" + this.listData[idx].id; + const p = document.getElementById(elementId); + p.addEventListener("click", () => { + this.listData[idx].toggle(); + this.store(); + p.classList.toggle("is-success"); + p.classList.toggle("is-danger"); + }); + } + } + active() { + return this.listData.filter(function (c) { + return c.status; + }); + } + inactive() { + return this.listData.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; +} -- cgit v1.3.1 From 51cf65e4d3e928a37b542acfb3de439c42907a9f Mon Sep 17 00:00:00 2001 From: Karan Jayachandra Date: Fri, 14 Nov 2025 14:30:38 +0100 Subject: Added the guests section functionality --- index.html | 25 ++++++--------- src/game.mjs | 18 +++++++++-- src/guest.mjs | 31 +++++++++++------- src/main.js | 25 ++++----------- src/player.mjs | 9 +++--- src/style.css | 2 +- src/timer.js | 88 -------------------------------------------------- src/utils.mjs | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 157 insertions(+), 141 deletions(-) delete mode 100644 src/timer.js (limited to 'src') diff --git a/index.html b/index.html index b2501a5..1117176 100644 --- a/index.html +++ b/index.html @@ -9,18 +9,14 @@
-
+

Player Update

- \ No newline at end of file diff --git a/src/game.mjs b/src/game.mjs index c8931ac..864f255 100644 --- a/src/game.mjs +++ b/src/game.mjs @@ -1,4 +1,4 @@ -import { Notyf } from 'notyf'; +import { Notyf } from "notyf"; import { Manager } from "./utils.mjs"; import { CourtManager } from "./court.mjs"; import { PlayerManager } from "./player.mjs"; @@ -78,6 +78,7 @@ export class GameManager extends Manager { } console.log("Loaded " + this.listData.length + " games."); this.render(); + addGameBehaviour(this); } isConfirmed() { return this.listData[0].status; @@ -122,7 +123,7 @@ export class GameManager extends Manager { propose() { console.log("Proposing new games!"); let possibleMatches = getMatchCount( - this.players.listData, + this.players.listData.concat(this.players.g.listData), this.courts.listData ); console.log("Total possible matches are " + possibleMatches + "."); @@ -152,7 +153,6 @@ export class GameManager extends Manager { for (let i = 0; i < this.listData.length; i++) { this.listData[i].status = true; } - // Need to update the number of games played here this.store(); this.render(); document.getElementById("timer-start").click(); @@ -184,3 +184,15 @@ function getMatchCount(players, courts) { possibleMatches = Math.min(possibleMatches, courts.length); return possibleMatches; } + +function addGameBehaviour(g) { + document.getElementById("propose").addEventListener("click", () => { + g.propose(); + }); + document.getElementById("confirm").addEventListener("click", () => { + g.confirm(); + }); + document.getElementById("reset").addEventListener("click", () => { + g.reset(); + }); +} diff --git a/src/guest.mjs b/src/guest.mjs index ba9e8cc..c82d115 100644 --- a/src/guest.mjs +++ b/src/guest.mjs @@ -1,11 +1,22 @@ import { Manager } from "./utils.mjs"; export class Guest { - constructor(id, name, level, status, totalPlayed) { + maxGuestCount = 12; + categoryCount = 3; + + categories = { + 0: { description: "Beginner", level: 1 }, + 1: { description: "Novice", level: 3 }, + 2: { description: "Intermediate", level: 6 }, + }; + + constructor(id, status, totalPlayed) { this.id = id; this.status = typeof status !== "undefined" ? status : false; - this.name = name; - this.level = typeof level !== "undefined" ? level : 1; + const categoryId = Math.floor(id / (12 / this.categoryCount)); + const guestIdentifier = (id % (12 / this.categoryCount)) + 1; + this.name = this.categories[categoryId].description + " " + guestIdentifier; + this.level = this.categories[categoryId].level; this.totalPlayed = typeof totalPlayed !== "undefined" ? status : 0; } toggle() { @@ -19,7 +30,7 @@ export class Guest { render() { let color = this.status ? "is-success" : "is-danger"; let type = `class="button is-medium ${color}"`; - return ``; + return ``; } } @@ -35,21 +46,17 @@ export class GuestManager extends Manager { } for (let i = 0; i < data.length; i++) { let id = Number(data[i].id); - let name = data[i].name; - let level = data[i].level; let status = data[i].status; let totalPlayed = data[i].totalPlayed; - this.listData.push(new Player(id, name, level, status, totalPlayed)); + this.listData.push(new Guest(id, status, totalPlayed)); } console.log("Loaded " + this.listData.length + " players."); this.render(); } generate() { console.log("Generating guest data."); - let maxPlayerCount = 12; - for (let i = 0; i < maxPlayerCount; i++) { - let level = i < 3 ? 1 : ( i < 6 ? 3 : 7); - let p = new Player(i, "Player " + i, level, false, 0); + for (let i = 0; i < new Guest(0, false).maxGuestCount; i++) { + let p = new Guest(i, false, 0); this.listData.push(p); } console.log("Generated data for " + this.listData.length + " guest"); @@ -66,4 +73,4 @@ export class GuestManager extends Manager { }); return players; } -} \ No newline at end of file +} diff --git a/src/main.js b/src/main.js index 91ac386..0e05e0d 100644 --- a/src/main.js +++ b/src/main.js @@ -1,20 +1,9 @@ -import 'notyf/notyf.min.css' -import 'bulma/css/bulma.css' -import '@fortawesome/fontawesome-free/css/all.css' -import './style.css' - +import "notyf/notyf.min.css"; +import "bulma/css/bulma.css"; +import "@fortawesome/fontawesome-free/css/all.css"; +import "./style.css"; import { GameManager } from "./game.mjs"; +import { Timer } from "./utils.mjs"; -// Court and player handling -let g = new GameManager(); - -// Game handling -document.getElementById("propose").addEventListener("click", () => { - g.propose(); -}); -document.getElementById("confirm").addEventListener("click", () => { - g.confirm(); -}); -document.getElementById("reset").addEventListener("click", () => { - g.reset(); -}); +const t = new Timer(); +const g = new GameManager(); diff --git a/src/player.mjs b/src/player.mjs index adf874d..7ca2a1f 100644 --- a/src/player.mjs +++ b/src/player.mjs @@ -42,7 +42,7 @@ function parseLineToPlayer(data) { } export class PlayerManager extends Manager { - // g = new GuestManager(); + g = new GuestManager(); constructor() { super("regular", []); @@ -108,7 +108,9 @@ export class PlayerManager extends Manager { console.log("Required players are " + count); let factor = Number(document.getElementById("skill").value); console.log("Skill normalized by a factor of " + factor + "."); - const activePlayers = this.active(factor); + let activePlayers = this.active(factor); + const activeGuests = this.g.active(factor); + activePlayers = activePlayers.concat(activeGuests); console.log("Active players are:"); console.log( activePlayers @@ -133,8 +135,7 @@ export class PlayerManager extends Manager { } } -// TODO Add load behaviour to constructor -export function addLoadBehaviour(p) { +function addLoadBehaviour(p) { const f = document.querySelector("#player-load input[type=file]"); f.addEventListener("change", () => { const file = f.files[0]; diff --git a/src/style.css b/src/style.css index 8e3b713..1bd8901 100644 --- a/src/style.css +++ b/src/style.css @@ -9,4 +9,4 @@ } table { font-size: 1.5em; -} \ No newline at end of file +} diff --git a/src/timer.js b/src/timer.js deleted file mode 100644 index 09189c0..0000000 --- a/src/timer.js +++ /dev/null @@ -1,88 +0,0 @@ -let minsPerRound = Number(sessionStorage.getItem("minsPerRound")) || 12; -let timerRunningFlag = Number(sessionStorage.getItem("timerRunningFlag")) || 0; -let deadline = - Number(sessionStorage.getItem("deadline")) || new Date().getTime(); -let clock = 0; - -function setTimer(m, s) { - let timer = document.getElementById("timer-display"); - m = m < 10 ? "0" + m : m; - s = s < 10 ? "0" + s : s; - timer.value = `${m}:${s}`; -} - -function setSessionData() { - sessionStorage.setItem("deadline", deadline); - sessionStorage.setItem("minsPerRound", minsPerRound); - sessionStorage.setItem("timerRunningFlag", timerRunningFlag); -} - -function resetTimer() { - clearInterval(clock); - let mins = Math.floor(minsPerRound); - let secs = (minsPerRound - mins) * 60; - setTimer(mins, secs); - timerRunningFlag = 0; - setSessionData(); -} - -function updateTimer(milliseconds) { - const m = Math.floor((milliseconds % (1000 * 60 * 60)) / (1000 * 60)); - const s = Math.floor((milliseconds % (1000 * 60)) / 1000); - setTimer(m, s); -} - -function refreshTimer() { - const now = new Date().getTime(); - const millisecondsToDeadline = deadline - now; - if (millisecondsToDeadline > 0) { - updateTimer(millisecondsToDeadline); - return; - } - resetTimer(); - const notification = new Notyf({ - duration: 0, - position: { x: "center", y: "top" }, - dismissible: true, - }); - notification.error("Round completed"); -} - -function startTimer(fresh) { - if (fresh) { - let now = new Date().getTime(); - const millisecondsToDeadline = minsPerRound * 60 * 1000; - deadline = now + millisecondsToDeadline; - } - timerRunningFlag = 1; - setSessionData(); - clock = setInterval(refreshTimer, 1000); -} - -window.onload = function () { - if (timerRunningFlag) startTimer(0); - else resetTimer(); - - document.getElementById("timer-start").addEventListener("click", () => { - if (timerRunningFlag != 0) return; - startTimer(1); - }); - - document.getElementById("timer-stop").addEventListener("click", () => { - resetTimer(); - }); - - document.getElementById("timer-inc").addEventListener("click", () => { - if (timerRunningFlag == 0) { - minsPerRound += 0.5; - resetTimer(); - } - }); - - document.getElementById("timer-dec").addEventListener("click", () => { - if (timerRunningFlag == 0 && minsPerRound != 0) { - minsPerRound -= 0.5; - resetTimer(); - } - }); -}; diff --git a/src/utils.mjs b/src/utils.mjs index 06a2519..97d1255 100644 --- a/src/utils.mjs +++ b/src/utils.mjs @@ -1,3 +1,95 @@ +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, listData) { this.description = description; @@ -49,3 +141,11 @@ export function shuffle(array) { } return array; } + +export function getNotifier(seconds) { + return new Notyf({ + duration: seconds * milliSecond, + position: { x: "center", y: "top" }, + dismissible: true, + }); +} -- cgit v1.3.1 From e4b599e57e076bef7caa8f5825bbca17540b571d Mon Sep 17 00:00:00 2001 From: Karan Jayachandra Date: Fri, 14 Nov 2025 15:58:36 +0100 Subject: Unified the data classes --- index.html | 10 +++--- src/court.mjs | 41 ++++++------------------ src/data.js | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/game.mjs | 78 +++++++++++++--------------------------------- src/guest.mjs | 56 +++++++++------------------------ src/player.mjs | 60 ++++++++++------------------------- src/utils.mjs | 34 ++++++++++++-------- 7 files changed, 186 insertions(+), 191 deletions(-) create mode 100644 src/data.js (limited to 'src') diff --git a/index.html b/index.html index 1117176..34f649a 100644 --- a/index.html +++ b/index.html @@ -26,14 +26,14 @@
- + - +
Court Team 1 Team 2
@@ -53,15 +53,15 @@

Courts

-
+

Regulars

-
+

Guests

-
+

Player Update

diff --git a/src/court.mjs b/src/court.mjs index 713c488..d85f05e 100644 --- a/src/court.mjs +++ b/src/court.mjs @@ -1,53 +1,32 @@ +import { Court } from "./data"; import { Manager } from "./utils.mjs"; -class Court { - constructor(id, status) { - this.id = id; - this.status = typeof status !== "undefined" ? status : true; - this.name = "Court " + (id + 1); - } - toggle() { - this.status = !this.status; - this.print(); - } - print() { - let status = this.status ? "active" : "inactive"; - console.log(this.name + " is currently " + status); - } - render() { - let color = this.status ? "is-success" : "is-danger"; - let type = `class="button is-medium ${color}"`; - return ``; - } -} - export class CourtManager extends Manager { maxCourtCount = 12; constructor() { - super("court", []); + super(); console.log("Loading court data."); - let data = JSON.parse(localStorage.getItem(this.description)); + let tempCourt = new Court(); + let data = JSON.parse(localStorage.getItem(tempCourt.description)); if (data === null || data.length != this.maxCourtCount) { - console.log("Court data unavailable: " + data); this.generate(); return; } for (let i = 0; i < this.maxCourtCount; i++) { - this.listData.push(new Court(data[i].id, data[i].status)); + let id = Number(data[i].id); + let status = Boolean(Number(data[i].status)); + this.data.push(new Court(id, status)); } - console.log("Loaded " + this.listData.length + " courts."); + console.log("Loaded " + this.data.length + " courts."); this.render(); - this.addBehaviour(); } generate() { - console.log("Generating court data."); for (let i = 0; i < this.maxCourtCount; i++) { - this.listData.push(new Court(i)); + this.data.push(new Court(i, true)); } - console.log("Generated data for " + this.listData.length + " courts"); + console.log("Generated data for " + this.data.length + " courts"); this.store(); this.render(); - this.addBehaviour(); } } diff --git a/src/data.js b/src/data.js new file mode 100644 index 0000000..4358ee6 --- /dev/null +++ b/src/data.js @@ -0,0 +1,98 @@ +class Switch { + constructor(id, description, status) { + this.id = id; + this.status = typeof status !== "undefined" ? status : false; + this.description = description; + this.name = description + " " + (id + 1); + } + toggle() { + this.status = !this.status; + this.print(); + } + print() { + let status = this.status ? "active" : "inactive"; + console.log(this.name + " is currently " + status); + } + render() { + let color = this.status ? "is-success" : "is-danger"; + let type = `class="button is-medium ${color}"`; + let id = this.description + "_" + this.id; + return ``; + } +} + +export class Court extends Switch { + constructor(id, status) { + super(id, "Court", status); + } +} + +export class Player extends Switch { + constructor(id, status, level, games, name) { + super(id, "Regular", status); + this.level = typeof level !== "undefined" ? level : 1; + this.games = typeof games !== "undefined" ? games : 0; + if (typeof name !== "undefined") { + this.name = name; + } + } +} + +const guestCategories = { + 0: { description: "Beginner", level: 1 }, + 1: { description: "Novice", level: 3 }, + 2: { description: "Intermediate", level: 6 }, +}; + +export class Guest extends Switch { + maxCount = 4; + categoryCount = 3; + + constructor(id, status, games) { + super(id, "Guest", status); + const categoryId = Math.floor(id / this.maxCount) || 0; + this.level = guestCategories[categoryId].level; + this.games = typeof games !== "undefined" ? games : 0; + const guestNumber = (id % this.maxCount) + 1; + this.name = guestCategories[categoryId].description + " " + guestNumber; + } +} + +export class Team { + constructor(playerOne, playerTwo) { + this.playerOne = playerOne; + this.playerTwo = playerTwo; + } + print() { + console.log("Team consists of:"); + this.playerOne.print(); + this.playerTwo.print(); + } + render() { + let p1 = `${this.playerOne}`; + let p2 = `${this.playerTwo}`; + return p1 + p2; + } +} + +export class Game extends Switch { + constructor(id, status, teamOne, teamTwo) { + super(id, "Game", status); + this.teamOne = teamOne; + this.teamTwo = teamTwo; + } + print() { + super.print(); + let teamOne = this.teamOne.playerOne + " and " + this.teamOne.playerTwo; + let teamTwo = this.teamTwo.playerOne + " and " + this.teamTwo.playerTwo; + console.log(teamOne + " is playing against " + teamTwo); + } + render() { + let blockedState = this.teamOne.playerOne === "RESERVED"; + let type = blockedState ? `class="is-danger is-dark"` : ``; + let court = `${ + this.id + 1 + }`; + return `${court}${this.teamOne.render()}${this.teamTwo.render()}`; + } +} diff --git a/src/game.mjs b/src/game.mjs index 864f255..9a2a921 100644 --- a/src/game.mjs +++ b/src/game.mjs @@ -2,48 +2,14 @@ import { Notyf } from "notyf"; import { Manager } from "./utils.mjs"; import { CourtManager } from "./court.mjs"; import { PlayerManager } from "./player.mjs"; +import { Team, Game } from "./data"; -class Team { - constructor(playerOne, playerTwo) { - this.playerOne = playerOne; - this.playerTwo = playerTwo; - } - print() { - console.log(this.playerOne + " and " + this.playerTwo); - } - render() { - let p1 = `${this.playerOne}`; - let p2 = `${this.playerTwo}`; - return p1 + p2; - } -} - -class Game { - constructor(id, teamOne, teamTwo, status) { - this.id = id; - this.teamOne = teamOne; - this.teamTwo = teamTwo; - this.status = typeof status !== "undefined" ? status : false; - } - print() { - let teamOne = this.teamOne.playerOne + " and " + this.teamOne.playerTwo; - let teamTwo = this.teamTwo.playerOne + " and " + this.teamTwo.playerTwo; - console.log(teamOne + " is playing against " + teamTwo); - } - render() { - let blockedState = this.teamOne.playerOne === "RESERVED"; - let type = blockedState ? `class="is-danger is-dark"` : ``; - return `${ - this.id + 1 - }${this.teamOne.render()}${this.teamTwo.render()}`; - } -} function generateDummyGames(courts, description) { let team = new Team(description, description); let games = []; for (const court of courts) { - let game = new Game(court.id, team, team); + let game = new Game(court.id, false, team, team); games.push(game); } return games; @@ -54,10 +20,11 @@ export class GameManager extends Manager { players = new PlayerManager(); constructor() { - super("game", []); + super(); this.round = Number(localStorage.getItem("round")) || 0; console.log("Loading game data."); - let data = JSON.parse(localStorage.getItem(this.description)); + let tempGame = new Game(); + let data = JSON.parse(localStorage.getItem(tempGame.description)); if (data === null || data.length === 0) { console.log("Game data unavailable: " + data); this.generate(); @@ -74,29 +41,28 @@ export class GameManager extends Manager { data[i].teamTwo.playerTwo ); let status = Boolean(data[i].status); - this.listData.push(new Game(id, teamOne, teamTwo, status)); + this.data.push(new Game(id, status, teamOne, teamTwo)); } - console.log("Loaded " + this.listData.length + " games."); + console.log("Loaded " + this.data.length + " games."); this.render(); addGameBehaviour(this); } isConfirmed() { - return this.listData[0].status; + return this.data[0].status; } generate() { console.log("Generating the dummy round."); - this.listData = generateDummyGames(this.courts.listData, "---"); - console.log("Loaded " + this.listData.length + " dummy round."); - for (let i = 0; i < this.listData.length; i++) { - this.listData[i].status = true; + this.data = generateDummyGames(this.courts.data, "---"); + console.log("Loaded " + this.data.length + " dummy round."); + for (let i = 0; i < this.data.length; i++) { + this.data[i].status = true; } - console.log(this.listData); this.store(); this.render(); } addBehaviour() { let description = this.isConfirmed() ? "Round " + this.round : "Proposal"; - document.getElementById("game_description").innerHTML = description; + document.getElementById("Game_description").innerHTML = description; } getBlockedGames() { const inactiveCourts = this.courts.inactive(); @@ -114,7 +80,7 @@ export class GameManager extends Manager { const courtPlayers = players.slice(startIndex, endIndex); const team_1 = new Team(courtPlayers[0].name, courtPlayers[3].name); const team_2 = new Team(courtPlayers[1].name, courtPlayers[2].name); - const game = new Game(courts[index].id, team_1, team_2); + const game = new Game(courts[index].id, false, team_1, team_2); game.print(); games.push(game); } @@ -123,22 +89,22 @@ export class GameManager extends Manager { propose() { console.log("Proposing new games!"); let possibleMatches = getMatchCount( - this.players.listData.concat(this.players.g.listData), - this.courts.listData + this.players.data.concat(this.players.g.data), + this.courts.data ); console.log("Total possible matches are " + possibleMatches + "."); - this.listData = this.getBlockedGames(); + this.data = this.getBlockedGames(); const activeCourts = this.courts.active(); const unusedCourts = activeCourts.slice(possibleMatches + 1); - this.listData = this.listData.concat(this.inactive(unusedCourts)); + this.data = this.data.concat(this.inactive(unusedCourts)); const usedCourts = activeCourts.slice(0, possibleMatches); let requiredPlayerCount = possibleMatches * 4; const selectedPlayers = this.players.propose(requiredPlayerCount); console.log("The matches are:"); - this.listData = this.listData.concat( + this.data = this.data.concat( this.active(usedCourts, selectedPlayers) ); - this.listData.sort((a, b) => a.id - b.id); + this.data.sort((a, b) => a.id - b.id); this.render(); } confirm() { @@ -150,8 +116,8 @@ export class GameManager extends Manager { console.log("Confirm the proposal for round " + this.round + "."); this.round += 1; localStorage.setItem("round", this.round); - for (let i = 0; i < this.listData.length; i++) { - this.listData[i].status = true; + for (let i = 0; i < this.data.length; i++) { + this.data[i].status = true; } this.store(); this.render(); diff --git a/src/guest.mjs b/src/guest.mjs index c82d115..57eb237 100644 --- a/src/guest.mjs +++ b/src/guest.mjs @@ -1,65 +1,37 @@ import { Manager } from "./utils.mjs"; - -export class Guest { - maxGuestCount = 12; - categoryCount = 3; - - categories = { - 0: { description: "Beginner", level: 1 }, - 1: { description: "Novice", level: 3 }, - 2: { description: "Intermediate", level: 6 }, - }; - - constructor(id, status, totalPlayed) { - this.id = id; - this.status = typeof status !== "undefined" ? status : false; - const categoryId = Math.floor(id / (12 / this.categoryCount)); - const guestIdentifier = (id % (12 / this.categoryCount)) + 1; - this.name = this.categories[categoryId].description + " " + guestIdentifier; - this.level = this.categories[categoryId].level; - this.totalPlayed = typeof totalPlayed !== "undefined" ? status : 0; - } - toggle() { - this.status = !this.status; - this.print(); - } - print() { - let status = this.status ? "active" : "inactive"; - console.log(this.name + " is currently " + status); - } - render() { - let color = this.status ? "is-success" : "is-danger"; - let type = `class="button is-medium ${color}"`; - return ``; - } -} +import { Guest } from "./data"; export class GuestManager extends Manager { constructor() { super("guest", []); console.log("Loading guest data."); - let data = JSON.parse(localStorage.getItem(this.description)); + let tempGuest = new Guest(); + let data = JSON.parse(localStorage.getItem(tempGuest.description)); if (data === null || data.length === 0) { console.log("Guest data unavailable: " + data); this.generate(); return; } + console.log(tempGuest.description); for (let i = 0; i < data.length; i++) { + console.log(data[i]); let id = Number(data[i].id); - let status = data[i].status; - let totalPlayed = data[i].totalPlayed; - this.listData.push(new Guest(id, status, totalPlayed)); + let status = Boolean(Number(data[i].status)); + let games = data[i].games; + this.data.push(new Guest(id, status, games)); } - console.log("Loaded " + this.listData.length + " players."); + console.log("Loaded " + this.data.length + " players."); this.render(); } generate() { console.log("Generating guest data."); - for (let i = 0; i < new Guest(0, false).maxGuestCount; i++) { + const tempGuest = new Guest(0, false); + const totalGuestCount = tempGuest.maxCount * tempGuest.categoryCount; + for (let i = 0; i < totalGuestCount; i++) { let p = new Guest(i, false, 0); - this.listData.push(p); + this.data.push(p); } - console.log("Generated data for " + this.listData.length + " guest"); + console.log("Generated data for " + this.data.length + " guest"); this.store(); this.render(); } diff --git a/src/player.mjs b/src/player.mjs index 7ca2a1f..06b1abd 100644 --- a/src/player.mjs +++ b/src/player.mjs @@ -1,53 +1,24 @@ import { GuestManager } from "./guest.mjs"; -import { shuffle, Manager } from "./utils.mjs"; +import { shuffle, Manager, randomLevel, randomStatus } from "./utils.mjs"; +import { Player } from "./data"; -class Player { - constructor(id, name, level, status, totalPlayed) { - this.id = id; - this.status = typeof status !== "undefined" ? status : false; - this.name = name; - this.level = typeof level !== "undefined" ? level : 1; - this.totalPlayed = typeof totalPlayed !== "undefined" ? status : 0; - } - toggle() { - this.status = !this.status; - this.print(); - } - print() { - let status = this.status ? "active" : "inactive"; - console.log(this.name + " is currently " + status); - } - render() { - let color = this.status ? "is-success" : "is-danger"; - let type = `class="button is-medium ${color}"`; - return ``; - } -} - -function randomLevel() { - const max_level = 10; - return Math.floor(Math.random() * max_level + 1); -} - -function randomStatus() { - return Math.random() < 0.5; -} function parseLineToPlayer(data) { var info = data.split(","); var id = Number(info[0].trim()); var name = info[1].trim() + " " + info[2].trim(); var level = Number(info[3].trim()); - return new Player(id, name, level, true, 0); + return new Player(id, true, level, 0, name); } export class PlayerManager extends Manager { g = new GuestManager(); constructor() { - super("regular", []); + super(); console.log("Loading player data."); - let data = JSON.parse(localStorage.getItem(this.description)); + let tempPlayer = new Player(); + let data = JSON.parse(localStorage.getItem(tempPlayer.description)); if (data === null || data.length === 0) { console.log("Player data unavailable: " + data); this.generate(); @@ -56,12 +27,12 @@ export class PlayerManager extends Manager { for (let i = 0; i < data.length; i++) { let id = Number(data[i].id); let name = data[i].name; - let level = data[i].level; - let status = data[i].status; - let totalPlayed = data[i].totalPlayed; - this.listData.push(new Player(id, name, level, status, totalPlayed)); + let level = Number(data[i].level); + let status = Boolean(Number(data[i].status)); + let games = Number(data[i].games); + this.data.push(new Player(id, status, level, games, name)); } - console.log("Loaded " + this.listData.length + " players."); + console.log("Loaded " + this.data.length + " players."); this.render(); this.addBehaviour(); addLoadBehaviour(this); @@ -70,10 +41,11 @@ export class PlayerManager extends Manager { console.log("Generating player data."); let maxPlayerCount = 71; for (let i = 0; i < maxPlayerCount; i++) { - let p = new Player(i, "Player " + i, randomLevel(), randomStatus(), 0); - this.listData.push(p); + let p = new Player(i, randomStatus(), randomLevel()); + console.log(p); + this.data.push(p); } - console.log("Generated data for " + this.listData.length + " players"); + console.log("Generated data for " + this.data.length + " players"); this.store(); this.render(); } @@ -90,7 +62,7 @@ export class PlayerManager extends Manager { for (var i = 0; i < players.length; i++) { players[i].print(); } - this.listData = players; + this.data = players; this.store(); this.render(); } diff --git a/src/utils.mjs b/src/utils.mjs index 97d1255..2fca3f5 100644 --- a/src/utils.mjs +++ b/src/utils.mjs @@ -91,31 +91,30 @@ function addTimerBehaviour(t) { } export class Manager { - constructor(description, listData) { - this.description = description; - this.listData = listData; - this.count = listData.length; + constructor() { + this.data = []; + this.count = this.data.length; } store() { - let stringData = JSON.stringify(this.listData); - localStorage.setItem(this.description, stringData); + let stringData = JSON.stringify(this.data); + localStorage.setItem(this.data[0].description, stringData); } render() { - let renderedHTML = this.listData + let renderedHTML = this.data .map((i) => { return i.render(); }) .join(""); - let elementId = this.description + "_list"; + let elementId = this.data[0].description + "_list"; document.getElementById(elementId).innerHTML = renderedHTML; this.addBehaviour(); } addBehaviour() { - for (let idx = 0; idx < this.listData.length; ++idx) { - const elementId = this.description + "_" + this.listData[idx].id; + 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.listData[idx].toggle(); + this.data[idx].toggle(); this.store(); p.classList.toggle("is-success"); p.classList.toggle("is-danger"); @@ -123,12 +122,12 @@ export class Manager { } } active() { - return this.listData.filter(function (c) { + return this.data.filter(function (c) { return c.status; }); } inactive() { - return this.listData.filter(function (c) { + return this.data.filter(function (c) { return !c.status; }); } @@ -142,6 +141,15 @@ export function shuffle(array) { 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, -- cgit v1.3.1 From 27b3a8f4fe5f6259983a7bcf44e7e987f8e19e09 Mon Sep 17 00:00:00 2001 From: Karan Jayachandra Date: Fri, 14 Nov 2025 17:15:13 +0100 Subject: Simplified the file structure --- src/court.js | 139 +++++++++++++++++++++++++++++++++++++++++++ src/court.mjs | 32 ---------- src/game.mjs | 164 --------------------------------------------------- src/guest.mjs | 48 --------------- src/main.js | 143 ++++++++++++++++++++++++++++++++++++++++++++- src/player.mjs | 123 -------------------------------------- src/utils.js | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils.mjs | 159 ------------------------------------------------- 8 files changed, 461 insertions(+), 529 deletions(-) create mode 100644 src/court.js delete mode 100644 src/court.mjs delete mode 100644 src/game.mjs delete mode 100644 src/guest.mjs delete mode 100644 src/player.mjs create mode 100644 src/utils.js delete mode 100644 src/utils.mjs (limited to 'src') diff --git a/src/court.js b/src/court.js new file mode 100644 index 0000000..31e828d --- /dev/null +++ b/src/court.js @@ -0,0 +1,139 @@ +import { Court, Guest, Player } from "./data"; +import { shuffle, Manager, randomLevel, randomStatus } from "./utils"; + +export class CourtManager extends Manager { + constructor() { + super("Court", 12); + } + createItem(i) { + return new Court(i, randomStatus()); + } + loadItem(data) { + let id = Number(data.id); + let status = Boolean(Number(data.status)); + return new Court(id, status); + } +} + +export class GuestManager extends Manager { + constructor() { + super("Guest", 12); + } + createItem(i) { + return new Guest(i, randomStatus()); + } + loadItem(data) { + let id = Number(data.id); + let status = Boolean(Number(data.status)); + let games = data.games; + return new Guest(id, status, games); + } + 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; + } +} + +export class PlayerManager extends Manager { + constructor() { + super("Regular", 71); + addLoadBehaviour(this); + this.g = new GuestManager(); + } + createItem(i) { + return new Player(i, randomStatus(), randomLevel()); + } + loadItem(data) { + let id = Number(data.id); + let name = data.name; + let level = Number(data.level); + let status = Boolean(Number(data.status)); + let games = Number(data.games); + return new Player(id, status, level, games, name); + } + import(data) { + var lines = data.split("\n"); + var players = []; + for (var i = 1; i < lines.length; i++) { + if (lines[i] == undefined || lines[i].trim() == "") { + continue; + } + players.push(parseLineToPlayer(lines[i])); + } + console.log("Loaded " + players.length + " Players"); + for (var i = 0; i < players.length; i++) { + players[i].print(); + } + this.data = players; + this.store(); + this.render(); + } + 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; + } +} + +function parseLineToPlayer(data) { + var info = data.split(","); + var id = Number(info[0].trim()); + var name = info[1].trim() + " " + info[2].trim(); + var level = Number(info[3].trim()); + return new Player(id, true, level, 0, name); +} + +function addLoadBehaviour(p) { + const f = document.querySelector("#player-load input[type=file]"); + f.addEventListener("change", () => { + const file = f.files[0]; + let importData; + console.log("Loading data from " + file.name); + const reader = new FileReader(); + reader.onload = function (e) { + importData = reader.result; + p.import(importData); + }; + reader.readAsText(file); + }); +} diff --git a/src/court.mjs b/src/court.mjs deleted file mode 100644 index d85f05e..0000000 --- a/src/court.mjs +++ /dev/null @@ -1,32 +0,0 @@ -import { Court } from "./data"; -import { Manager } from "./utils.mjs"; - -export class CourtManager extends Manager { - maxCourtCount = 12; - - constructor() { - super(); - console.log("Loading court data."); - let tempCourt = new Court(); - let data = JSON.parse(localStorage.getItem(tempCourt.description)); - if (data === null || data.length != this.maxCourtCount) { - this.generate(); - return; - } - for (let i = 0; i < this.maxCourtCount; i++) { - let id = Number(data[i].id); - let status = Boolean(Number(data[i].status)); - this.data.push(new Court(id, status)); - } - console.log("Loaded " + this.data.length + " courts."); - this.render(); - } - generate() { - for (let i = 0; i < this.maxCourtCount; i++) { - this.data.push(new Court(i, true)); - } - console.log("Generated data for " + this.data.length + " courts"); - this.store(); - this.render(); - } -} diff --git a/src/game.mjs b/src/game.mjs deleted file mode 100644 index 9a2a921..0000000 --- a/src/game.mjs +++ /dev/null @@ -1,164 +0,0 @@ -import { Notyf } from "notyf"; -import { Manager } from "./utils.mjs"; -import { CourtManager } from "./court.mjs"; -import { PlayerManager } from "./player.mjs"; -import { Team, Game } from "./data"; - - -function generateDummyGames(courts, description) { - let team = new Team(description, description); - let games = []; - for (const court of courts) { - let game = new Game(court.id, false, team, team); - games.push(game); - } - return games; -} - -export class GameManager extends Manager { - courts = new CourtManager(); - players = new PlayerManager(); - - constructor() { - super(); - this.round = Number(localStorage.getItem("round")) || 0; - console.log("Loading game data."); - let tempGame = new Game(); - let data = JSON.parse(localStorage.getItem(tempGame.description)); - if (data === null || data.length === 0) { - console.log("Game data unavailable: " + data); - this.generate(); - return; - } - for (let i = 0; i < data.length; i++) { - let id = Number(data[i].id); - let teamOne = new Team( - data[i].teamOne.playerOne, - data[i].teamOne.playerTwo - ); - let teamTwo = new Team( - data[i].teamTwo.playerOne, - data[i].teamTwo.playerTwo - ); - let status = Boolean(data[i].status); - this.data.push(new Game(id, status, teamOne, teamTwo)); - } - console.log("Loaded " + this.data.length + " games."); - this.render(); - addGameBehaviour(this); - } - isConfirmed() { - return this.data[0].status; - } - generate() { - console.log("Generating the dummy round."); - this.data = generateDummyGames(this.courts.data, "---"); - console.log("Loaded " + this.data.length + " dummy round."); - for (let i = 0; i < this.data.length; i++) { - this.data[i].status = true; - } - this.store(); - this.render(); - } - addBehaviour() { - let description = this.isConfirmed() ? "Round " + this.round : "Proposal"; - document.getElementById("Game_description").innerHTML = description; - } - getBlockedGames() { - const inactiveCourts = this.courts.inactive(); - console.log("Total reserved courts are " + inactiveCourts.length + "."); - return generateDummyGames(inactiveCourts, "RESERVED"); - } - inactive(courts) { - return generateDummyGames(courts, "---"); - } - active(courts, players) { - let games = []; - for (let index = 0; index < courts.length; index++) { - const startIndex = 4 * index; - const endIndex = startIndex + 4; - const courtPlayers = players.slice(startIndex, endIndex); - const team_1 = new Team(courtPlayers[0].name, courtPlayers[3].name); - 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); - } - return games; - } - propose() { - console.log("Proposing new games!"); - let possibleMatches = getMatchCount( - this.players.data.concat(this.players.g.data), - this.courts.data - ); - console.log("Total possible matches are " + possibleMatches + "."); - this.data = this.getBlockedGames(); - const activeCourts = this.courts.active(); - const unusedCourts = activeCourts.slice(possibleMatches + 1); - this.data = this.data.concat(this.inactive(unusedCourts)); - const usedCourts = activeCourts.slice(0, possibleMatches); - let requiredPlayerCount = possibleMatches * 4; - const selectedPlayers = this.players.propose(requiredPlayerCount); - console.log("The matches are:"); - this.data = this.data.concat( - this.active(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!"); - return; - } - console.log("Confirm the proposal for round " + this.round + "."); - this.round += 1; - localStorage.setItem("round", this.round); - for (let i = 0; i < this.data.length; i++) { - this.data[i].status = true; - } - this.store(); - this.render(); - document.getElementById("timer-start").click(); - const notification = new Notyf(); - notification.success("Round confirmed!"); - } - reset() { - localStorage.removeItem("round"); - localStorage.removeItem(this.description); - localStorage.removeItem(this.courts.description); - document.getElementById("timer-stop").click(); - window.location.reload(); - const notification = new Notyf(); - notification.error("Session has been reset!"); - } -} - -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 addGameBehaviour(g) { - document.getElementById("propose").addEventListener("click", () => { - g.propose(); - }); - document.getElementById("confirm").addEventListener("click", () => { - g.confirm(); - }); - document.getElementById("reset").addEventListener("click", () => { - g.reset(); - }); -} diff --git a/src/guest.mjs b/src/guest.mjs deleted file mode 100644 index 57eb237..0000000 --- a/src/guest.mjs +++ /dev/null @@ -1,48 +0,0 @@ -import { Manager } from "./utils.mjs"; -import { Guest } from "./data"; - -export class GuestManager extends Manager { - constructor() { - super("guest", []); - console.log("Loading guest data."); - let tempGuest = new Guest(); - let data = JSON.parse(localStorage.getItem(tempGuest.description)); - if (data === null || data.length === 0) { - console.log("Guest data unavailable: " + data); - this.generate(); - return; - } - console.log(tempGuest.description); - for (let i = 0; i < data.length; i++) { - console.log(data[i]); - let id = Number(data[i].id); - let status = Boolean(Number(data[i].status)); - let games = data[i].games; - this.data.push(new Guest(id, status, games)); - } - console.log("Loaded " + this.data.length + " players."); - this.render(); - } - generate() { - console.log("Generating guest data."); - const tempGuest = new Guest(0, false); - const totalGuestCount = tempGuest.maxCount * tempGuest.categoryCount; - for (let i = 0; i < totalGuestCount; i++) { - let p = new Guest(i, false, 0); - this.data.push(p); - } - console.log("Generated data for " + this.data.length + " guest"); - this.store(); - this.render(); - } - 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; - } -} diff --git a/src/main.js b/src/main.js index 0e05e0d..d66ddb6 100644 --- a/src/main.js +++ b/src/main.js @@ -2,8 +2,145 @@ import "notyf/notyf.min.css"; import "bulma/css/bulma.css"; import "@fortawesome/fontawesome-free/css/all.css"; import "./style.css"; -import { GameManager } from "./game.mjs"; -import { Timer } from "./utils.mjs"; +import { Manager, Timer } from "./utils"; +import { CourtManager, PlayerManager } from "./court"; +import { Team, Game } from "./data"; + +export class GameManager extends Manager { + t = new Timer(); + courts = new CourtManager(); + players = new PlayerManager(); + + constructor() { + super("Game", 12); + this.round = Number(localStorage.getItem("round")) || 0; + this.render(); + addGameBehaviour(this); + } + createItem(i, description) { + if (typeof description === "undefined") { + description = "---"; + } + let team = new Team(description, description); + return new Game(i, true, team, team); + } + loadItem(data) { + let id = Number(data.id); + let teamOne = new Team(data.teamOne.playerOne, data.teamOne.playerTwo); + let teamTwo = new Team(data.teamTwo.playerOne, data.teamTwo.playerTwo); + let status = Boolean(data.status); + return new Game(id, status, teamOne, teamTwo); + } + addBehaviour() { + let description = this.isConfirmed() ? "Round " + this.round : "Proposal"; + document.getElementById("Game_description").innerHTML = description; + } + isConfirmed() { + return this.data[0].status; + } + getBlockedGames() { + 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")); + } + return games; + } + inactive(courts) { + let games = []; + for (let court of courts) { + games.push(this.createItem(court.id)); + } + return games; + } + active(courts, players) { + let games = []; + for (let index = 0; index < courts.length; index++) { + const startIndex = 4 * index; + const endIndex = startIndex + 4; + const courtPlayers = players.slice(startIndex, endIndex); + const team_1 = new Team(courtPlayers[0].name, courtPlayers[3].name); + 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); + } + return games; + } + propose() { + console.log("Proposing new games!"); + let possibleMatches = getMatchCount( + this.players.data.concat(this.players.g.data), + this.courts.data + ); + console.log("Total possible matches are " + possibleMatches + "."); + this.data = this.getBlockedGames(); + const activeCourts = this.courts.active(); + const unusedCourts = activeCourts.slice(possibleMatches + 1); + this.data = this.data.concat(this.inactive(unusedCourts)); + const usedCourts = activeCourts.slice(0, possibleMatches); + let requiredPlayerCount = possibleMatches * 4; + const selectedPlayers = this.players.propose(requiredPlayerCount); + console.log("The matches are:"); + this.data = this.data.concat(this.active(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!"); + return; + } + console.log("Confirm the proposal for round " + this.round + "."); + this.round += 1; + localStorage.setItem("round", this.round); + for (let i = 0; i < this.data.length; i++) { + this.data[i].status = true; + } + this.store(); + this.render(); + document.getElementById("timer-start").click(); + const notification = new Notyf(); + notification.success("Round confirmed!"); + } + reset() { + localStorage.removeItem("round"); + localStorage.removeItem(this.description); + localStorage.removeItem(this.courts.description); + document.getElementById("timer-stop").click(); + window.location.reload(); + const notification = new Notyf(); + notification.error("Session has been reset!"); + } +} + +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 addGameBehaviour(g) { + document.getElementById("propose").addEventListener("click", () => { + g.propose(); + }); + document.getElementById("confirm").addEventListener("click", () => { + g.confirm(); + }); + document.getElementById("reset").addEventListener("click", () => { + g.reset(); + }); +} -const t = new Timer(); const g = new GameManager(); diff --git a/src/player.mjs b/src/player.mjs deleted file mode 100644 index 06b1abd..0000000 --- a/src/player.mjs +++ /dev/null @@ -1,123 +0,0 @@ -import { GuestManager } from "./guest.mjs"; -import { shuffle, Manager, randomLevel, randomStatus } from "./utils.mjs"; -import { Player } from "./data"; - - -function parseLineToPlayer(data) { - var info = data.split(","); - var id = Number(info[0].trim()); - var name = info[1].trim() + " " + info[2].trim(); - var level = Number(info[3].trim()); - return new Player(id, true, level, 0, name); -} - -export class PlayerManager extends Manager { - g = new GuestManager(); - - constructor() { - super(); - console.log("Loading player data."); - let tempPlayer = new Player(); - let data = JSON.parse(localStorage.getItem(tempPlayer.description)); - if (data === null || data.length === 0) { - console.log("Player data unavailable: " + data); - this.generate(); - return; - } - for (let i = 0; i < data.length; i++) { - let id = Number(data[i].id); - let name = data[i].name; - let level = Number(data[i].level); - let status = Boolean(Number(data[i].status)); - let games = Number(data[i].games); - this.data.push(new Player(id, status, level, games, name)); - } - console.log("Loaded " + this.data.length + " players."); - this.render(); - this.addBehaviour(); - addLoadBehaviour(this); - } - generate() { - console.log("Generating player data."); - let maxPlayerCount = 71; - for (let i = 0; i < maxPlayerCount; i++) { - let p = new Player(i, randomStatus(), randomLevel()); - console.log(p); - this.data.push(p); - } - console.log("Generated data for " + this.data.length + " players"); - this.store(); - this.render(); - } - import(data) { - var lines = data.split("\n"); - var players = []; - for (var i = 1; i < lines.length; i++) { - if (lines[i] == undefined || lines[i].trim() == "") { - continue; - } - players.push(parseLineToPlayer(lines[i])); - } - console.log("Loaded " + players.length + " Players"); - for (var i = 0; i < players.length; i++) { - players[i].print(); - } - this.data = players; - this.store(); - this.render(); - } - 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; - } -} - -function addLoadBehaviour(p) { - const f = document.querySelector("#player-load input[type=file]"); - f.addEventListener("change", () => { - const file = f.files[0]; - let importData; - console.log("Loading data from " + file.name); - const reader = new FileReader(); - reader.onload = function (e) { - importData = reader.result; - p.import(importData); - }; - reader.readAsText(file); - }); -} diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..a8d4f07 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,182 @@ +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, + }); +} diff --git a/src/utils.mjs b/src/utils.mjs deleted file mode 100644 index 2fca3f5..0000000 --- a/src/utils.mjs +++ /dev/null @@ -1,159 +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() { - this.data = []; - this.count = this.data.length; - } - 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, - }); -} -- cgit v1.3.1 From baba5a39de4f699141438b122905888acd50ea53 Mon Sep 17 00:00:00 2001 From: Karan Jayachandra Date: Fri, 14 Nov 2025 17:16:37 +0100 Subject: Cleaned up the manager --- src/court.js | 139 ---------------------------------------------------------- src/main.js | 2 +- src/manage.js | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 140 deletions(-) delete mode 100644 src/court.js create mode 100644 src/manage.js (limited to 'src') diff --git a/src/court.js b/src/court.js deleted file mode 100644 index 31e828d..0000000 --- a/src/court.js +++ /dev/null @@ -1,139 +0,0 @@ -import { Court, Guest, Player } from "./data"; -import { shuffle, Manager, randomLevel, randomStatus } from "./utils"; - -export class CourtManager extends Manager { - constructor() { - super("Court", 12); - } - createItem(i) { - return new Court(i, randomStatus()); - } - loadItem(data) { - let id = Number(data.id); - let status = Boolean(Number(data.status)); - return new Court(id, status); - } -} - -export class GuestManager extends Manager { - constructor() { - super("Guest", 12); - } - createItem(i) { - return new Guest(i, randomStatus()); - } - loadItem(data) { - let id = Number(data.id); - let status = Boolean(Number(data.status)); - let games = data.games; - return new Guest(id, status, games); - } - 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; - } -} - -export class PlayerManager extends Manager { - constructor() { - super("Regular", 71); - addLoadBehaviour(this); - this.g = new GuestManager(); - } - createItem(i) { - return new Player(i, randomStatus(), randomLevel()); - } - loadItem(data) { - let id = Number(data.id); - let name = data.name; - let level = Number(data.level); - let status = Boolean(Number(data.status)); - let games = Number(data.games); - return new Player(id, status, level, games, name); - } - import(data) { - var lines = data.split("\n"); - var players = []; - for (var i = 1; i < lines.length; i++) { - if (lines[i] == undefined || lines[i].trim() == "") { - continue; - } - players.push(parseLineToPlayer(lines[i])); - } - console.log("Loaded " + players.length + " Players"); - for (var i = 0; i < players.length; i++) { - players[i].print(); - } - this.data = players; - this.store(); - this.render(); - } - 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; - } -} - -function parseLineToPlayer(data) { - var info = data.split(","); - var id = Number(info[0].trim()); - var name = info[1].trim() + " " + info[2].trim(); - var level = Number(info[3].trim()); - return new Player(id, true, level, 0, name); -} - -function addLoadBehaviour(p) { - const f = document.querySelector("#player-load input[type=file]"); - f.addEventListener("change", () => { - const file = f.files[0]; - let importData; - console.log("Loading data from " + file.name); - const reader = new FileReader(); - reader.onload = function (e) { - importData = reader.result; - p.import(importData); - }; - reader.readAsText(file); - }); -} diff --git a/src/main.js b/src/main.js index d66ddb6..a0ec6bc 100644 --- a/src/main.js +++ b/src/main.js @@ -3,7 +3,7 @@ import "bulma/css/bulma.css"; import "@fortawesome/fontawesome-free/css/all.css"; import "./style.css"; import { Manager, Timer } from "./utils"; -import { CourtManager, PlayerManager } from "./court"; +import { CourtManager, PlayerManager } from "./manage"; import { Team, Game } from "./data"; export class GameManager extends Manager { diff --git a/src/manage.js b/src/manage.js new file mode 100644 index 0000000..31e828d --- /dev/null +++ b/src/manage.js @@ -0,0 +1,139 @@ +import { Court, Guest, Player } from "./data"; +import { shuffle, Manager, randomLevel, randomStatus } from "./utils"; + +export class CourtManager extends Manager { + constructor() { + super("Court", 12); + } + createItem(i) { + return new Court(i, randomStatus()); + } + loadItem(data) { + let id = Number(data.id); + let status = Boolean(Number(data.status)); + return new Court(id, status); + } +} + +export class GuestManager extends Manager { + constructor() { + super("Guest", 12); + } + createItem(i) { + return new Guest(i, randomStatus()); + } + loadItem(data) { + let id = Number(data.id); + let status = Boolean(Number(data.status)); + let games = data.games; + return new Guest(id, status, games); + } + 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; + } +} + +export class PlayerManager extends Manager { + constructor() { + super("Regular", 71); + addLoadBehaviour(this); + this.g = new GuestManager(); + } + createItem(i) { + return new Player(i, randomStatus(), randomLevel()); + } + loadItem(data) { + let id = Number(data.id); + let name = data.name; + let level = Number(data.level); + let status = Boolean(Number(data.status)); + let games = Number(data.games); + return new Player(id, status, level, games, name); + } + import(data) { + var lines = data.split("\n"); + var players = []; + for (var i = 1; i < lines.length; i++) { + if (lines[i] == undefined || lines[i].trim() == "") { + continue; + } + players.push(parseLineToPlayer(lines[i])); + } + console.log("Loaded " + players.length + " Players"); + for (var i = 0; i < players.length; i++) { + players[i].print(); + } + this.data = players; + this.store(); + this.render(); + } + 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; + } +} + +function parseLineToPlayer(data) { + var info = data.split(","); + var id = Number(info[0].trim()); + var name = info[1].trim() + " " + info[2].trim(); + var level = Number(info[3].trim()); + return new Player(id, true, level, 0, name); +} + +function addLoadBehaviour(p) { + const f = document.querySelector("#player-load input[type=file]"); + f.addEventListener("change", () => { + const file = f.files[0]; + let importData; + console.log("Loading data from " + file.name); + const reader = new FileReader(); + reader.onload = function (e) { + importData = reader.result; + p.import(importData); + }; + reader.readAsText(file); + }); +} -- cgit v1.3.1 From 06d6cf87acfd4582beb6beb314c6f1d7c3fe9675 Mon Sep 17 00:00:00 2001 From: Karan Jayachandra Date: Fri, 14 Nov 2025 17:46:28 +0100 Subject: Simplified the file even more though longer --- src/main.js | 116 +++++++++++++++++++++++-------------- src/manage.js | 130 +++++++++++++++++++++++++++-------------- src/timer.js | 89 ++++++++++++++++++++++++++++ src/utils.js | 182 ---------------------------------------------------------- 4 files changed, 248 insertions(+), 269 deletions(-) create mode 100644 src/timer.js delete mode 100644 src/utils.js (limited to 'src') 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, - }); -} -- cgit v1.3.1 From 0aab565ffb594069abaf6b3e25c25737523a7bf3 Mon Sep 17 00:00:00 2001 From: Karan Jayachandra Date: Fri, 14 Nov 2025 17:57:28 +0100 Subject: Only the history is pending --- src/main.js | 24 ++++++++++++++++-------- src/timer.js | 13 ++++--------- 2 files changed, 20 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/main.js b/src/main.js index 7e9f988..4c88167 100644 --- a/src/main.js +++ b/src/main.js @@ -3,7 +3,7 @@ import "bulma/css/bulma.css"; import "@fortawesome/fontawesome-free/css/all.css"; import "./style.css"; import { Notyf } from "notyf"; -import { Timer } from "./utils"; +import { Timer } from "./timer"; import { Team, Game } from "./data"; import { Manager, CourtManager, PlayerManager, GuestManager } from "./manage"; @@ -74,10 +74,17 @@ export class GameManager extends Manager { 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."); + 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); + console.log( + "There are a total of " + activeCourtCount + " courts available." + ); + let possibleMatches = Math.min( + Math.floor(activePlayerCount / 4), + activeCourtCount + ); return possibleMatches; } selectPlayers(count) { @@ -136,20 +143,19 @@ export class GameManager extends Manager { for (let i = 0; i < this.data.length; i++) { this.data[i].status = true; } + // Increment the number of games played this.store(); this.render(); document.getElementById("timer-start").click(); - const notification = new Notyf(); - notification.success("Round confirmed!"); } reset() { localStorage.removeItem("round"); localStorage.removeItem(this.description); localStorage.removeItem(this.courts.description); + // Clear the number of games played + localStorage.removeItem(this.guests.description); document.getElementById("timer-stop").click(); window.location.reload(); - const notification = new Notyf(); - notification.error("Session has been reset!"); } } @@ -167,9 +173,11 @@ function addGameBehaviour(g) { }); document.getElementById("confirm").addEventListener("click", () => { g.confirm(); + getNotifier().success("Round confirmed!"); }); document.getElementById("reset").addEventListener("click", () => { g.reset(); + getNotifier().error("Session has been reset!"); }); } diff --git a/src/timer.js b/src/timer.js index 7c70550..c00ffdc 100644 --- a/src/timer.js +++ b/src/timer.js @@ -2,17 +2,12 @@ const milliSecond = 1000; export class Timer { pointer = 0; + mins = Number(sessionStorage.getItem("mins")) || 12; + running = Boolean(Number(sessionStorage.getItem("running"))) || false; + deadline = Number(sessionStorage.getItem("deadline")) || new Date().getTime(); 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(); - } + this.running ? this.start(false) : this.reset(); addTimerBehaviour(this); } store() { -- cgit v1.3.1 From 56eb065a8165b3f508a35734adbb00c76bee012a Mon Sep 17 00:00:00 2001 From: Karan Jayachandra Date: Fri, 14 Nov 2025 18:08:45 +0100 Subject: Cleaned up the manager even more --- src/main.js | 6 +++--- src/manage.js | 50 ++++++++++++++++++++++++-------------------------- 2 files changed, 27 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/main.js b/src/main.js index 4c88167..cb7ec8e 100644 --- a/src/main.js +++ b/src/main.js @@ -63,9 +63,9 @@ export class GameManager extends Manager { const startIndex = 4 * index; const endIndex = startIndex + 4; const courtPlayers = players.slice(startIndex, endIndex); - const team_1 = new Team(courtPlayers[0].name, courtPlayers[3].name); - const team_2 = new Team(courtPlayers[1].name, courtPlayers[2].name); - const game = new Game(courts[index].id, false, team_1, team_2); + const teamOne = new Team(courtPlayers[0].name, courtPlayers[3].name); + const teamTwo = new Team(courtPlayers[1].name, courtPlayers[2].name); + const game = new Game(courts[index].id, false, teamOne, teamTwo); game.print(); this.data.push(game); } diff --git a/src/manage.js b/src/manage.js index ef48f8e..952c72f 100644 --- a/src/manage.js +++ b/src/manage.js @@ -106,22 +106,20 @@ export class GuestManager extends Manager { let games = data.games; return new Guest(id, status, games); } - active(factor) { - factor = typeof factor !== "undefined" ? factor : 1; + active() { return normalize(super.active()); } } export function randomLevel() { - const max_level = 10; - return Math.floor(Math.random() * max_level + 1); + const maxLevel = 10; + return Math.floor(Math.random() * maxLevel + 1); } export class PlayerManager extends Manager { constructor() { super("Regular", 71); addLoadBehaviour(this); - this.g = new GuestManager(); } createItem(i) { return new Player(i, randomStatus(), randomLevel()); @@ -134,25 +132,7 @@ export class PlayerManager extends Manager { let games = Number(data.games); return new Player(id, status, level, games, name); } - import(data) { - var lines = data.split("\n"); - var players = []; - for (var i = 1; i < lines.length; i++) { - if (lines[i] == undefined || lines[i].trim() == "") { - continue; - } - players.push(parseLineToPlayer(lines[i])); - } - console.log("Loaded " + players.length + " Players"); - for (var i = 0; i < players.length; i++) { - players[i].print(); - } - this.data = players; - this.store(); - this.render(); - } - active(factor) { - factor = typeof factor !== "undefined" ? factor : 1; + active() { return normalize(super.active()); } } @@ -162,7 +142,23 @@ function parseLineToPlayer(data) { var id = Number(info[0].trim()); var name = info[1].trim() + " " + info[2].trim(); var level = Number(info[3].trim()); - return new Player(id, true, level, 0, name); + return new Player(id, randomStatus(), level, 0, name); +} + +function parseCsv(data) { + let lines = data.split("\n"); + let players = []; + for (let i = 1; i < lines.length; i++) { + if (lines[i] == undefined || lines[i].trim() == "") { + continue; + } + players.push(parseLineToPlayer(lines[i])); + } + console.log("Loaded " + players.length + " Players"); + for (let i = 0; i < players.length; i++) { + players[i].print(); + } + return players; } function addLoadBehaviour(p) { @@ -174,7 +170,9 @@ function addLoadBehaviour(p) { const reader = new FileReader(); reader.onload = function (e) { importData = reader.result; - p.import(importData); + p.data = parseCsv(importData); + p.store(); + p.render(); }; reader.readAsText(file); }); -- cgit v1.3.1