- ZRFの記述をZ2JでJS/HTMLにトランスパイル
- トランスパイルされたファイルを編集する(※たぶんこのフェーズで参照するAIやアルゴリズムの変更とかをするんだと思う)
- こうして作られたゲームの記述はzrf-model.jsが合法手を生成するために使用される
- 複雑なルール(e.g. チェッカーの「着手を完全に終わらせてから取った駒を取り除く」)はZRFだと表現が難しい
- Z2J製のゲーム記述から生成された合法手に対して、特定の手を合法手から取り除いたり追加でアクションを実行したりする
- このメカニズムをextensionと呼ぶ(関数名:CheckInvariants)
- 例えばdeferred-captures.jsはextensionの一つ
- 各着手(movement)は、原始的なアクション(action)の流れを含むものとして表現される:
- あるマス目から他のマス目へと移動する行為(move)
- 盤上から駒を除去する行為(capture)
- 盤上に駒を追加する行為(drop)
- 着手(the move)は、複数のアクションからなる配列として表現される
- 各アクションは4つの要素を持つ配列として表現される:
- 1番目 [0] 着手(movement)の開始地点:moveとcaptureのアクションで利用される。dropの場合はnullになる
- 2番目 [1] 着手の終了地点:moveとdropのアクションで利用される。captureの場合はnullになる
- 3番目 [2] その着手において動く駒の種類:moveとdropのアクションで利用される。駒が成る場合の判定で使う
- 上記3つのパラメータもまたそれぞれ配列として表現されるが、現在のバージョンではその先頭の要素のみ利用している
- これは昔の設計が今でもまだ残っているせい
- 4番目の要素は「partial movesにおいて、複合的な着手(composite moves)を構成する、実行されたアクションの組を示すインデックス」を表す
- チェッカーで駒を取った時、その動きはmoveアクションとcaptureアクションの2つで表現される。
- deferred-captures extensionは、captureアクションの4番目の要素を書き換えて、手番(turn)の最後にそれを動かす(※captureアクションを実行する順番を着手の一番最後に持っていくということ?)
- 駒はthe compound grabsの最初で盤から取り除かれることをやめるので(?)、russian-captures.jsを使って追加のアクションを実行する
- ここでは、単純に「以前の手番で既にcaptureされた駒をcaptureしない」ようにしている
- extensionは複数を連鎖させて利用できる(extensions can be chained)
- ゲームそれ自体は3つの部分からなるアーキテクチャとなっている:
- Model(zrf-model.js):合法手の生成、ゲームの状態管理など
- View(2d-view-v2.js):canvasにゲームを描画する
- Controller(app-v2.js):eventsを管理し全てのmodeを一本に統括する
- Modelは、ゲームのルールを記述する「design部分」(ZrfDesign)と、ゲームの盤面状態を管理する「store部分」(ZrfBoard)を含んでいる
- 盤面部分(The board ※おそらくZrfBoardのこと)
- generateメソッドを用いて合法手のリストを生成することができる
- applyメソッドを用いて着手を行って新しい盤面状態を生成することができる
- デザイン(The design)の重要な部分は、盤面のトポロジー(=無数のpositionを繋ぐgraph)の記述
- navigateメソッドを用いて、あるpositionから別のpositionに動かす(※何を?)
- デザインは対局の間変化しない。盤面の状態も変化せず、着手を行うと新たな盤面が生成される
// dagaz.js
var Dagaz = {
Model: {},
View: {},
AI: {},
KPI: {},
Controller: {}
};
// some exception
var CheckInvariants = Dagaz.Model.CheckInvariants;
Dagaz.Model.CheckInvariants = function(board) {
var design = Dagaz.Model.design;
/* ... */
CheckInvariants(board);
}
// zrf-model.js
ZrfBoard.prototype.generateInternal = function(callback, cont, cover, serial) {
/* ... */
if (cont) {
Dagaz.Model.CheckInvariants(this);
Dagaz.Model.PostActions(this);
/* ... */
}
}
-
Z2Jの設計はあまりよくできていない
-
生成されたファイルを手動で編集する必要がある
-
可能ならZ2Jを使わない方向でに移行したい
-
XSLTでJS・HTMLに変換している
-
cf. https://github.com/GlukKazan/Dagaz/tree/master/utils/z2j/src/main/resources/xslt
-
Z2Jの設計は込み入っており、非常に手間なので自分は改修したくない
-
興味が有るなら、以下の手順でZ2Jを動かせる:
- Java SEをインストール
- z2j.cmd内のJavaへのpathを修正するなり何なりして、実行するためのスクリプトを整える
z2j.cmd example.zrf
-
うまく行ったら、変換されたファイルが生成されているはず
-
同時に生成されるXMLは昔デバッグ用に使ってたやつがそのままになってる
-
Dagaz.KPIはパフォーマンス向上のために使っていたが、効果がなかった。今では使っていない(deprecated)
-
今では代わりにstandard profiling toolsを使っている
-
ゲームの準備が行われる手順
-
ゲームの準備はDagaz.Model.BuildDesign() の中で行われ、盤面の準備と駒の準備という2つの部分に分けて行われる
-
盤面は、「方向(direction)」addDirectionと「位置(position)」addPositionによって定義されるグラフである
-
各位置では、各方向に対する位置を含んだ1次元配列内のオフセットを指定するベクトルが定義されている(?)
-
Zero valueが代入されていたら、それは接続が存在しないことを示す
-
こうすることで、盤上の移動が簡単な算術加算に単純化される
-
この操作は頻繁に行われるので高速でないといけない
ZrfDesign.prototype.navigate = function(player, pos, dir) {
if (this.positions[pos][dir] != 0) {
return + pos + this.positions[pos][dir];
} else {
return null;
}
}
- Z2Jの主な役割の一つは、盤面のグラフを構築すること
- しかしこの方式からの移行を始めている
- ZrfGridを用いることで簡単に盤面を記述できるようになっている(Z2Jは不要)
var g = design.addGrid();
g.addScale("A/B/C/D/E/F/G/H");
g.addScale("8/7/6/5/4/3/2/1");
g.addDirection("n",[ 0, -1]);
g.addDirection("nw",[-1, -1]);
g.addDirection("e",[ 1, 0]);
g.addDirection("ne",[ 1, -1]);
g.addDirection("w",[-1, 0]);
g.addDirection("sw",[-1, 1]);
g.addDirection("s",[ 0, 1]);
g.addDirection("se",[ 1, 1]);
design.addPlayer("White", [6, 7, 4, 5, 2, 3, 0, 1]);
design.addPlayer("Black", [6, 5, 2, 7, 4, 1, 0, 3]);
g.addPositions();
- 描画準備の部分(Dagaz.View.configure())は以下のように記述できる:
var b = view.root.addRegion(70, 0, 540, 540);
b.addBoard("WhiteBoard", [0]);
b.addBoard("BlackBoard", [1]);
var g = b.addGrid(31, 31, 89, 89);
g.addScale("A/B/C/D/E/F/G/H", 60, 0);
g.addScale("8/7/6/5/4/3/2/1", 0, 60);
g.addTurns(0, [0]);
g.addTurns(1, [1]);
design.addCommand(6, ZRF.FUNCTION, 24); // from
design.addCommand(6, ZRF.PARAM, 0); // $1
design.addCommand(6, ZRF.FUNCTION, 22); // navigate
design.addCommand(6, ZRF.FUNCTION, 3); // friend?
design.addCommand(6, ZRF.FUNCTION, 0); // not
design.addCommand(6, ZRF.FUNCTION, 20); // verify
design.addCommand(6, ZRF.FUNCTION, 25); // to
design.addCommand(6, ZRF.FUNCTION, 28); // end
design.addPiece("King", 5, 20000);
design.addMove(5, 6, [4], 0);
design.addMove(5, 6, [2], 0);
design.addMove(5, 6, [0], 0);
design.addMove(5, 6, [1], 0);
design.addMove(5, 6, [7], 0);
design.addMove(5, 6, [6], 0);
design.addMove(5, 6, [3], 0);
design.addMove(5, 6, [5], 0);
- この現状をどうにかしたい、よりヒューマンリーダブルな書き方にしたい
var step = function(ctx, params) {
if (ctx.go(params, 0) && !ctx.isFriend()) {
ctx.end();
}
};
design.addPiece("King", 5, 1000);
design.addMove(5, step, [4], 0);
design.addMove(5, step, [2], 0);
design.addMove(5, step, [0], 0);
design.addMove(5, step, [1], 0);
design.addMove(5, step, [7], 0);
design.addMove(5, step, [6], 0);
design.addMove(5, step, [3], 0);
design.addMove(5, step, [5], 0);
- russian-checkers.jsで定義されているもの:
- design.checkVersion (options modifying the game)
- design.addDirection (directions on the board)
- design.addPlayer (players and direction conversion rules)
- design.addTurn (turn order - not used in this game, because it corresponds to theorder in which the players are defined)
- design.addPosition (positions on the board and offsets for directions between them)
- design.addZone (special areas on the board)
- design.addCommand (description of moves of pieces by commands of the stackmachine - this part is obsolete)
- design.addPriority (priority on the mode of moves - captures in checkers are priority)
- design.addPiece (pieces and their cost)
- design.addMove (possible movement of pieces)
- design.setup (initial arrangement of pieces)
- view.defBoard, view.defPiece (graphic resources used)
- view.defPosition (screen coordinates of positions)
- underscore (a library that I use often)
- dagaz.js (creates a global name Dagaz that is used to communicate betweenmodules)
- zrf-model (universal game model)
- zobrist.js (Zobrist hashing)
- common-setup-v2.js (saving and reproducing the arrangement of pieces)
- 2d-view-v2.js (universal view)
- move-list-v1.js (converts a sequence of clicks into composite moves)
- session-manager.js (undo and redo)
- sound-manager-v2.js (sound effects)
- random-ai.js, uct-ai-v4.js, forced-ai.js, sgf-parser.js, russian.js, sgf-ai-v2.js, russian-checkers-extension.js (AI)
- deferred-captures.js (pieces are removed from the board only at the end of the move)
- russian-captures.js (small bugfix)
- russian-checkers.js (game configuration)
- app-v2.js (universal controller)
- Dagazにおけるmoveの表現(以下の要素から成る配列):
- 0番目:配列(大抵は要素1つだけ)。着手の開始位置を表す。囲碁のようなdrop-moveの場合はnull
- 1番目:配列(大抵は要素1つだけ)。着手の終了位置を表す。capture-moveの場合はnull
- 2番目:成る駒の配列(nullになることはない)
- 3番目:move execution phase