*.swp
-*.csv
+/joueurs.csv
+*.bak
.~lock*
## Ajustement du fichier de données
1. Renommer joueurs.csv.dist en joueurs.csv
- 2. éditer joueurs.csv (ajout de joueurs, édition, suppression...). Format en lignes : prénom,nom[,pdt,session,présent]
+ 2. éditer joueurs.csv en s'inspirant de joueurs.sample.csv. Format en lignes : prénom,nom[,pdt,session,présent]
pdt, session, présent : optionnels (par défaut resp. 0, 0, 1).
1. Cliquer sur les joueurs absents dans l'onglet "joueurs"
2. Aller dans la section "appariements" et cliquer sur le bouton en haut
- 3. À la fin d'une ronde, cliquer sur chaque table pour indiquer les (mini-)points. Pour lancer la ronde suivante, revenir en 1.
+ 3. Lancer le chrono (section "chronomètre", puis click gauche, puis passer en plein écran [F11])
+ 4. À la fin d'une ronde, cliquer sur chaque table pour indiquer les (mini-)points.
-Le classement est mis à jour dans la rubrique correspondante et dans joueurs.csv. Il peut être réinitialisé (bouton en haut).
+Le classement est mis à jour dans la rubrique correspondante et dans joueurs.csv. Il peut être réinitialisé (bouton en haut).
Après chaque opération sur les points, en cas d'erreur le bouton "Restaurer" en haut à droite annule la dernière opération.
+
+-----
+
+Pour plus de détails, naviguer vers localhost:8000/doc
top: 0;
min-height: 100%;
width: 100%;
- font-size: 500px;
background-color: white;
cursor: pointer;
line-height: 100%;
- font-family: monospace;
+ text-align: center;
+ vertical-align: middle;
}
.timeout {
--- /dev/null
+@import '../vendor/Ubuntu_googlefont.css';
+
+body {
+ font-family: Ubuntu, Verdana, sans-serif;
+ font-size: 1.1rem;
+ width: 1200px;
+ margin: 30px auto;
+ line-height: 1.5rem;
+}
+
+img {
+ display: block;
+ margin: 30px 0;
+ width: 100%;
+}
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Westcastle usage</title>
+ <link rel="stylesheet" href="doc/index.css">
+ </head>
+ <body><span>L'application est divisée en 4 sections :</span>
+ <ul>
+ <li>Participants : la liste des joueurs présents (et absents)</li>
+ <li>Appariements : répartition des joueurs présents par tables</li>
+ <li>Chronomètre : un chrono qui démarre à 1h30 et sonne une fois à zéro</li>
+ <li>Classement : le tableau des scores (voir aussi joueurs.csv)</li>
+ </ul>
+ <h2>Participants</h2><img src="doc/screen_players.png">
+ <p>
+ Un clic sur un joueur présent l'enlève des joueurs actifs (il est absent) ;
+ réciproquement, un clic sur un absent le ramène dans la liste des joueurs actifs.
+ Les appariements sont déterminés pour les joueurs présents seulement - en revanche le classement indique tout le monde.
+
+ </p>
+ <h2>Appariements</h2><img src="doc/screen_pairings_new.png">
+ <p>
+ Un clic sur le bouton "Nouvelle ronde" réinitialise toutes les tables, en (re-)répartissant les joueurs aléatoirement sur celles-ci.
+ Si nécessaire, un quatrième joueur "Toto" est ajouté en fin de table.
+ Si seulement 1, 2, ou 5 ou 6 joueurs sont présents, aucune configuration ne permet de faire jouer tout le monde : il y aura des joueurs exempts.
+
+ </p><img src="doc/screen_pairings_scoring.png">
+ <p>
+ En fin de ronde, un clic sur une table permet de donner les scores de chaque joueur - en mini-points.
+ Un clic sur "Enregistrer" valide les scores : le classement est automatiquement mis à jour dans la rubrique correspondante,
+ et la table s'affiche désormais sur fond vert. Un clic sur "Fermer" annule l'opération, aucun changement n'est effectué.
+
+ </p><img src="doc/screen_pairings_restore.png">
+ <p>
+ En cas d'erreur, ne surtout pas scorer une nouvelle table : d'abord restaurer l'état précédent en cliquant sur le bouton "Restaurer"
+ sur l'écran de classement ; alternativement, on peut cliquer sur le lien présent dans l'avertissement lorsqu'on reclique sur la table en question.
+ Ensuite, rentrer les scores corrigés.
+
+ </p>
+ <h2>Chronomètre</h2><img src="doc/screen_timer.png">
+ <p>
+ Ce chronomètre basique est conçu pour s'afficher centré en mode plein écran : il faut donc commencer par appuyer sur F11
+ (la touche peut varier suivant le navigateur...). Ensuite :
+
+ </p>
+ <ul>
+ <li>un clic gauche lance le chrono ou le met en pause. Un gong retentit une fois le temps écoulé.</li>
+ <li>un clic droit réinitialise le chrono (à 1h30 = 90 minutes)</li>
+ <li>un clic sur la croix en haut à droite revient à la section appariements (suite logique).</li>
+ </ul>
+ <p>
+ Note : le chronomètre reste actif même si l'on change de vue - penser à le mettre en pause ou le réinitialiser.
+
+ </p>
+ <h2>Classement</h2><img src="doc/screen_ranking.png">
+ <p>
+ Les scores sont ordonnés par points de table décroissants d'abord, puis en cas d'ex-aequos par mini-points décroissants.
+
+ </p>
+ <p>
+ Un clic sur "Réinitialiser" remet tous les compteurs à zéro : par exemple pour démarrer un nouveau cycle de tournois.
+ Cette action peut être annulée (immédiatement après) en cliquant sur "Restaurer".
+ </p>
+ </body>
+</html>
\ No newline at end of file
--- /dev/null
+doctype html
+html
+
+ head
+ meta(charset="utf-8")
+ title Westcastle usage
+ link(rel="stylesheet", href="doc/index.css")
+
+ body
+
+ span L'application est divisée en 4 sections :
+ ul
+ li Participants : la liste des joueurs présents (et absents)
+ li Appariements : répartition des joueurs présents par tables
+ li Chronomètre : un chrono qui démarre à 1h30 et sonne une fois à zéro
+ li Classement : le tableau des scores (voir aussi joueurs.csv)
+
+ h2 Participants
+
+ img(src="doc/screen_players.png")
+
+ p.
+ Un clic sur un joueur présent l'enlève des joueurs actifs (il est absent) ;
+ réciproquement, un clic sur un absent le ramène dans la liste des joueurs actifs.
+ Les appariements sont déterminés pour les joueurs présents seulement - en revanche le classement indique tout le monde.
+
+ h2 Appariements
+
+ img(src="doc/screen_pairings_new.png")
+
+ p.
+ Un clic sur le bouton "Nouvelle ronde" réinitialise toutes les tables, en (re-)répartissant les joueurs aléatoirement sur celles-ci.
+ Si nécessaire, un quatrième joueur "Toto" est ajouté en fin de table.
+ Si seulement 1, 2, ou 5 ou 6 joueurs sont présents, aucune configuration ne permet de faire jouer tout le monde : il y aura des joueurs exempts.
+
+ img(src="doc/screen_pairings_scoring.png")
+
+ p.
+ En fin de ronde, un clic sur une table permet de donner les scores de chaque joueur - en mini-points.
+ Un clic sur "Enregistrer" valide les scores : le classement est automatiquement mis à jour dans la rubrique correspondante,
+ et la table s'affiche désormais sur fond vert. Un clic sur "Fermer" annule l'opération, aucun changement n'est effectué.
+
+ img(src="doc/screen_pairings_restore.png")
+
+ p.
+ En cas d'erreur, ne surtout pas scorer une nouvelle table : d'abord restaurer l'état précédent en cliquant sur le bouton "Restaurer"
+ sur l'écran de classement ; alternativement, on peut cliquer sur le lien présent dans l'avertissement lorsqu'on reclique sur la table en question.
+ Ensuite, rentrer les scores corrigés.
+
+ h2 Chronomètre
+
+ img(src="doc/screen_timer.png")
+
+ p.
+ Ce chronomètre basique est conçu pour s'afficher centré en mode plein écran : il faut donc commencer par appuyer sur F11
+ (la touche peut varier suivant le navigateur...). Ensuite :
+
+ ul
+ li un clic gauche lance le chrono ou le met en pause. Un gong retentit une fois le temps écoulé.
+ li un clic droit réinitialise le chrono (à 1h30 = 90 minutes)
+ li un clic sur la croix en haut à droite revient à la section appariements (suite logique).
+
+ p.
+ Note : le chronomètre reste actif même si l'on change de vue - penser à le mettre en pause ou le réinitialiser.
+
+ h2 Classement
+
+ img(src="doc/screen_ranking.png")
+
+ p.
+ Les scores sont ordonnés par points de table décroissants d'abord, puis en cas d'ex-aequos par mini-points décroissants.
+
+ p.
+ Un clic sur "Réinitialiser" remet tous les compteurs à zéro : par exemple pour démarrer un nouveau cycle de tournois.
+ Cette action peut être annulée (immédiatement après) en cliquant sur "Restaurer".
<div id="mahjong">
<header>
<ul class="sidenav">
- <li @click="display='players'">Joueurs</li>
- <li @click="display='ranking'">Classement</li>
+ <li @click="display='players'">Participants</li>
<li @click="display='pairings'">Appariements</li>
<li @click="display='timer'">Chronomètre</li>
+ <li @click="display='ranking'">Classement</li>
</ul>
<img class="logo" src="img/logo_Westcastle.png"/>
</header>
<main>
<my-players v-show="display=='players'" :players="players"></my-players>
- <my-ranking v-show="display=='ranking'" :players="players" :sort-by-score="sortByScore" :write-score-to-db="writeScoreToDb"></my-ranking>
<my-pairings v-show="display=='pairings'" :players="players" :write-score-to-db="writeScoreToDb"></my-pairings>
<my-timer v-show="display=='timer'" @clockover="display='pairings'"></my-timer>
+ <my-ranking v-show="display=='ranking'" :players="players" :sort-by-score="sortByScore" :write-score-to-db="writeScoreToDb"></my-ranking>
</main>
</div>
</body>
--- /dev/null
+prenom,nom,pdt,session,present
+William,Plaisance,4,30,1
+Rosamonde,Dupuy,4,25,1
+Fabienne,Aubin,2,15,1
+Grégoire,Léveillé,2,10,0
+Fantina,Quinn,1,0,1
+Amitee,Morneau,1,-5,0
+William,Lespérance
+Dreux,Vadeboncoeur
+Brigliador,Cadieux
+Grosvenor,Provencher
+Landers,Devost
+Joy,Laprise
+Dielle,Séguin
+Sidney,DeGrasse
+Jules,Gaillou
+Archaimbau,Bizier
+Dexter,Aucoin
+Searlas,Rivière
+Germain,Charpie
+Honore,Charlesbois
+Georges,LaCaille
+Anne,Ruest
+Searlas,Rochefort
+Ferrau,Adler
+Aimée,Asselin
+Delit,Cyr
+Noël,Babin
},
},
},
- 'my-ranking': {
- props: ['players','sortByScore','writeScoreToDb'],
- template: `
- <div id="ranking">
- <table class="ranking">
- <tr class="title">
- <th>Rang</th>
- <th>Joueur</th>
- <th>Points</th>
- <th>Mini-pts</th>
- </tr>
- <tr v-for="p in sortedPlayers">
- <td>{{ p.rank }}</td>
- <td>{{ p.prenom }} {{ p.nom }}</td>
- <td>{{ p.pdt }}</td>
- <td>{{ p.session }}</td>
- </tr>
- </table>
- <div class="button-container-vertical" style="width:200px">
- <button class="btn cancel" @click="resetPlayers()">Réinitialiser</button>
- <button id="restoreBtn" class="btn" @click="restoreLast()">Restaurer</button>
- </div>
- </div>
- `,
- computed: {
- sortedPlayers: function() {
- let res = this.rankPeople();
- // Add rank information (taking care of ex-aequos)
- let rank = 1;
- for (let i=0; i<res.length; i++)
- {
- if (i==0 || this.sortByScore(res[i],res[i-1]) == 0)
- res[i].rank = rank;
- else //strictly lower scoring
- res[i].rank = ++rank;
- }
- return res;
- },
- },
- methods: {
- rankPeople: function() {
- return this.players
- .slice(1) //discard Toto
- .map( p => { return Object.assign({}, p); }) //to not alter original array
- .sort(this.sortByScore);
- },
- resetPlayers: function() {
- this.players
- .slice(1) //discard Toto
- .forEach( p => {
- p.pdt = 0;
- p.session = 0;
- p.available = 1;
- });
- this.writeScoreToDb();
- document.getElementById("runPairing").click(); //TODO: hack...
- },
- restoreLast: function() {
- let xhr = new XMLHttpRequest();
- let self = this;
- xhr.onreadystatechange = function() {
- if (this.readyState == 4 && this.status == 200)
- {
- let players = JSON.parse(xhr.responseText);
- if (players.length > 0)
- {
- players.unshift({ //add ghost 4th player for 3-players tables
- prenom: "Toto",
- nom: "",
- pdt: 0,
- session: 0,
- available: 0,
- });
- self.players = players;
- }
- }
- };
- xhr.open("GET", "scripts/rw_players.php?restore=1", true);
- xhr.send(null);
- },
- },
- },
'my-pairings': {
props: ['players','writeScoreToDb'],
data: function() {
};
},
template: `
- <div id="timer">
+ <div id="timer" :style="{lineHeight: screen.height+ 'px', fontSize: 0.66*screen.height + 'px'}">
<div @click.left="pauseResume()" @click.right.prevent="reset()" :class="{timeout:time==0}">
{{ formattedTime }}
</div>
},
reset: function(e) {
this.running = false;
- this.time = 10; //1:30
+ this.time = 5400; //1:30
},
start: function() {
if (!this.running)
this.reset();
},
},
+ 'my-ranking': {
+ props: ['players','sortByScore','writeScoreToDb'],
+ template: `
+ <div id="ranking">
+ <table class="ranking">
+ <tr class="title">
+ <th>Rang</th>
+ <th>Joueur</th>
+ <th>Points</th>
+ <th>Mini-pts</th>
+ </tr>
+ <tr v-for="p in sortedPlayers">
+ <td>{{ p.rank }}</td>
+ <td>{{ p.prenom }} {{ p.nom }}</td>
+ <td>{{ p.pdt }}</td>
+ <td>{{ p.session }}</td>
+ </tr>
+ </table>
+ <div class="button-container-vertical" style="width:200px">
+ <button class="btn cancel" @click="resetPlayers()">Réinitialiser</button>
+ <button id="restoreBtn" class="btn" @click="restoreLast()">Restaurer</button>
+ </div>
+ </div>
+ `,
+ computed: {
+ sortedPlayers: function() {
+ let res = this.rankPeople();
+ // Add rank information (taking care of ex-aequos)
+ let rank = 1;
+ for (let i=0; i<res.length; i++)
+ {
+ if (i==0 || this.sortByScore(res[i],res[i-1]) == 0)
+ res[i].rank = rank;
+ else //strictly lower scoring
+ res[i].rank = ++rank;
+ }
+ return res;
+ },
+ },
+ methods: {
+ rankPeople: function() {
+ return this.players
+ .slice(1) //discard Toto
+ .map( p => { return Object.assign({}, p); }) //to not alter original array
+ .sort(this.sortByScore);
+ },
+ resetPlayers: function() {
+ this.players
+ .slice(1) //discard Toto
+ .forEach( p => {
+ p.pdt = 0;
+ p.session = 0;
+ p.available = 1;
+ });
+ this.writeScoreToDb();
+ document.getElementById("runPairing").click(); //TODO: hack...
+ },
+ restoreLast: function() {
+ let xhr = new XMLHttpRequest();
+ let self = this;
+ xhr.onreadystatechange = function() {
+ if (this.readyState == 4 && this.status == 200)
+ {
+ let players = JSON.parse(xhr.responseText);
+ if (players.length > 0)
+ {
+ players.unshift({ //add ghost 4th player for 3-players tables
+ prenom: "Toto",
+ nom: "",
+ pdt: 0,
+ session: 0,
+ available: 0,
+ });
+ self.players = players;
+ }
+ }
+ };
+ xhr.open("GET", "scripts/rw_players.php?restore=1", true);
+ xhr.send(null);
+ },
+ },
+ },
},
created: function() {
let xhr = new XMLHttpRequest();