When quit, send mdisconnect (relayed by server if no other MyGames tab).
And remove current "notify through newmove" on server in sockets.js
-Analyse mode when launched from a position: should keep orientation
---> $route query param, "side=w or b"
-
-Subcursor (intra move) for multi-move variants for better navigation (in BaseGame)
-
-Allow symmetric mode in all variants (vertical symmetry for racing kings)
-flag in challenge, "Symmetric: true / false", option of GenRandInitFen()
-
# Misc:
Saw once a "double challenge" bug, one anonymous and a second one logged
Both were asked a challenge probably, and both challenges added as different ones.
/////////////
// FEN UTILS
- // Setup the initial random (assymetric) position
- static GenRandInitFen() {
+ // Setup the initial random (asymmetric) position
+ static GenRandInitFen(randomness) {
+ if (!randomness) randomness = 2;
+ if (randomness == 0)
+ // Deterministic:
+ return "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w 0 1111 -";
+
let pieces = { w: new Array(8), b: new Array(8) };
- // Shuffle pieces on first and last rank
+ // Shuffle pieces on first (and last rank if randomness == 2)
for (let c of ["w", "b"]) {
+ if (c == 'b' && randomness == 1) {
+ pieces['b'] = pieces['w'];
+ break;
+ }
+
let positions = ArrayFun.range(8);
// Get random squares for bishops
this.lastMove = null;
},
analyzePosition: function() {
- const newUrl =
+ let newUrl =
"/analyse/" +
this.game.vname +
"/?fen=" +
this.vr.getFen().replace(/ /g, "_");
+ if (this.game.mycolor)
+ newUrl += "&side=" + this.game.mycolor;
// Open in same tab in live games (against cheating)
if (this.game.type == "live") this.$router.push(newUrl);
else window.open("#" + newUrl);
}
};
const playMove = () => {
- const animate = V.ShowMoves == "all" && received;
+ const animate = V.ShowMoves == "all" && (received || navigate);
if (!Array.isArray(move)) move = [move];
let moveIdx = 0;
let self = this;
th {{ st.tr["Variant"] }}
th {{ st.tr["With"] }}
th {{ st.tr["Cadence"] }}
+ th {{ st.tr["Random?"] }}
tbody
tr(
v-for="c in sortedChallenges"
td {{ c.vname }}
td {{ withWho(c) }}
td {{ c.cadence }}
+ td(:class="getRandomnessClass(c)")
</template>
<script>
if (c.from.sid == this.st.user.sid || c.from.id == this.st.user.id)
return c.to || this.st.tr["Any player"];
return c.from.name || "@nonymous";
+ },
+ getRandomnessClass: function(c) {
+ return {
+ ["random-" + c.randomness]: true
+ };
}
}
};
font-style: italic
tr.toyou > td
background-color: #fcd785
+
+tr > td:last-child
+ &.random-0
+ background-color: #FF5733
+ &.random-1
+ background-color: #2B63B4
+ &.random-2
+ background-color: #33B42B
</style>
A few years later I had a prototype to play in live, then other variants
were added and the website was made more attractive.
-h3 Philosophy
+h3 Notes
-p Have fun and challenge your mind :-)
-ul
- li ELO rating is purposely absent from this website.
- li Games start with a random assymetric position.
+p ELO rating is purposely absent from this website.
+
+p.
+ Games start by default with a random asymmetric position.
+ Random symmetric or even deterministic positions are available too,
+ if you prefer more fairness (but less fun? :-P ).
h3 Contribute
para jugar en vivo, y luego otras variantes se agregaron
y el sitio se hizo más atractivo.
-h3 FilosofÃa
+h3 Notas
-p Diviértete y desafÃa tu mente:-)
-ul
- li El ranking ELO está ausente a propósito de este sitio.
- li Las partidas comienzan con una posición aleatoria no simétrica.
+p El ranking ELO está ausente a propósito de este sitio.
+
+p.
+ Las partidas comienzan por defecto con una posición aleatoria no simétrica.
+ Es posible una posición aleatoria simétrica o incluso determinista,
+ si prefieres más justicia (¿pero más aburrimiento? :-P).
h3 Contribuir
tard je disposais d'un prototype pour jouer en direct, puis d'autres
variantes se sont ajoutées et le site a été rendu plus attractif.
-h3 Philosophie
+h3 Notes
-p Exercez vos neurones en vous amusant :-)
-ul
- li Le classement ELO est à dessein absent de ce site.
- li Les parties démarrent avec une position aléatoire non symétrique.
+p Le classement ELO est à dessein absent de ce site.
+
+p.
+ Les parties démarrent par défaut avec une position aléatoire non symétrique.
+ Une position aléatoire symétrique ou même déterministe est possible,
+ si vous préférez plus de justice (mais plus d'ennui ? :-P ).
h3 Contribuer
"Any player": "Any player",
Apply: "Apply",
"Are you sure?": "Are you sure?",
+ "Asymmetric random": "Asymmetric random",
"Authentication successful!": "Authentication successful!",
"Back to Hall in 3 seconds...": "Back to Hall in 3 seconds...",
"Back to list": "Back to list",
"Correspondance games": "Correspondance games",
"Database error: stop private browsing, or update your browser": "Database error: stop private browsing, or update your browser",
Delete: "Delete",
+ Deterministic: "Deterministic",
Download: "Download",
Draw: "Draw",
"Draw offer only in your turn": "Draw offer only in your turn",
"Processing... Please wait": "Processing... Please wait",
Problems: "Problems",
"participant(s):": "participant(s):",
+ "Random?": "Random?",
+ "Randomness": "Randomness",
Refuse: "Refuse",
Register: "Register",
"Registration complete! Please check your emails now": "Registration complete! Please check your emails now",
Stop: "Stop",
"Stop game": "Stop game",
Subject: "Subject",
+ "Symmetric random": "Symmetric random",
"Terminate game?": "Terminate game?",
"Three repetitions": "Three repetitions",
Time: "Time",
"Any player": "Cualquier jugador",
Apply: "Aplicar",
"Are you sure?": "¿Está usted seguro?",
+ "Asymmetric random": "Aleatorio asimétrico",
"Authentication successful!": "¡Autenticación exitosa!",
"Back to Hall in 3 seconds...": "Regreso al salón en 3 segundos...",
"Back to list": "Volver a la lista",
"Correspondance games": "Partidas por correspondencia",
"Database error: stop private browsing, or update your browser": "Error de la base de datos: detener la navegación privada, o actualizar su navegador",
Delete: "Borrar",
+ Deterministic: "Determinista",
Download: "Descargar",
Draw: "Tablas",
"Draw offer only in your turn": "Oferta de tablas solo en tu turno",
"Processing... Please wait": "Procesando... por favor espere",
Problems: "Problemas",
"participant(s):": "participante(s):",
+ "Random?": "Aleatorio?",
+ "Randomness": "Grado de azar",
Refuse: "Rechazar",
Register: "Registrarse",
"Registration complete! Please check your emails now": "¡Registro completo! Revise sus correos electrónicos ahora",
Stop: "Interrupción",
"Stop game": "Terminar la partida",
Subject: "Asunto",
+ "Symmetric random": "Aleatorio simétrico",
"Terminate game?": "¿Terminar la partida?",
"Three repetitions": "Tres repeticiones",
Time: "Tiempo",
Apply: "Appliquer",
"Authentication successful!": "Authentification réussie !",
"Are you sure?": "Étes vous sûr?",
+ "Asymmetric random": "Aléatoire asymétrique",
"Back to Hall in 3 seconds...": "Retour au Hall dans 3 secondes...",
"Back to list": "Retour à la liste",
"Black to move": "Trait aux noirs",
"Correspondance games": "Parties par correspondance",
"Database error: stop private browsing, or update your browser": "Erreur de base de données : arrêtez la navigation privée, ou mettez à jour votre navigateur",
Delete: "Supprimer",
+ Deterministic: "Déterministe",
Download: "Télécharger",
Draw: "Nulle",
"Draw offer only in your turn": "Proposition de nulle seulement sur votre temps",
"Processing... Please wait": "Traitement en cours... Attendez SVP",
Problems: "Problèmes",
"participant(s):": "participant(s) :",
+ "Random?": "Aléatoire?",
+ "Randomness": "Degré d'aléa",
Refuse: "Refuser",
Register: "S'enregistrer",
"Registration complete! Please check your emails now": "Enregistrement terminé ! Allez voir vos emails maintenant",
Stop: "Arrêt",
"Stop game": "Arrêter la partie",
Subject: "Sujet",
+ "Symmetric random": "Aléatoire symétrique",
"Terminate game?": "Stopper la partie ?",
"Three repetitions": "Triple répétition",
Time: "Temps",
const mainTime = timeUnitToSeconds(mainTimeValue, mainTimeUnit);
let increment = 0;
if (tcParts.length >= 2) {
+ // Correspondance games don't use an increment:
+ if (mainTimeUnit == 'd') return null;
tcParts[1] += "s";
const incrementArray = tcParts[1].match(/^([0-9]+)([smhd]+)$/);
if (!incrementArray) return null;
return [];
}
- static GenRandInitFen() {
- return ChessRules.GenRandInitFen().replace(/ -$/, "");
+ static GenRandInitFen(randomness) {
+ return ChessRules.GenRandInitFen(randomness).replace(/ -$/, "");
}
getPotentialMovesFrom([x, y]) {
return [];
}
- static GenRandInitFen() {
- return ChessRules.GenRandInitFen().replace(/ -$/, "");
+ static GenRandInitFen(randomness) {
+ return ChessRules.GenRandInitFen(randomness).replace(/ -$/, "");
}
getPotentialMovesFrom([x, y]) {
);
}
- static GenRandInitFen() {
+ static GenRandInitFen(randomness) {
+ if (!randomness) randomness = 2;
+ if (randomness == 0)
+ return "rnbqkbnr/pppppppp/3A4/8/8/3a4/PPPPPPPP/RNBQKBNR w 0 1111 -";
+
let pieces = { w: new Array(8), b: new Array(8) };
let antikingPos = { w: -1, b: -1 };
for (let c of ["w", "b"]) {
+ if (c == 'b' && randomness == 1) {
+ pieces['b'] = pieces['w'];
+ break;
+ }
+
let positions = ArrayFun.range(8);
// Get random squares for bishops, but avoid corners; because,
return false;
}
- static GenRandInitFen() {
- return ChessRules.GenRandInitFen().replace("w 1111 -", "w -");
+ static GenRandInitFen(randomness) {
+ return ChessRules
+ .GenRandInitFen(randomness)
+ .replace("w 0 1111 -", "w 0 -");
}
static InArena(x) {
return 2;
}
- static GenRandInitFen() {
+ static GenRandInitFen(randomness) {
+ if (!randomness) randomness = 2;
+ if (randomness == 0)
+ // Deterministic:
+ return "rnbqkbnrm/pppppppp/8/8/8/8/PPPPPPPP/MNBKQBNR w 0";
+
let pieces = { w: new Array(8), b: new Array(8) };
// Shuffle pieces on first and last rank
for (let c of ["w", "b"]) {
+ if (c == 'b' && randomness == 1) {
+ pieces['b'] = pieces['w'];
+ break;
+ }
+
let positions = ArrayFun.range(8);
// Get random squares for every piece, totally freely
return evaluation;
}
- static GenRandInitFen() {
- const randFen = ChessRules.GenRandInitFen();
- // Add 16 pawns flags + empty cmove:
- return randFen.replace(" w 0 1111", " w 0 11111111111111111111 -");
+ static GenRandInitFen(randomness) {
+ return ChessRules.GenRandInitFen(randomness)
+ // Add 16 pawns flags + empty cmove:
+ .replace(" w 0 1111", " w 0 11111111111111111111 -");
}
static ParseFen(fen) {
this.pawnFlags = flags;
}
- static GenRandInitFen() {
+ static GenRandInitFen(randomness) {
+ if (!randomness) randomness = 2;
+ if (randomness == 0)
+ return "8/8/pppppppp/rnbqkbnr/8/8/PPPPPPPP/RNBQKBNR w 0 1111111111111111";
+
let pieces = { w: new Array(8), b: new Array(8) };
// Shuffle pieces on first and fifth rank
for (let c of ["w", "b"]) {
+ if (c == 'b' && randomness == 1) {
+ pieces['b'] = pieces['w'];
+ break;
+ }
+
let positions = ArrayFun.range(8);
// Get random squares for bishops
});
}
- static GenRandInitFen() {
- return ChessRules.GenRandInitFen() + " 0000000000 -";
+ static GenRandInitFen(randomness) {
+ return ChessRules.GenRandInitFen(randomness) + " 0000000000 -";
}
getFen() {
return 2;
}
- static GenRandInitFen() {
+ static GenRandInitFen(randomness) {
+ if (!randomness) randomness = 2;
+ if (randomness == 0) {
+ return "rnbqkmcbnr/pppppppppp/10/10/10/10/10/10/PPPPPPPPPP/RNBQKMCBNR " +
+ "w 0 1111 - 00000000000000";
+ }
+
let pieces = { w: new Array(10), b: new Array(10) };
// Shuffle pieces on first and last rank
for (let c of ["w", "b"]) {
+ if (c == 'b' && randomness == 1) {
+ pieces['b'] = pieces['w'];
+ break;
+ }
+
let positions = ArrayFun.range(10);
// Get random squares for bishops
);
}
- static GenRandInitFen() {
- return ChessRules.GenRandInitFen()
+ static GenRandInitFen(randomness) {
+ return ChessRules.GenRandInitFen(randomness)
.replace("w 0 1111 -", "w 0 1111")
.replace(
"/pppppppp/8/8/8/8/PPPPPPPP/",
return moves;
}
+ // Ignore randomness here: placement is always random asymmetric
static GenRandInitFen() {
let pieces = { w: new Array(8), b: new Array(8) };
// Shuffle pieces + pawns on two first ranks
return this.filterValid(this.getPotentialMovesFrom(sq));
}
- static GenRandInitFen() {
- let fen = ChessRules.GenRandInitFen();
- // Place hidden queens at random:
+ static GenRandInitFen(randomness) {
+ let fen = ChessRules.GenRandInitFen(randomness);
+ // Place hidden queens at random (always):
let hiddenQueenPos = randInt(8);
let pawnRank = "PPPPPPPP".split("");
pawnRank[hiddenQueenPos] = "T";
return ([V.KING, V.COMMONER].includes(b[1]) ? "Knightmate/" : "") + b;
}
- static GenRandInitFen() {
- let pieces = { w: new Array(8), b: new Array(8) };
- // Shuffle pieces on first and last rank
- for (let c of ["w", "b"]) {
- let positions = ArrayFun.range(8);
-
- // Get random squares for bishops
- let randIndex = 2 * randInt(4);
- const bishop1Pos = positions[randIndex];
- let randIndex_tmp = 2 * randInt(4) + 1;
- const bishop2Pos = positions[randIndex_tmp];
- positions.splice(Math.max(randIndex, randIndex_tmp), 1);
- positions.splice(Math.min(randIndex, randIndex_tmp), 1);
-
- // Get random squares for commoners
- randIndex = randInt(6);
- const commoner1Pos = positions[randIndex];
- positions.splice(randIndex, 1);
- randIndex = randInt(5);
- const commoner2Pos = positions[randIndex];
- positions.splice(randIndex, 1);
-
- // Get random square for queen
- randIndex = randInt(4);
- const queenPos = positions[randIndex];
- positions.splice(randIndex, 1);
-
- // Rooks and king positions are now fixed,
- // because of the ordering rook-king-rook
- const rook1Pos = positions[0];
- const kingPos = positions[1];
- const rook2Pos = positions[2];
-
- // Finally put the shuffled pieces in the board array
- pieces[c][rook1Pos] = "r";
- pieces[c][commoner1Pos] = "c";
- pieces[c][bishop1Pos] = "b";
- pieces[c][queenPos] = "q";
- pieces[c][kingPos] = "k";
- pieces[c][bishop2Pos] = "b";
- pieces[c][commoner2Pos] = "c";
- pieces[c][rook2Pos] = "r";
- }
- // Add turn + flags + enpassant
- return (
- pieces["b"].join("") +
- "/pppppppp/8/8/8/8/PPPPPPPP/" +
- pieces["w"].join("").toUpperCase() +
- " w 0 1111 -"
- );
+ static GenRandInitFen(randomness) {
+ return ChessRules.GenRandInitFen(randomness)
+ .replace(/n/g, 'c').replace(/N/g, 'C');
}
getPotentialMovesFrom([x, y]) {
return -super.evalPosition(); //better with less material
}
- static GenRandInitFen() {
+ static GenRandInitFen(randomness) {
+ if (!randomness) randomness = 2;
+ if (randomness == 0)
+ return "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w 0 -";
+
let pieces = { w: new Array(8), b: new Array(8) };
// Shuffle pieces on first and last rank
for (let c of ["w", "b"]) {
+ if (c == 'b' && randomness == 1) {
+ pieces['b'] = pieces['w'];
+ break;
+ }
+
let positions = ArrayFun.range(8);
// Get random squares for bishops
pieces["b"].join("") +
"/pppppppp/8/8/8/8/PPPPPPPP/" +
pieces["w"].join("").toUpperCase() +
+ // En-passant allowed, but no flags
" w 0 -"
- ); //en-passant allowed, but no flags
+ );
}
};
});
}
- static GenRandInitFen() {
- return ChessRules.GenRandInitFen() + " 0000000000";
+ static GenRandInitFen(randomness) {
+ return ChessRules.GenRandInitFen(randomness) + " 0000000000";
}
getFen() {
return { x: 11, y: 11 };
}
- static GenRandInitFen() {
+ static GenRandInitFen(randomness) {
+ if (!randomness) randomness = 2;
+ if (randomness == 0)
+ return "11/11/11/11/11/11/11/11/11/QRBNP1pnbrq/KRBNP1pnbrk w 0";
+
let pieces = { w: new Array(10), b: new Array(10) };
// Shuffle pieces on first and second rank
for (let c of ["w", "b"]) {
+ if (c == 'b' && randomness == 1) {
+ pieces['b'] = JSON.parse(JSON.stringify(pieces['w'])).reverse();
+ pieces['b'] =
+ pieces['b'].splice(5,10).reverse().concat(
+ pieces['b'].splice(0,5).reverse());
+ break;
+ }
+
// Reserve 4 and 5 which are pawns positions
let positions = ArrayFun.range(10).filter(i => i != 4 && i != 5);
];
}
- static GenRandInitFen() {
- return ChessRules.GenRandInitFen().replace("w 1111 -", "w");
+ static GenRandInitFen(randomness) {
+ return ChessRules.GenRandInitFen(randomness).replace("w 1111 -", "w");
}
getPotentialPawnMoves([x, y]) {
}
}
- static GenRandInitFen() {
+ static GenRandInitFen(randomness) {
// Add empty cmove:
- return ChessRules.GenRandInitFen() + " -";
+ return ChessRules.GenRandInitFen(randomness) + " -";
}
getFen() {
return super.getCurrentScore();
}
- static GenRandInitFen() {
- const randFen = ChessRules.GenRandInitFen();
- // Add check flags (at 0)
- return randFen.replace(" w 0 1111", " w 0 111100");
+ static GenRandInitFen(randomness) {
+ return ChessRules.GenRandInitFen(randomness)
+ // Add check flags (at 0)
+ .replace(" w 0 1111", " w 0 111100");
}
getFlagsFen() {
);
}
- static GenRandInitFen() {
+ static GenRandInitFen(randomness) {
+ if (!randomness) randomness = 2;
+ if (randomness == 0)
+ return "RNBQKBNR/PPPPPPPP/8/8/8/8/pppppppp/rnbqkbnr w 0";
+
let pieces = { w: new Array(8), b: new Array(8) };
for (let c of ["w", "b"]) {
+ if (c == 'b' && randomness == 1) {
+ pieces['b'] = pieces['w'];
+ break;
+ }
+
let positions = ArrayFun.range(8);
let randIndex = randInt(8);
return 2;
}
- static GenRandInitFen() {
+ static GenRandInitFen(randomness) {
+ if (!randomness) randomness = 2;
+ if (randomness == 0)
+ return "rnccwkqbbnr/ppppppppppp/11/11/11/11/11/11/PPPPPPPPPPP/RNBBQKWCCNR w 0 1111 -";
+
let pieces = { w: new Array(10), b: new Array(10) };
for (let c of ["w", "b"]) {
+ if (c == 'b' && randomness == 1) {
+ pieces['b'] = pieces['w'];
+ break;
+ }
+
let positions = ArrayFun.range(11);
// Get random squares for bishops + camels (different colors)
for (let idx of randIndexes.concat(randIndexes_tmp).sort((a, b) => {
return b - a;
})) {
- //largest indices first
+ // Largest indices first
positions.splice(idx, 1);
}
if (!routeFen) this.alertAndQuit("Missing FEN");
else {
this.gameRef.fen = routeFen.replace(/_/g, " ");
- this.initialize();
+ // orientation is optional: taken from FEN if missing
+ const orientation = this.$route.query["side"];
+ this.initialize(orientation);
}
},
methods: {
this.$router.replace(newUrl);
}, 500);
},
- initialize: async function() {
+ initialize: async function(orientation) {
// Obtain VariantRules object
await import("@/variants/" + this.gameRef.vname + ".js")
.then((vModule) => {
if (!V.CanAnalyze)
// Late check, in case the user tried to enter URL by hand
this.alertAndQuit("Analysis disabled for this variant");
- else this.loadGame();
+ else this.loadGame(orientation);
})
.catch((err) => { this.alertAndQuit("Mispelled variant name", true); });
},
- loadGame: function() {
+ loadGame: function(orientation) {
// NOTE: no need to set score (~unused)
this.game.vname = this.gameRef.vname;
this.game.fen = this.gameRef.fen;
this.curFen = this.game.fen;
this.adjustFenSize();
- this.game.mycolor = V.ParseFen(this.gameRef.fen).turn;
+ this.game.mycolor = orientation || V.ParseFen(this.gameRef.fen).turn;
this.$set(this.game, "fenStart", this.gameRef.fen);
},
// Triggered by "fenchange" emitted in BaseGame:
v-model="newchallenge.cadence"
placeholder="5+0, 1h+30s, 5d ..."
)
+ fieldset
+ label(for="selectRandomLevel") {{ st.tr["Randomness"] }}
+ select#selectRandomLevel(v-model="newchallenge.randomness")
+ option(value="0") {{ st.tr["Deterministic"] }}
+ option(value="1") {{ st.tr["Symmetric random"] }}
+ option(value="2") {{ st.tr["Asymmetric random"] }}
fieldset(v-if="st.user.id > 0")
label(for="selectPlayers") {{ st.tr["Play with?"] }}
input#selectPlayers(
vid: parseInt(localStorage.getItem("vid")) || 0,
to: "", //name of challenged player (if any)
cadence: localStorage.getItem("cadence") || "",
+ randomness: parseInt(localStorage.getItem("randomness")) || 2,
// VariantRules object, stored to not interfere with
// diagrams of targetted challenges:
V: null,
id: c.id,
from: this.st.user.sid,
to: c.to,
+ randomness: c.randomness,
fen: c.fen,
vid: c.vid,
cadence: c.cadence,
) {
let newChall = Object.assign({}, chall);
newChall.type = this.classifyObject(chall);
+ newChall.randomness = chall.randomness;
newChall.added = Date.now();
let fromValues = Object.assign({}, this.people[chall.from]);
delete fromValues["pages"]; //irrelevant in this context
}
// NOTE: "from" information is not required here
let chall = Object.assign({}, this.newchallenge);
+ delete chall["V"];
+ delete chall["diag"];
const finishAddChallenge = cid => {
chall.id = cid || "c" + getRandString();
// Remove old challenge if any (only one at a time of a given type):
// Remember cadence + vid for quicker further challenges:
localStorage.setItem("cadence", chall.cadence);
localStorage.setItem("vid", chall.vid);
+ localStorage.setItem("randomness", chall.randomness);
document.getElementById("modalNewgame").checked = false;
// Show the challenge if not on current display
if (
// These game informations will be shared
let gameInfo = {
id: getRandString(),
- fen: c.fen || V.GenRandInitFen(),
+ fen: c.fen || V.GenRandInitFen(c.randomness),
// White player index 0, black player index 1:
players: c.mycolor
? (c.mycolor == "w" ? [c.seat, c.from] : [c.from, c.seat])
uid integer,
target integer,
vid integer,
+ randomness integer,
fen varchar,
cadence varchar,
foreign key (uid) references Users(id),
* uid: user id (int)
* target: recipient id (optional)
* vid: variant id (int)
+ * randomness: integer in 0..2
* fen: varchar (optional)
- * cadence: string (3m+2s, 7d+1d ...)
+ * cadence: string (3m+2s, 7d ...)
*/
const ChallengeModel =
return (
c.vid.toString().match(/^[0-9]+$/) &&
c.cadence.match(/^[0-9dhms +]+$/) &&
+ c.randomness.toString().match(/^[0-2]$/) &&
c.fen.match(/^[a-zA-Z0-9, /-]*$/) &&
(!c.to || UserModel.checkNameEmail({name: c.to}))
);
db.serialize(function() {
const query =
"INSERT INTO Challenges " +
- "(added, uid, " + (!!c.to ? "target, " : "") + "vid, fen, cadence) " +
- "VALUES " +
- "(" + Date.now() + "," + c.uid + "," + (!!c.to ? c.to + "," : "") +
- c.vid + ",'" + c.fen + "','" + c.cadence + "')";
+ "(added, uid, " + (!!c.to ? "target, " : "") +
+ "vid, randomness, fen, cadence) " +
+ "VALUES " +
+ "(" + Date.now() + "," + c.uid + "," + (!!c.to ? c.to + "," : "") +
+ c.vid + "," + c.randomness + ",'" + c.fen + "','" + c.cadence + "')";
db.run(query, function(err) {
cb(err, {cid: this.lastID});
});
{
fen: req.body.chall.fen,
cadence: req.body.chall.cadence,
+ randomness: req.body.chall.randomness,
vid: req.body.chall.vid,
uid: req.userId,
to: req.body.chall.to, //string: user name (may be empty)