Dagaz: une histoire de persistance

Toute technologie suffisamment avancée est indiscernable de la magie.
Arthur Clark
 
- Je ne veux plus être une comparaison ... Fais-moi une métaphore.
Chine Mieville


Travailler sur un grand projet est similaire à la plongée en métro . En résolvant des problèmes particuliers, nous ouvrons de nouvelles opportunités. Au fil du temps, ces opportunités se renforcent, se connectent à d'autres opportunités et cela nous permet de résoudre des problèmes anciens, beaucoup plus importants et complexes d'une manière nouvelle et complètement inattendue. J'ai un bon exemple à ce sujet. Et je veux parler de lui.

Le module de configuration commune a été conçu comme un simple outil de débogage. Souvent, il est très utile de pouvoir revenir à une position spécifique afin de localiser le problème. Mais cette disposition des figures se pose fugitivement dans le jeu, et sa restauration vaut un travail considérable. J'avais besoin d'un outil pour automatiser ce processus, et je l'ai fait. En fait, je peux facilement encoder n'importe quelle position en décrivant l'emplacement des pièces sur le plateau:

? setup = 0c3; 0a2; 0c2; 0d2; 1a1; 4b1; 5c1; 1d1; -1a4; 4b4; 5c4; 1d4; 0a3; 0d3; 0b2 ;; & turn = 0

Ensuite, je peux ajouter ces paramètres à l'url pour reproduire la position. C'est ce que fait la configuration commune. Le module enregistre la description de toutes les positions intermédiaires dans le journal et permet de les reproduire. Ce n'est pas un mécanisme très parfait. Par exemple, une telle description ne nous donne rien si nous ne savons pas à quel jeu elle appartient. Il y a d'autres lacunes, dont je parlerai plus tard. Maintenant, il est temps de rencontrer le prochain participant de notre histoire.


L'option de niveaux progressifs est venue de Zillions of Games et pendant longtemps je n'ai pas compris pourquoi elle était nécessaire. Essayez d'éteindre toutes les ampoules (c'est simple) et vous comprendrez de quoi je parle. Une fois que le joueur a gagné, progressif-level regarde l'url actuelle et s'il y trouve un nombre, l'augmente d'une unité. En fait, c'est un excellent moyen d'engager le joueur, mais ses capacités ne se limitent pas à cela. Il y a des jeux composés de plusieurs tours. Après avoir terminé un, les joueurs, selon certaines règles, redistribuent les pièces et recommencent à jouer.


Cette approche est souvent pratiquée dans le mankali africain . À Ovalhu , par exemple, le jeu ne recommence pas seulement. Les joueurs utilisent des grains capturés lors du tour précédent pour remplir initialement leurs trous. Les trous qui n'ont pas été remplis sont considérés comme abandonnés du jeu; ils ne peuvent pas être utilisés. En fait, à chaque tour, une nouvelle partie est jouée, sur un nouveau plateau. Ce n'est que lorsque le perdant au tour suivant, le joueur ne peut pas remplir au moins un trou, que sa défaite finale est reconnue.

Cette opportunité peut être comprise beaucoup plus largement.

, . common-setup . , , , . , .


, . «» , . , "Magyar Dama" ( , «»), Hive, , . , , , , , .


( , roguelike-). «», seed, . , ( ). (, ), .


, , . . "", , , , .

La prochaine étape a été franchie presque par accident. Il y a du son dans mes jeux. Je l'aime vraiment, mais il y a probablement des gens dans le monde qu'il agace. C'était pour eux qu'il était possible de l'éteindre. Il semblerait que cela fonctionnait bien, mais les paramètres n'étaient enregistrés nulle part et après chaque rafraîchissement de page, le son devait être à nouveau désactivé (et cela était encore plus gênant). On m'a demandé de résoudre ce problème d'une manière ou d'une autre et la première solution qui m'est venue à l'esprit était un cookie (la première solution n'est pas toujours réussie).

Voici à quoi ça ressemblait
Dagaz.Controller.sound = function() {
    if (Dagaz.Controller.soundOff) {
        sound.innerHTML = "no Sound";
        Dagaz.Controller.soundOff = false;
        document.cookie = "dagaz.sound=on";
    } else {
        sound.innerHTML = "Sound";
        Dagaz.Controller.soundOff = true;
        document.cookie = "dagaz.sound=off";
    }
}

Je ne voulais pas jeter de déchets, donc les cookies ont été de courte durée jusqu'à la fermeture de la fenêtre du navigateur. Et puis je me suis dit: "pourquoi ne pas enseigner la configuration commune à être également stockée dans les cookies?" J'ai dû définir le paramètre max-age , mais cela en valait la peine. Tout d'abord, l'état du jeu était désormais sauvegardé lorsque la fenêtre était accidentellement fermée. En prime, le changement de mode de jeu avec le bot AI / no AI n'a pas non plus réinitialisé le jeu. C'était génial!

Bien sûr, je devais prévoir autre chose
, , , , cookie ( ). «New game», . . , common-setup , ? cookie ( , ).

-
var getName = function() {
  var str = window.location.pathname.toString();
  var result = str.match(/\/([^.\/]+)\./);
  if (result) {
      return result[1].replace("-board", "").replace("-ai", "");
  } else {
      return str;
  }
}

var badName = function(str) {
  var result = str.match(/[?&]game=([^&*]*)/);
  if (result) {
      return result[1] != getName();
  } else {
      return true;
  }
}

var getCookie = function() {
  var str = document.cookie;
  var result = str.match(/dagaz\.(setup=[^*]*)/);
  if (result) {
      var r = decodeURIComponent(result[1]);
      if (badName(r)) return "";
      return "?" + r;
  } else {
      return "";
  }
}

var getSetup = function() {
  var str = window.location.search.toString();
  var result = str.match(/[?&]setup=([^&]*)/);
  if (result) {
      return result[1];
  } else {
      str = getCookie();
      result = str.match(/[?&]setup=([^&]*)/);
      if (result) {
          return result[1];
      } else {
          return "";
      }
  }
}

Dagaz.Model.getSetup = function(design, board) {
  var str = "";
  ...
  str = str + ";&turn=" + board.turn;
  if (Dagaz.Controller.persistense == "setup") {
      var s = str + "&game=" + getName() + "*";
      var maxage = getMaxage();
      if (maxage) {
        document.cookie = "dagaz.setup=" + encodeURIComponent(s) + "; max-age=" + maxage;
      } else {
        document.cookie = "dagaz.setup=" + encodeURIComponent(s);
      }
  }
  return "?setup=" + str;
}

, . , ( Pasang Chaturanji) , , , (Morris, Bolotoudou) common-setup , . , !


. ( , ). , Stratego Luzhanqi, ( ). (common-setup, , ), …


, , , common-setup , . ( Mana, , ), , .

, , . , random, c seed , , , - . , seed cookie, , , , .

Malheureusement, il existe des jeux pour lesquels la méthode d'enregistrement de l'état par le module de configuration commune n'est pas appropriée. Dans le Kamisado mentionné ci-dessus , la possibilité de terminer un coup (pour tous les coups sauf le tout premier) dépend du champ dans lequel le coup précédent a été accompli. Il existe des jeux avec des mécanismes encore plus complexes:


Dans le Moulin , en plus des mouvements habituels, il y a des bonus - si un joueur a arrangé ses trois pièces d'affilée, il a le droit de retirer la pièce d'un adversaire du plateau. De plus, les règles interdisent de construire le même triplet deux fois de suite. Tout cela signifie que pour que le jeu fonctionne correctement, vous devez sauvegarder l'historique des coups précédents. Heureusement, il existe une telle opportunité.

Le module de gestion de session enregistre l'historique du jeu, permettant au joueur de revenir en arrière un ou plusieurs coups, éventuellement en effectuant un autre. De plus, l'option conseiller est associée à ce mécanisme, qui indique au joueur un mouvement possible lors de la lecture avec le bot. Rétrospectivement, l'idée de sauvegarder l'historique du jeu dans les cookies semble évidente, mais je n'y suis pas tout de suite arrivée.

Le jeu de correspondance est apparu pour la première fois
Dagaz . - , "Zillions of Games", 1998 . 2003 Zillions , , . Ed van Zon . "MindSports", .


MindSports Dagaz . Ed , Java-, , , . , Ed Dagaz, .

, , , , . , Dagaz, , - backend-, JavaScript- . Ed session-manager, . , , , , , , ( , ), , .

SGF , , session-manager , SGF . , , , , SGF ( , ). , MindSports, , 80 Dagaz .

L'étape suivante était assez évidente: j'ai commencé à enregistrer la description SGF des parties dans un cookie, puis ils m'ont dit que ce n'était pas très moderne et j'ai tout déplacé vers localStorage (cela a simplifié le code et résolu certains problèmes de débogage dans Google Chrome). À ce stade, le lecteur peut avoir une question. J'ai deux mécanismes pour le même but, et l'un d'eux est plus parfait que l'autre. Pourquoi ne pas basculer tous les jeux en persistance de session? Malheureusement, ce n'est pas si simple.

Il existe des familles entières de jeux pour lesquelles les sessions de sauvegarde ne sont pas applicables:

  1. (Shatranj, Sittuyin, Janggi, Stratego, Luzhanqi, Banqi )
  2. , session-manager (Ur, Puluc, Shen, Backgammon, Chaturaji )
  3. (Kamisado, Washington, Ohvalhu)
  4. Enfin, il y a des jeux dans lesquels la persistance du gestionnaire de session ne peut pas être utilisée, pour des raisons de performance (curieusement, à Fanorona , pour toute sa simplicité apparente, au tout début du jeu, il y a un grand nombre de débuts possibles liés aux spécificités de la prise dans ce jeu)

En général, j'ai deux mécanismes conçus, en général, pour le même. Et c'est super, car je peux choisir lequel appliquer.

All Articles