From d7c00f6a7d6ad573df2a27965bf763b3bb1d0c18 Mon Sep 17 00:00:00 2001
From: Benjamin Auder <benjamin.auder@somewhere>
Date: Fri, 21 Feb 2020 13:14:13 +0100
Subject: [PATCH] Fix ExtinctionRules position check, add prev/next buttons in
 problems page

---
 client/src/base_rules.js          |  6 ++++++
 client/src/translations/en.js     |  3 +++
 client/src/translations/es.js     |  3 +++
 client/src/translations/fr.js     |  3 +++
 client/src/variants/Extinction.js | 17 ++++++++++++++++
 client/src/views/Problems.vue     | 32 +++++++++++++++++++++----------
 6 files changed, 54 insertions(+), 10 deletions(-)

diff --git a/client/src/base_rules.js b/client/src/base_rules.js
index 295b4cd3..350e0de6 100644
--- a/client/src/base_rules.js
+++ b/client/src/base_rules.js
@@ -96,9 +96,12 @@ export const ChessRules = class ChessRules {
     if (position.length == 0) return false;
     const rows = position.split("/");
     if (rows.length != V.size.x) return false;
+    let kings = {};
     for (let row of rows) {
       let sumElts = 0;
       for (let i = 0; i < row.length; i++) {
+        if (['K','k'].includes(row[i]))
+          kings[row[i]] = true;
         if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
         else {
           const num = parseInt(row[i]);
@@ -108,6 +111,9 @@ export const ChessRules = class ChessRules {
       }
       if (sumElts != V.size.y) return false;
     }
+    // Both kings should be on board:
+    if (Object.keys(kings).length != 2)
+      return false;
     return true;
   }
 
diff --git a/client/src/translations/en.js b/client/src/translations/en.js
index 6d5d0ec2..2d7ccce5 100644
--- a/client/src/translations/en.js
+++ b/client/src/translations/en.js
@@ -61,11 +61,13 @@ export const translations = {
   "My problems": "My problems",
   "Name: alphanumerics and underscore": "Name: alphanumerics and underscore",
   "Name or Email": "Name or Email",
+  Next: "Next",
   "New connexion detected: tab now offline": "New connexion detected: tab now offline",
   "New correspondance game:": "New correspondance game:",
   "New game": "New game",
   "New problem": "New problem",
   News: "News",
+  "No more problems": "No more problems",
   "No subject. Send anyway?": "No subject. Send anyway?",
   None: "None",
   "Notifications by email": "Notifications by email",
@@ -81,6 +83,7 @@ export const translations = {
   "Please select a variant": "Please select a variant",
   Practice: "Practice",
   "Prefix?": "Prefix?",
+  Previous: "Previous",
   "Processing... Please wait": "Processing... Please wait",
   Problems: "Problems",
   "participant(s):": "participant(s):",
diff --git a/client/src/translations/es.js b/client/src/translations/es.js
index 192c5320..f004b123 100644
--- a/client/src/translations/es.js
+++ b/client/src/translations/es.js
@@ -61,11 +61,13 @@ export const translations = {
   "My problems": "Mis problemas",
   "Name: alphanumerics and underscore": "Nombre: alfanuméricos y underscore",
   "Name or Email": "Nombre o Email",
+  Next: "Próximo",
   "New connexion detected: tab now offline": "Nueva conexión detectada: pestaña ahora desconectada",
   "New correspondance game:": "Nueva partida por correspondencia:",
   "New game": "Nueva partida",
   "New problem": "Nuevo problema",
   News: "Noticias",
+  "No more problems": "No mas problemas",
   "No subject. Send anyway?": "Sin asunto. ¿Enviar sin embargo?",
   None: "Ninguno",
   "Notifications by email": "Notificaciones por email",
@@ -81,6 +83,7 @@ export const translations = {
   "Please select a variant": "Por favor seleccione una variante",
   Practice: "Práctica",
   "Prefix?": "¿Prefijo?",
+  Previous: "Anterior",
   "Processing... Please wait": "Procesando... por favor espere",
   Problems: "Problemas",
   "participant(s):": "participante(s):",
diff --git a/client/src/translations/fr.js b/client/src/translations/fr.js
index e229d0a0..de8b1dae 100644
--- a/client/src/translations/fr.js
+++ b/client/src/translations/fr.js
@@ -61,11 +61,13 @@ export const translations = {
   "My problems": "Mes problèmes",
   "Name: alphanumerics and underscore": "Nom: alphanumériques et underscore",
   "Name or Email": "Nom ou Email",
+  Next: "Suivant",
   "New connexion detected: tab now offline": "Nouvelle connexion détectée : onglet désormais hors ligne",
   "New correspondance game:": "Nouvelle partie par corespondance :",
   "New game": "Nouvelle partie",
   "New problem": "Nouveau problème",
   News: "Nouvelles",
+  "No more problems": "Plus de problèmes",
   "No subject. Send anyway?": "Pas de sujet. Envoyer quand-même ??",
   None: "Aucun",
   "Notifications by email": "Notifications par email",
@@ -81,6 +83,7 @@ export const translations = {
   "Please select a variant": "Sélectionnez une variante SVP",
   Practice: "Pratiquer",
   "Prefix?": "Préfixe ?",
+  Previous: "Précédent",
   "Processing... Please wait": "Traitement en cours... Attendez SVP",
   Problems: "Problèmes",
   "participant(s):": "participant(s) :",
diff --git a/client/src/variants/Extinction.js b/client/src/variants/Extinction.js
index 75db0e11..8896292a 100644
--- a/client/src/variants/Extinction.js
+++ b/client/src/variants/Extinction.js
@@ -1,6 +1,23 @@
 import { ChessRules } from "@/base_rules";
 
 export const VariantRules = class ExtinctionRules extends ChessRules {
+  static IsGoodPosition(position) {
+    if (!ChessRules.IsGoodPosition(position))
+      return false;
+    // Also check that each piece type is present
+    const rows = position.split("/");
+    let pieces = {};
+    for (let row of rows) {
+      for (let i = 0; i < row.length; i++) {
+        if (isNaN(parseInt(row[i])) && !pieces[row[i]])
+          pieces[row[i]] = true;
+      }
+    }
+    if (Object.keys(pieces).length != 12)
+      return false;
+    return true;
+  }
+
   setOtherVariables(fen) {
     super.setOtherVariables(fen);
     const pos = V.ParseFen(fen).position;
diff --git a/client/src/views/Problems.vue b/client/src/views/Problems.vue
index 338eaaf2..30d3356d 100644
--- a/client/src/views/Problems.vue
+++ b/client/src/views/Problems.vue
@@ -47,19 +47,16 @@ main
   .row(v-if="showOne")
     .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
       #topPage
+        .button-group(v-if="st.user.id == curproblem.uid")
+          button(@click="editProblem(curproblem)") {{ st.tr["Edit"] }}
+          button(@click="deleteProblem(curproblem)") {{ st.tr["Delete"] }}
         span.vname {{ curproblem.vname }}
         span.uname ({{ curproblem.uname }})
         button.marginleft(@click="backToList()") {{ st.tr["Back to list"] }}
-        button.nomargin(
-          v-if="st.user.id == curproblem.uid"
-          @click="editProblem(curproblem)"
-        )
-          | {{ st.tr["Edit"] }}
-        button.nomargin(
-          v-if="st.user.id == curproblem.uid"
-          @click="deleteProblem(curproblem)"
-        )
-          | {{ st.tr["Delete"] }}
+        button.nomargin(@click="gotoPrevNext($event,curproblem,1)")
+          | {{ st.tr["Previous"] }}
+        button.nomargin(@click="gotoPrevNext($event,curproblem,-1)")
+          | {{ st.tr["Next"] }}
       p.oneInstructions.clickable(
         v-html="parseHtml(curproblem.instruction)"
         @click="curproblem.showSolution=!curproblem.showSolution"
@@ -292,6 +289,21 @@ export default {
         this.showOne = true;
       });
     },
+    gotoPrevNext: function(e, prob, dir) {
+      const startIdx = this.problems.findIndex(p => p.id == prob.id);
+      let nextIdx = startIdx + dir;
+      while (
+        nextIdx >= 0 &&
+        nextIdx < this.problems.length &&
+        ((this.onlyMines && this.problems[nextIdx].uid != this.st.user.id) ||
+          (!this.onlyMines && this.problems[nextIdx].uid == this.st.user.id))
+      )
+        nextIdx += dir;
+      if (nextIdx >= 0 && nextIdx < this.problems.length)
+        this.setHrefPid(this.problems[nextIdx]);
+      else
+        alert(this.st.tr["No more problems"]);
+    },
     prepareNewProblem: function() {
       this.resetCurProb();
       window.doClick("modalNewprob");
-- 
2.44.0