Dagaz: A Persistence Story

Any sufficiently advanced technology is indistinguishable from magic.
Arthur Clark
 
- I don't want to be a comparison anymore ... Make me a metaphor.
China Mieville


Working on a large project is similar to metro diving . Solving particular problems, we open up new opportunities. Over time, these opportunities grow stronger, connect with other opportunities and this allows us to solve old, much more important and complex problems in a new, completely unexpected way. I have a good example on this subject. And I want to talk about him.

The common-setup module was conceived as a simple debugging tool. Often, it is very useful to be able to return to a specific position in order to localize the problem. But this arrangement of figures arises in the game fleetingly, and its restoration is worth considerable work. I needed a tool to automate this process, and I did it. In fact, I can easily encode any position by describing the location of the pieces on the board:

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

Then, I can add these parameters to the url to reproduce the position. This is what common-setup does. The module saves the description of all intermediate positions in the log and makes it possible to reproduce them. This is not a very perfect mechanism. For example, such a description does not give us anything if we do not know which game it belongs to. There are other shortcomings, which I will discuss later. Now, it's time to meet the next participant in our story.


The progressive-levels option came from Zillions of Games and for a long time I did not understand why it was needed. Try to turn off all the bulbs (it's simple) and you will understand what I'm talking about. After the player wins, progressive-levels looks at the current url, and if he finds a number in it, increases it by one. In fact, this is a great way to engage the player, but his capabilities are not limited to this. There are games consisting of several rounds. Having finished one, players, according to certain rules, redistribute pieces and begin to play again.


This approach is often practiced in African mankali . In Ovalhu , for example, the game does not just start again. Players use grains captured in the previous round to initially fill their holes. Holes that failed to be filled are considered to be dropped out of the game; they cannot be used. In fact, in each round a new game is played, on a new board. Only when the loser in the next round, the player cannot fill at least one hole, his final defeat is recognized.

This opportunity can be understood much wider.

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


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


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


, , . . "", , , , .

The next step was taken almost by accident. There is sound in my games. I really like him, but there are probably people in the world whom he annoys. It was for them that it was possible to turn it off. It would seem that this worked well, but the settings were not saved anywhere and after each page refresh the sound had to be turned off again (and this annoyed even more). I was asked to somehow fix this problem and the first solution that came to my mind was a cookie (the first solution is not always successful).

Here is how it looked
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";
    }
}

I didn’t want to litter, so the cookies were short-lived until the browser window was closed. And then I thought: “why not teach common-setup to be stored in cookies too?” I had to set the max-age parameter , but it was worth it. Firstly, the state of the game was now saved when the window was accidentally closed. As a bonus, switching the game mode with the AI ​​/ no AI bot also did not reset the game. That was great!

Of course, I had to provide for something else
, , , , 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, , , , .

Unfortunately, there are games for which the method of saving state by the common-setup module is not suitable. In the Kamisado mentioned above , the ability to complete a move (for all moves except the very first) depends on which field the previous move was completed. There are games with even more complex mechanics:


In the Mill , in addition to the usual moves, there are bonus ones - if a player has arranged his three pieces in a row, he has the right to remove one opponent’s piece from the board. In addition, the rules prohibit building the same triplet twice in a row. All this means that for the game to work correctly, you must save the history of previous moves. Fortunately, there is such an opportunity.

The session-manager module saves the game’s history, allowing the player to go back one or more moves, possibly performing another move. Also, the advisor option is associated with this mechanism, which tells the player a possible move when playing with the bot. In retrospect, the idea of ​​saving the history of the game in cookies seems obvious, but I did not come to it right away.

Correspondence game first appeared
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 .

The next step was pretty obvious - I began to save the SGF- description of the parties in cookies, and then they told me that it was not very modern and I moved everything to localStorage (this simplified the code and solved some debugging problems in Google Chrome). At this point, the reader may have a question. I have two mechanisms for the same purpose, and one of them is more perfect than the other. Why not switch all games to session persistence? Unfortunately, this is not so simple.

There are entire families of games for which saving sessions is not applicable:

  1. (Shatranj, Sittuyin, Janggi, Stratego, Luzhanqi, Banqi )
  2. , session-manager (Ur, Puluc, Shen, Backgammon, Chaturaji )
  3. (Kamisado, Washington, Ohvalhu)
  4. Finally, there are games in which session-manager persistence cannot be used, for performance reasons (oddly enough, in Fanorona , for all its apparent simplicity, at the very beginning of the game, there are a huge number of possible debuts related to the specifics of taking in this game)

In general, I have two mechanisms designed, in general, for the same. And this is great, because I can choose which one to apply.

All Articles