I hope it's intuitive enough :)
But, a few important points:
- - All games start with a random assymetric position!
- - Games are untimed: you decide to play fast or not...
- - Your identity (if filled) is revealed only after the game
+ - Games start with a random assymetric position!
+ - Your identity is revealed only after a game
## Resources
// 2) Check turn
if (!fenParsed.turn || !V.IsGoodTurn(fenParsed.turn))
return false;
- // 3) Check flags
+ // 3) Check moves count
+ if (!fenParsed.movesCount || !(parseInt(fenParsed.movesCount) >= 0))
+ return false;
+ // 4) Check flags
if (V.HasFlags && (!fenParsed.flags || !V.IsGoodFlags(fenParsed.flags)))
return false;
- // 4) Check enpassant
+ // 5) Check enpassant
if (V.HasEnpassant &&
(!fenParsed.enpassant || !V.IsGoodEnpassant(fenParsed.enpassant)))
{
{
position: fenParts[0],
turn: fenParts[1],
+ movesCount: fenParts[2],
};
- let nextIdx = 2;
+ let nextIdx = 3;
if (V.HasFlags)
Object.assign(res, {flags: fenParts[nextIdx++]});
if (V.HasEnpassant)
// Return current fen (game state)
getFen()
{
- return this.getBaseFen() + " " + this.getTurnFen() +
+ return this.getBaseFen() + " " +
+ this.getTurnFen() + " " + this.movesCount +
(V.HasFlags ? (" " + this.getFlagsFen()) : "") +
(V.HasEnpassant ? (" " + this.getEnpassantFen()) : "");
}
// INITIALIZATION
// Fen string fully describes the game state
- constructor(fen, moves)
+ constructor(fen)
{
- this.moves = moves;
const fenParsed = V.ParseFen(fen);
this.board = V.GetBoard(fenParsed.position);
this.turn = fenParsed.turn[0]; //[0] to work with MarseilleRules
+ this.movesCount = parseInt(fenParsed.movesCount);
this.setOtherVariables(fen);
}
return (color=="w" ? "b" : "w");
}
- get lastMove()
- {
- const L = this.moves.length;
- return (L>0 ? this.moves[L-1] : null);
- }
-
// Pieces codes (for a clearer code)
static get PAWN() { return 'p'; }
static get ROOK() { return 'r'; }
// if (!ingame) this.states.push(this.getFen());
if (!!ingame)
- move.notation = [this.getNotation(move), this.getLongNotation(move)];
+ move.notation = this.getNotation(move);
if (V.HasFlags)
move.flags = JSON.stringify(this.aggregateFlags()); //save flags (for undo)
this.epSquares.push( this.getEpSquare(move) );
V.PlayOnBoard(this.board, move);
this.turn = this.getOppCol(this.turn);
- this.moves.push(move);
+ this.movesCount++;
this.updateVariables(move);
if (!!ingame)
this.disaggregateFlags(JSON.parse(move.flags));
V.UndoOnBoard(this.board, move);
this.turn = this.getOppCol(this.turn);
- this.moves.pop();
+ this.movesCount--;
this.unupdateVariables(move);
// DEBUG:
///////////////
// END OF GAME
- // Check for 3 repetitions (position + flags + turn)
- checkRepetition()
- {
- if (!this.hashStates)
- this.hashStates = {};
- const startIndex =
- Object.values(this.hashStates).reduce((a,b) => { return a+b; }, 0)
- // Update this.hashStates with last move (or all moves if continuation)
- // NOTE: redundant storage, but faster and moderate size
- for (let i=startIndex; i<this.moves.length; i++)
- {
- const move = this.moves[i];
- if (!this.hashStates[move.hash])
- this.hashStates[move.hash] = 1;
- else
- this.hashStates[move.hash]++;
- }
- return Object.values(this.hashStates).some(elt => { return (elt >= 3); });
- }
-
// Is game over ? And if yes, what is the score ?
checkGameOver()
{
- if (this.checkRepetition())
- return "1/2";
-
if (this.atLeastOneMove()) // game not over
return "*";
/////////////////////////
// Context: just before move is played, turn hasn't changed
+ // TODO: un-ambiguous notation (switch on piece type, check directions...)
getNotation(move)
{
if (move.appear.length == 2 && move.appear[0].p == V.KING) //castle
}
// The score is already computed when calling this function
- getPGN(mycolor, score, fenStart, mode)
+ getPGN(moves, mycolor, score, fenStart, mode)
{
let pgn = "";
pgn += '[Site "vchess.club"]\n';
: "analyze";
pgn += '[White "' + whiteName + '"]\n';
pgn += '[Black "' + blackName + '"]\n';
- pgn += '[FenStart "' + fenStart + '"]\n';
- pgn += '[Fen "' + this.getFen() + '"]\n';
+ pgn += '[Fen "' + fenStart + '"]\n';
pgn += '[Result "' + score + '"]\n\n';
- // Standard PGN
- for (let i=0; i<this.moves.length; i++)
- {
- if (i % 2 == 0)
- pgn += ((i/2)+1) + ".";
- pgn += this.moves[i].notation[0] + " ";
- }
- pgn += "\n\n";
-
- // "Complete moves" PGN (helping in ambiguous cases)
- for (let i=0; i<this.moves.length; i++)
+ // Print moves
+ for (let i=0; i<moves.length; i++)
{
if (i % 2 == 0)
pgn += ((i/2)+1) + ".";
- pgn += this.moves[i].notation[1] + " ";
+ pgn += moves[i].notation + " ";
}
return pgn + "\n";
}
);
aboveBoardElts.push(turnIndic);
- const settingsBtn = h(
- 'button',
- {
- on: { click: this.showSettings },
- attrs: {
- "aria-label": translations['Settings'],
- "id": "settingsBtn",
- },
- 'class': {
- "tooltip": true,
- "play": true,
- "above-board": true,
- "indic-right": true,
- },
- },
- [h('i', { 'class': { "material-icons": true } }, "settings")]
- );
- aboveBoardElts.push(settingsBtn);
elementArray.push(
h('div',
{ "class": { "aboveboard-wrapper": true } },
)
];
elementArray = elementArray.concat(modalFenEdit);
- const modalSettings = [
- h('input',
- {
- attrs: { "id": "modal-settings", type: "checkbox" },
- "class": { "modal": true },
- }),
- h('div',
- {
- attrs: { "role": "dialog", "aria-labelledby": "settingsTitle" },
- },
- [
- h('div',
- {
- "class": { "card": true, "smallpad": true },
- },
- [
- h('label',
- {
- attrs: { "id": "close-settings", "for": "modal-settings" },
- "class": { "modal-close": true },
- }
- ),
- h('h3',
- {
- attrs: { "id": "settingsTitle" },
- "class": { "section": true },
- domProps: { innerHTML: translations["Preferences"] },
- }
- ),
- h('fieldset',
- { },
- [
- h('label',
- {
- attrs: { for: "nameSetter" },
- domProps: { innerHTML: translations["My name is..."] },
- },
- ),
- h('input',
- {
- attrs: {
- "id": "nameSetter",
- type: "text",
- value: this.myname,
- },
- on: { "change": this.setMyname },
- }
- ),
- ]
- ),
- h('fieldset',
- { },
- [
- h('label',
- {
- attrs: { for: "setHints" },
- domProps: { innerHTML: translations["Show hints?"] },
- },
- ),
- h('input',
- {
- attrs: {
- "id": "setHints",
- type: "checkbox",
- checked: this.hints,
- },
- on: { "change": this.toggleHints },
- }
- ),
- ]
- ),
- h('fieldset',
- { },
- [
- h('label',
- {
- attrs: { for: "selectColor" },
- domProps: { innerHTML: translations["Board colors"] },
- },
- ),
- h("select",
- {
- attrs: { "id": "selectColor" },
- on: { "change": this.setBoardColor },
- },
- [
- h("option",
- {
- domProps: {
- "value": "lichess",
- innerHTML: translations["brown"]
- },
- attrs: { "selected": this.color=="lichess" },
- }
- ),
- h("option",
- {
- domProps: {
- "value": "chesscom",
- innerHTML: translations["green"]
- },
- attrs: { "selected": this.color=="chesscom" },
- }
- ),
- h("option",
- {
- domProps: {
- "value": "chesstempo",
- innerHTML: translations["blue"]
- },
- attrs: { "selected": this.color=="chesstempo" },
- }
- ),
- ],
- ),
- ]
- ),
- h('fieldset',
- { },
- [
- h('label',
- {
- attrs: { for: "selectSound" },
- domProps: { innerHTML: translations["Play sounds?"] },
- },
- ),
- h("select",
- {
- attrs: { "id": "selectSound" },
- on: { "change": this.setSound },
- },
- [
- h("option",
- {
- domProps: {
- "value": "0",
- innerHTML: translations["None"]
- },
- attrs: { "selected": this.sound==0 },
- }
- ),
- h("option",
- {
- domProps: {
- "value": "1",
- innerHTML: translations["New game"]
- },
- attrs: { "selected": this.sound==1 },
- }
- ),
- h("option",
- {
- domProps: {
- "value": "2",
- innerHTML: translations["All"]
- },
- attrs: { "selected": this.sound==2 },
- }
- ),
- ],
- ),
- ]
- ),
- ]
- )
- ]
- )
- ];
- elementArray = elementArray.concat(modalSettings);
let chatEltsArray =
[
h('label',
},
},
})
+
+// TODO: keep moves list here
+get lastMove()
+ {
+ const L = this.moves.length;
+ return (L>0 ? this.moves[L-1] : null);
+ }
--- /dev/null
+// TODO
+//My games : (tabs)
+//mes parties en cours --> démarrer là-dessus si y en a et c'est à moi de jouer ?
+//mes parties terminées (possibilité de supprimer)
},
},
})
+
+// TODO:
+// possibilité de supprimer / éditer si peer ID reconnu comme celui du probleme (champ "uploader")
+// --> côté serveur on vérifie un certain "secret"
+// --> filtre possible "mes problèmes"
--- /dev/null
+// TODO: main playing hall, chat + online players + current challenges + button "new game"
+/*
+input#modal-newgame.modal(type="checkbox")
+div(role="dialog" aria-labelledby="newGameTxt")
+ .card.smallpad.small-modal
+ label#close-newgame.modal-close(for="modal-newgame")
+ h3#newGameTxt= translations["New game"]
+ p= translations["Waiting for opponent..."]
+*/
+
+/*
+Players + challenges : == "room" home of variant (surligner si nouveau défi perso et pas affichage courant)
+joueurs en ligne (dte),
+Nouvelle partie + défis en temps réel + parties en cours (milieu, tabs),
+chat général (gauche, activé ou non (bool global storage)).
+(cadences base + incrément, corr == incr >= 1jour ou base >= 7j)
+--> correspondance: stocker sur serveur lastMove + peerId + color + movesCount + gameId + variant + timeleft
+quand je poste un lastMove corr, supprimer mon ancien lastMove le cas échéant (tlm l'a eu)
+fin de partie corr: garder maxi nbPlayers lastMove sur serveur, pendant 7 jours (arbitraire)
+*/
},
computed: {
sortedCounts: function () {
+ // TODO: priorité aux parties corr où c'est à nous de jouer !
const variantsCounts = variantArray
.filter( v => {
return v.name.startsWith(this.curPrefix);
}
// ...ignore everything else
};
- // Show welcome dialog box if "first visit"
- const visited = getCookie("visited");
- if (!visited || visited !== "1")
- document.getElementById("modalB4welcome").checked = true;
- },
- methods: {
- showWelcomeMsg: function() {
- document.getElementById("modalB4welcome").checked = false;
- document.getElementById("modalWelcome").checked = true;
- },
- markAsVisited: function() {
- setCookie('visited', '1');
- document.getElementById('modalWelcome').checked = false;
- },
},
});
+
+// TODO:
+// si dernier lastMove sur serveur n'est pas le mien et nextColor == moi, alors background orange
+// ==> background orange si à moi de jouer par corr (sur main index)
+// (fonction "getNextCol()" dans base_rules.js ?)
--- /dev/null
+// TODO:
+//à l'arrivée sur le site : set peerID (un identifiant unique en tout cas...) si pas trouvé
--- /dev/null
+// TODO:
+//à chaque onChange, envoyer matching event settings update
+//(par exemple si mise à jour du nom, juste envoyer cet update aux autres connectés ...etc)
-// Assuming V(ariantRules) class is loaded.
-// args: object with position (mandatory), orientation, marks (optional)
-function getDiagram(args)
+// Turn (human) marks into coordinates
+function getMarkArray(marks)
{
- const [sizeX,sizeY] = [V.size.x,V.size.y];
- // Obtain array of pieces images names
- const board = VariantRules.GetBoard(args.position);
- const orientation = args.orientation || "w";
- let markArray = [];
- if (!!args.marks && args.marks != "-")
+ if (!marks || marks == "-")
+ return [];
+ let markArray = doubleArray(V.size.x, V.size.y, false);
+ const squares = marks.split(",");
+ for (let i=0; i<squares.length; i++)
{
- // Turn (human) marks into coordinates
- markArray = doubleArray(sizeX, sizeY, false);
- let squares = args.marks.split(",");
- for (let i=0; i<squares.length; i++)
- {
- const coords = V.SquareToCoords(squares[i]);
- markArray[coords.x][coords.y] = true;
- }
+ const coords = V.SquareToCoords(squares[i]);
+ markArray[coords.x][coords.y] = true;
}
- let shadowArray = [];
- if (!!args.shadow && args.shadow != "-")
+ return markArray;
+}
+
+// Turn (human) shadow indications into coordinates
+function getShadowArray(shadow)
+{
+ if (!shadow || shadow == "-")
+ return [];
+ let shadowArray = doubleArray(V.size.x, V.size.y, false);
+ const squares = shadow.split(",");
+ for (let i=0; i<squares.length; i++)
{
- // Turn (human) shadow indications into coordinates
- shadowArray = doubleArray(sizeX, sizeY, false);
- let squares = args.shadow.split(",");
- for (let i=0; i<squares.length; i++)
+ const rownum = V.size.x - parseInt(squares[i]);
+ if (!isNaN(rownum))
{
- const rownum = V.size.x - parseInt(squares[i]);
- if (!isNaN(rownum))
- {
- // Shadow a full row
- for (let i=0; i<V.size.y; i++)
- shadowArray[rownum][i] = true;
- continue;
- }
- if (squares[i].length == 1)
- {
- // Shadow a full column
- const colnum = V.ColumnToCoord(squares[i]);
- for (let i=0; i<V.size.x; i++)
- shadowArray[i][colnum] = true;
- continue;
- }
- if (squares[i].indexOf("-") >= 0)
+ // Shadow a full row
+ for (let i=0; i<V.size.y; i++)
+ shadowArray[rownum][i] = true;
+ continue;
+ }
+ if (squares[i].length == 1)
+ {
+ // Shadow a full column
+ const colnum = V.ColumnToCoord(squares[i]);
+ for (let i=0; i<V.size.x; i++)
+ shadowArray[i][colnum] = true;
+ continue;
+ }
+ if (squares[i].indexOf("-") >= 0)
+ {
+ // Shadow a range of squares, horizontally or vertically
+ const firstLastSq = squares[i].split("-");
+ const range =
+ [
+ V.SquareToCoords(firstLastSq[0]),
+ V.SquareToCoords(firstLastSq[1])
+ ];
+ const step =
+ [
+ range[1].x == range[0].x
+ ? 0
+ : (range[1].x - range[0].x) / Math.abs(range[1].x - range[0].x),
+ range[1].y == range[0].y
+ ? 0
+ : (range[1].y - range[0].y) / Math.abs(range[1].y - range[0].y)
+ ];
+ // Convention: range always from smaller to larger number
+ for (let x=range[0].x, y=range[0].y; x <= range[1].x && y <= range[1].y;
+ x += step[0], y += step[1])
{
- // Shadow a range of squares, horizontally or vertically
- const firstLastSq = squares[i].split("-");
- const range =
- [
- V.SquareToCoords(firstLastSq[0]),
- V.SquareToCoords(firstLastSq[1])
- ];
- const step =
- [
- range[1].x == range[0].x
- ? 0
- : (range[1].x - range[0].x) / Math.abs(range[1].x - range[0].x),
- range[1].y == range[0].y
- ? 0
- : (range[1].y - range[0].y) / Math.abs(range[1].y - range[0].y)
- ];
- // Convention: range always from smaller to larger number
- for (let x=range[0].x, y=range[0].y; x <= range[1].x && y <= range[1].y;
- x += step[0], y += step[1])
- {
- shadowArray[x][y] = true;
- }
- continue;
+ shadowArray[x][y] = true;
}
- // Shadow just one square:
- const coords = V.SquareToCoords(squares[i]);
- shadowArray[coords.x][coords.y] = true;
+ continue;
}
+ // Shadow just one square:
+ const coords = V.SquareToCoords(squares[i]);
+ shadowArray[coords.x][coords.y] = true;
}
+ return shadowArray;
+}
+
+// args: object with position (mandatory), and
+// orientation, marks, shadow (optional)
+function getDiagram(args)
+{
+ // Obtain the array of pieces images names:
+ const board = VariantRules.GetBoard(args.position);
+ const orientation = args.orientation || "w";
+ const markArray = getMarkArray(args.marks);
+ const shadowArray = getShadowArray(args.shadow);
let boardDiv = "";
const [startX,startY,inc] = orientation == 'w'
? [0, 0, 1]
- : [sizeX-1, sizeY-1, -1];
- for (let i=startX; i>=0 && i<sizeX; i+=inc)
+ : [V.size.x-1, V.size.y-1, -1];
+ for (let i=startX; i>=0 && i<V.size.x; i+=inc)
{
boardDiv += "<div class='row'>";
- for (let j=startY; j>=0 && j<sizeY; j+=inc)
+ for (let j=startY; j>=0 && j<V.size.y; j+=inc)
{
- boardDiv += "<div class='board board" + sizeY + " " +
+ boardDiv += "<div class='board board" + V.size.y + " " +
((i+j)%2==0 ? "light-square-diag" : "dark-square-diag") +
(shadowArray.length > 0 && shadowArray[i][j] ? " in-shadow" : "") +
"'>";
new Vue({
el: "#variantPage",
data: {
- display: "play", //default: play!
- problem: undefined, //current problem in view
+ display: "room", //default: main hall
},
created: function() {
+ // TODO: navigation becomes a little more complex
const url = window.location.href;
const hashPos = url.indexOf("#");
if (hashPos >= 0)
this.setDisplay(url.substr(hashPos+1));
},
methods: {
- showProblem: function(problemTxt) {
- this.problem = JSON.parse(problemTxt);
- this.display = "play";
- },
setDisplay: function(elt) {
this.display = elt;
+ // Close menu on small screens:
let menuToggle = document.getElementById("drawer-control");
if (!!menuToggle)
menuToggle.checked = false;
},
- notDark: function() {
- return variant != "Dark";
- },
},
});
+
+// TODO:
+// si quand on arrive il y a une continuation "humaine" : display="game" et retour à la partie !
const pieces = Object.keys(V.ALICE_CODES);
const codes = Object.keys(V.ALICE_PIECES);
const mirrorSide = (pieces.includes(this.getPiece(x,y)) ? 1 : 2);
+ const color = this.getColor(x,y);
// Search valid moves on sideBoard
let saveBoard = this.board;
this.board = sideBoard || this.getSideBoard(mirrorSide);
- let moves = super.getPotentialMovesFrom([x,y]);
+ let moves = super.getPotentialMovesFrom([x,y])
+ .filter(m => {
+ // Filter out king moves which result in under-check position on
+ // current board (before mirror traversing)
+ let aprioriValid = true;
+ if (m.appear[0].p == V.KING)
+ {
+ this.play(m);
+ if (this.underCheck(color))
+ aprioriValid = false;
+ this.undo(m);
+ }
+ return aprioriValid;
+ });
this.board = saveBoard;
// Finally filter impossible moves
return Object.assign(
ChessRules.ParseFen(fen),
{
- reserve: fenParts[4],
- promoted: fenParts[5],
+ reserve: fenParts[5],
+ promoted: fenParts[6],
}
);
}
const fenParts = fen.split(" ");
return Object.assign(
ChessRules.ParseFen(fen),
- { captured: fenParts[4] }
+ { captured: fenParts[5] }
);
}
block content
.container#indexPage
- include langNames.pug
case lang
when "en"
- include translations/en.pug
- include welcome/en.pug
- include modal-lang/en.pug
- include modal-help/en.pug
+ include welcome/en
when "es"
- include translations/es.pug
- include welcome/es.pug
- include modal-lang/es.pug
- include modal-help/es.pug
+ include welcome/es
when "fr"
- include translations/fr.pug
- include welcome/fr.pug
- include modal-lang/fr.pug
- include modal-help/fr.pug
+ include welcome/fr
.row
#header.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
- #mainTitle
+ #mainTitle.clickable(
+ onClick="document.getElementById('modalWelcome').checked=true")
img(src="/images/index/unicorn.svg")
.info-container
p vchess.club
img(src="/images/index/wildebeest.svg")
- #flagMenu.clickable(
- onClick="document.getElementById('modalLang').checked=true")
- img(src="/images/flags/" + lang + ".svg")
- #helpMenu.clickable(
- onClick="document.getElementById('modalHelp').checked=true")
- .info-container
- p= translations["Help"]
+ #settings.clickable(
+ onClick="document.getElementById('modalSettings').checked=true")
+ i.material-icons settings
.row
my-variant-summary(v-for="(v,idx) in sortedCounts"
v-bind:vobj="v" v-bind:index="idx" v-bind:key="v.name")
- // Other modals:
- input#modalB4welcome.modal(type="checkbox")
- div(role="dialog")
- #b4welcome.card.text-center.small-modal
- h3.blue= translations["First visit?"]
- p#readThis.clickable(@click="showWelcomeMsg")
- =translations[">>> Please read this <<<"]
+
+ redesign index page :: lien github, lien contact mail, settings
block javascripts
script.
- const translations = !{JSON.stringify(translations)};
const variantArray = !{JSON.stringify(variantArray)};
script(src="/javascripts/utils/misc.js")
script(src="/javascripts/socket_url.js")
link(rel="mask-icon" href="/images/favicon/safari-pinned-tab.svg" color="#5bbad5")
link(rel="shortcut icon" href="/images/favicon/favicon.ico")
link(rel="stylesheet" href="/stylesheets/layout.css")
+ link(rel="stylesheet" href="//fonts.googleapis.com/icon?family=Material+Icons")
block css
body
main
+ include langNames
+ case lang
+ when "en"
+ include translations/en
+ when "es"
+ include translations/es
+ when "fr"
+ include translations/fr
+ include settings
block content
script(src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js")
+ script(src="/javascripts/layout.js")
if development
script(src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js")
else
script(src="https://cdn.jsdelivr.net/npm/vue")
+ script.
+ const translations = !{JSON.stringify(translations)};
block javascripts
+++ /dev/null
-input#modalHelp.modal(type="checkbox")
-div(role="dialog")
- #help.card
- label.modal-close(for="modalHelp")
- .section
- ol
- li Click on a variant,
- li Read the rules (in the upper left corner),
- li Back to playing mode (click on "Play")
- li Click on "New live game", and then, while waiting
- li Click on "New computer game" (just next).
- p Reminder:
- ul
- li All games start with a random assymetric position.
- li Games are untimed, and played anonymously.
- li No chat while playing, to focus on the moves.
- .section
- h3.red Bug report
- p
- | Please send an email (in English or French) to
- a(href="mailto:contact@vchess.club?subject=[vchess.club] bug report")
- | contact@vchess.club
- | .
+++ /dev/null
-input#modalHelp.modal(type="checkbox")
-div(role="dialog")
- #help.card
- label.modal-close(for="modalHelp")
- .section
- ol
- li Haga clic en una variante,
- li Lee las reglas (arriba a la izquierda),
- li Volver al modo de juego (haga clic en "Jugar"),
- li Haga clic en "Nuevo juego en vivo", luego, mientras tanto,
- li Haga clic en "Nuevo juego contra la computadora" (siguiente).
- p Recordatorio :
- ul
- li Todas las partes comienzan con una posición aleatoria asimétrica.
- li Los juegos no están cronometrados, y se juegan anónimamente.
- li No charla durante el juego, para concentrarse en los movimientos.
- .section
- h3.red Informe de bug
- p
- | Por favor envíe un correo electrónico (en inglés o francés) a
- a(href="mailto:contact@vchess.club?subject=[vchess.club] bug report")
- | contact@vchess.club
- | .
+++ /dev/null
-input#modalHelp.modal(type="checkbox")
-div(role="dialog")
- #help.card
- label.modal-close(for="modalHelp")
- .section
- ol
- li Cliquez sur une variante,
- li Lisez les règles (en haut à gauche),
- li Revenez en mode jeu (cliquer sur "Jouer")
- li Cliquez sur "Nouvelle partie en direct", puis, en attendant
- li Cliquez sur "Nouvelle partie contre l'ordinateur" (à côté).
- p Rappel :
- ul
- li Toutes les parties démarrent avec une position aléatoire assymétrique.
- li Les parties ne sont pas chronométrées, et jouée anonymemement.
- li Pas de chat pendant la partie, pour se concentrer sur les coups.
- .section
- h3.red Rapport de bug
- p
- | SVP envoyez un email (en français ou anglais) à
- a(href="mailto:contact@vchess.club?subject=[vchess.club] bug report")
- | contact@vchess.club
- | .
+++ /dev/null
-input#modalLang.modal(type="checkbox")
-div(role="dialog")
- #language.card
- label.modal-close(for="modalLang")
- .section
- fieldset
- label(for="langSelect") Preferred language?
- select#langSelect(onChange="setLanguage(event)")
- each langCode in languages
- option(value=langCode selected=(lang==langCode))
- =langName[langCode]
- .section
- h3.blue Contribute
- p
- | Browse the
- a(href="https://github.com/yagu0/vchess/tree/master/views")
- | github repository
- | : all files in the folders langNames/, modal-help/, modal-lang/,
- | translations/ and welcome/ should be translated. Moreover, and
- | it's the longest part, you would have to translate all the rules under
- | rules/. When it's done, send me the files:
- a(href="mailto:contact@vchess.club?subject=[vchess.club] translation")
- | contact@vchess.club
- | . Thanks!
+++ /dev/null
-input#modalLang.modal(type="checkbox")
-div(role="dialog")
- #language.card
- label.modal-close(for="modalLang")
- .section
- fieldset
- label(for="langSelect") ¿ Idioma preferido ?
- select#langSelect(onChange="setLanguage(event)")
- each langCode in languages
- option(value=langCode selected=(lang==langCode))
- =langName[langCode]
- .section
- h3.blue Contribuir
- p
- | ¿ Tu idioma favorito no está disponible ? Entonces...
- | Navegar por el
- a(href="https://github.com/yagu0/vchess/tree/master/views")
- | repositorio github
- | : tiene que traducir todos los ficheros en los archivos langNames/,
- | modal-help/, modal-lang/, translations/ y welcome/.
- | Además, y esa es la parte principal del trabajo, tiene que traducir todas
- | las reglas en rules/. Una vez hecho esto, envíame los archivos :
- a(href="mailto:contact@vchess.club?subject=[vchess.club] translation")
- | contact@vchess.club
- | . ¡ Gracias !
+++ /dev/null
-input#modalLang.modal(type="checkbox")
-div(role="dialog")
- #language.card
- label.modal-close(for="modalLang")
- .section
- fieldset
- label(for="langSelect") Langue préférée ?
- select#langSelect(onChange="setLanguage(event)")
- each langCode in languages
- option(value=langCode selected=(lang==langCode))
- =langName[langCode]
- .section
- h3.blue Contribuer
- p
- | Votre langue favorite n'est pas disponible ? Alors...
- | Parcourez le
- a(href="https://github.com/yagu0/vchess/tree/master/views")
- | dépôt github
- | : il faut traduire tous les fichiers dans les dossiers langNames/,
- | modal-help/, modal-lang/, translations/ et welcome/. De plus, et c'est l'essentiel
- | du travail il faut traduire toutes les règles dans rules/.
- | Une fois que c'est fait, envoyez-moi les fichiers :
- a(href="mailto:contact@vchess.club?subject=[vchess.club] translation")
- | contact@vchess.club
- | . Merci !
--- /dev/null
+input#modal-settings.modal(type="checkbox")
+div(role="dialog" aria-labelledby="settingsTitle")
+ .card.smallpad(onChange="blabla(event)")
+ label#close-settings.modal-close(for="modal-settings")
+ h3#settingsTitle.section= translations["Preferences"]
+ fieldset
+ label(for="langSelect")= translations["Language"]
+ // image avec drapeau + select language ici
+ select#langSelect
+ each langCode in languages
+ option(value=langCode selected=(lang==langCode))
+ =langName[langCode]
+ fieldset
+ label(for="nameSetter")
+ =translations["My name is..."]
+ input#nameSetter(type="text" value=this.myname)
+ // theme sombre / clair
+ // taille echiquier : TODO
+ fieldset
+ label(for="setHints")= translations["Show hints?"]
+ input#setHints(type: "checkbox" checked=this.hints)
+ fieldset
+ label(for="selectColor")= translations["Board colors"]
+ select#selectColor
+ option(value="lichess" selected="this.color=='lichess'")
+ = translations["brown"]
+ option(value="chesscom" selected="this.color=='chesscom'")
+ = translations["green"]
+ option(value="chesstempo" selected="this.color=='chesstempo'")
+ = translations["blue"]
+ fieldset
+ label(for="selectSound")= translations["Play sounds?"]
+ select#selectSound
+ option(value="0" selected="this.sound==0")= translations["None"]
+ option(value="1" selected="this.sound==1")= translations["New game"]
+ option(value="2" selected="this.sound==2")= translations["All"]
-
var translations =
{
+ "Language": "Language",
+
// Index page:
"Help": "Help",
"First visit?": "First visit?",
-
var translations =
{
+ "Language": "Idioma",
+
// Index page:
"Help": "Ayuda",
"First visit?": "¿ Primera visita ?",
-
var translations =
{
+ "Language": "Langue",
+
// Index page:
"Help": "Aide",
"First visit?": "Première visite ?",
extends layout
block css
- link(rel="stylesheet" href="//fonts.googleapis.com/icon?family=Material+Icons")
link(rel="stylesheet" href="/stylesheets/variant.css")
block content
.container#variantPage
- include langNames.pug
- case lang
- when "en"
- include translations/en.pug
- include modal-lang/en.pug
- include modal-help/en.pug
- when "es"
- include translations/es.pug
- include modal-lang/es.pug
- include modal-help/es.pug
- when "fr"
- include translations/fr.pug
- include modal-lang/fr.pug
- include modal-help/fr.pug
- input#modal-newgame.modal(type="checkbox")
- div(role="dialog" aria-labelledby="newGameTxt")
- .card.smallpad.small-modal
- label#close-newgame.modal-close(for="modal-newgame")
- h3#newGameTxt= translations["New game"]
- p= translations["Waiting for opponent..."]
.row
.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
label.drawer-toggle(for="drawer-control")
input#drawer-control.drawer(type="checkbox")
#menuBar
label.drawer-close(for="drawer-control")
- a#homeLink(href="/")
+ a.icon-link(href="/")
i.material-icons home
- .info-container
- a(href="#rules" @click="setDisplay('rules')")
- =translations["Rules"]
- a(href="#play" @click="setDisplay('play')")
- =translations["Play"]
- a(href="#problems" v-if="notDark()" @click="setDisplay('problems')")
- =translations["Problems"]
- #flagMenu.clickable(
- onClick="document.getElementById('modalLang').checked=true")
- img(src="/images/flags/" + lang + ".svg")
- #helpMenu.clickable(
- onClick="document.getElementById('modalHelp').checked=true")
- .info-container
- p= translations["Help"]
+ a(href="#room" @click="setDisplay('room')")
+ =translations["Hall"]
+ a(href="#gameList" @click="setDisplay('gameList')")
+ =translations["Play"]
+ a(href="#rules" @click="setDisplay('rules')")
+ =translations["Rules"]
+ a(href="#problems" @click="setDisplay('problems')")
+ =translations["Problems"]
+ #settings.clickable(
+ onClick="document.getElementById('modalSettings').checked=true")
+ i.material-icons settings
.row
+ my-room(v-show="display=='room'")
+ my-games-list(v-show="display=='gameList'")
my-rules(v-show="display=='rules'")
- my-game(v-show="display=='play'" v-bind:problem="problem")
- my-problems(v-if="notDark()" v-show="display=='problems'"
- v-on:show-problem="showProblem($event)")
+ my-problems(v-show="display=='problems'")
+ // my-game: for room and games-list components
+ my-game(v-show="display=='game'" :gameId="")
block javascripts
script(src="/javascripts/utils/misc.js")
const V = VariantRules; //because this variable is often used
const variant = "#{variant}";
const problemArray = !{JSON.stringify(problemArray)};
- const translations = !{JSON.stringify(translations)};
script(src="/javascripts/components/rules.js")
script(src="/javascripts/components/game.js")
script(src="/javascripts/components/problemSummary.js")
For informations about hundreds (if not thousands) of variants, you
can visit the excellent
#[a(href="https://www.chessvariants.com/") chessvariants] website.
- p#disableMsg.clickable(@click="markAsVisited")
- | Click here to not show this message next time
p.smallfont Image credit: #[a(href=wikipediaUrl) Wikipedia]
Pour s'informer sur des centaines de variantes (au moins), je vous invite à
visiter l'excellent site
#[a(href="https://www.chessvariants.com/") chessvariants].
- p#disableMsg.clickable(@click="markAsVisited")
- | Haga clic aquí para no mostrar este mensaje la próxima vez.
p.smallfont Credito de imagen : #[a(href=wikipediaUrl) Wikipedia]
Pour s'informer sur des centaines de variantes (au moins), je vous invite à
visiter l'excellent site
#[a(href="https://www.chessvariants.com/") chessvariants].
- p#disableMsg.clickable(@click="markAsVisited")
- | Cliquer ici pour ne pas montrer ce message la prochaine fois
p.smallfont Crédit image : #[a(href=wikipediaUrl) Wikipedia]