ダガズ:リハーサル

画像 -本当じゃない! この物語はまったく間違ったことを述べています。

「しかし、あなたがこの物語で言われていることをすでに知っているなら、なぜそれを読むべきですか?」

「それから私は彼女を聞きたい!」



テッド・チャン「 あなたの人生の物語





これは、何かが突然機能し始める大きなイベントです。 わかりにくいJavaおよびJavaScriptコードのページ、さらに理解しにくいXML、ペイントで描かれた写真-これらすべてを一緒に!

これで、実行してタッチできます。 テストはより早く実行でき、今日に至りました。 しかし、テストを実際のプログラムと比較できますか? 実行可能なリリース! 多くの人にとって、このマイルストーンは道の終わりを示しています。



これが私の始まりにすぎないことを願っています...



強さのテストの最初のタスクとして、私は「スライディングパズル」を選択しました-可動部分を持つパズル。 それはすべてゲーム " 15 "とサムロイドから始まりました。 この優れた起業家は、解決策のない問題を解決するために多額の賞金を提供しました。 そして、世界は夢中になりました。 狂気の程度が落ち着いたとき、他の人々は、スポットの部分を一緒に貼り付けて、さらに面白い(しかしすでに解決された)パズルを得るよう提案しました。









パパのパズルは、おそらくこの種の最初のパズルとして知られています(その名前で1926年にアメリカで販売されました)。 大きな正方形を右下隅に移動する必要があります。 簡単です。 (ほとんど)行き止まりや分岐点はなく、迷うことは困難です。



正方形を左下隅に配置するのはもう少し困難です。 長方形のパーツの1つを2つの小さな正方形に切り、それを別の箱に入れると、さらに複雑なパズルを得ることができます。









子供の頃、彼らは私にこれをくれました。 私は彼女を決して決めませんでした。 フランスでは、このパズルは「L'Ane rouge」(レッドロバ)として知られています。 大きな正方形を底部、正確には中央に配置する必要があります(場合によっては、箱から引き出すための穴が開けられていました)。 私の知る限り、「赤いロバ」を解くために必要な移動の最小数は不明です。 Martin Gardnerは、彼の著書Mathematical Leisureで 、81の動きで構成されるソリューションを説明しています。



もちろん、「赤いロバ」は最も難しいパズルではありません。 このタイプのゲームは非常に多くあります(そしてそれらのいくつかは非常に複雑です)。 非凸部のパズルが知られています(「 マザーズパズル 」や「 エスコットパズル 」など)。 一部のキットは、歴史的な出来事(アメリカ大統領としてジョージワシントンの選出や有名なパイロットの飛行など)を称えるために設計されました。 それは、豊かで多様な世界全体です。



ゲーム「15」とは異なり、このようなパズルに解決策があるかどうかを判断する簡単な方法はありません。 多すぎ! 驚くことではないが、プログラマは彼らのために非常に不均一呼吸している。 私のこの習慣も通りませんでした。 Delphiを習得したときに「赤いロバ」をやった。 その後、Android用のモバイルアプリケーションを開発しました。 今、私はそれをやり直していますが、今回はパズル自体は目標ではありません-それらは私が選択したアプローチが機能していることを確認するための単なる方法です。 より用途の広い製品の私的使用。



Dagazの観点からすると、パズルはシングルプレイヤーゲームです。 ボードとピースがあり、移動のルールとゲームを終了するための条件があります。 2人(またはそれ以上のプレイヤー)間の相互作用はありません。 これは、より複雑なゲームの実装に必要ないくつかのモジュールがなくてもプロジェクトを開始できるため、私にとって便利です。 これはゼロ反復です。 一種のプレリリースプロジェクト。



ZRFでのスライディングパズルの実装はどのようなものですか?
; for (2,1)-pieces (define shift2x1 ((verify (empty? w)) from w to cascade ee from w to (count-move) add) ((verify (empty? e)) from e to cascade ww from e to (count-move) add) (w (verify (piece? $1))(verify (empty? w)) e from w to cascade from w to (count-move) add) (e (verify (piece? $1))(verify (empty? e)) w from e to cascade from e to (count-move) add) ((verify (empty? n))(verify (empty? ne)) e (verify (piece? $1)) w from n to cascade se from n to (count-move) add) ((verify (empty? n))(verify (empty? nw)) w (verify (piece? $1)) e from n to cascade sw from n to (count-move) add) ((verify (empty? s))(verify (empty? se)) e (verify (piece? $1)) w from s to cascade ne from s to (count-move) add) ((verify (empty? s))(verify (empty? sw)) w (verify (piece? $1)) e from s to cascade nw from s to (count-move) add) (w (verify (empty? w)) (verify empty?) e from ww to cascade eee from ww to (count-move) add) (w (verify (piece? $1)) w (verify (empty? w)) (verify empty?) ee from ww to cascade e from ww to (count-move) add) (e (verify (empty? e)) (verify empty?) w from ee to cascade www from ee to (count-move) add) (e (verify (piece? $1)) e (verify (empty? e)) (verify empty?) ww from ee to cascade w from ee to (count-move) add) )
      
      





これは、タイルシェイプの調整された動きを制御するマクロの1つにすぎません! 具体的には、これにより、水平方向に回転する2x1ダイの動きが保証されます(垂直ダイには別のハードコードが使用されます)。 もちろん、 この恐ろしい恐怖は私の目標ではありません! ダガズでは、すべてがはるかに簡単です!



 (define step ( $1 add ))
      
      





以上です! もちろん、実生活ではすべてがそれほど単純ではありません。 パズルが正常に機能するためには、1つのダイを構成するタイルの形状が同期して移動する必要があります。 さらに、ボード上にある他のサイコロのタイルに「ぶつからない」ようにしてください。 これらすべてをZRFで説明するのは非常に困難です。 これを行う意味はまったくありません。



JavaScriptはこれをはるかに簡単にします!
 var distinctMode = false; var isEqual = function(a, b) { if ((a == 0) || (b == 0)) return false; return a == b; } var isEmpty = function(board, pos, value) { var piece = board.getPiece(pos); if (piece === null) return true; return isEqual(piece.getValue(0), value); } var isSubset = function(x, y) { for (var i = 0; i < x.actions.length; i++) { var action = x.actions[i]; if (_.chain(y.actions) .filter(function(a) { return a[0][0] == action[0][0] && a[1][0] == action[1][0]; }) .size() .value() == 0) return false; } return true; } Dagaz.Model.getPieceTypes = function(piece, board) { var tag = piece.getValue(0); return _.chain(board.pieces) .compact() .filter(function(piece) { return piece.getValue(0) == tag; }) .map(function(piece) { return piece.type; }) .uniq() .value(); } var CheckInvariants = Dagaz.Model.CheckInvariants; Dagaz.Model.CheckInvariants = function(board) { _.chain(board.moves) .filter(function(move) { if (move.actions.length != 1) return false; var action = move.actions[0]; if (!action[0]) return false; if (!action[1]) return false; if (action[0][0] == action[1][0]) return false; if (board.getPiece(action[0][0]) === null) return false; return true; }) .each(function(move) { var design = board.game.design; var action = move.actions[0]; var from = action[0][0]; var delta = action[1][0] - from; var piece = board.getPiece(from); var value = piece.getValue(0); if (isEmpty(board, action[1][0], value)) { _.chain(_.range(design.positions.length)) .filter(function(pos) { return pos != from; }) .filter(function(pos) { if (board.getPiece(pos) === null) return false; return isEqual(board.getPiece(pos).getValue(0), value); }) .each(function(pos) { var target = pos + delta; if ((Dagaz.find(design.positions[pos], delta) < 0) || (target < 0) || (target >= design.positions.length) || !isEmpty(board, target, value)) { move.failed = true; } else { move.movePiece(pos, target, null, 1); } }); } else { move.failed = true; } }); if (distinctMode) { var moves = []; _.chain(board.moves) .filter(function(move) { return (_.isUndefined(move.failed)); }) .each(function(move) { if (_.chain(moves) .filter(function(m) { return isSubset(m, move) && isSubset(move, m); }) .size() .value() == 0) { moves.push(move); } }); board.moves = moves; } CheckInvariants(board); }
      
      





このモジュールは必要なすべてを行います。 はい、それは複雑ですが、一度だけ書かれた後、このタイプのすべてのパズルで再利用されます。 JavaScriptモジュールをJavaScriptで記述されたDagazコアに接続するのは、Zの何百ものGames WindowsアプリケーションでC ++で記述されたDDLエンジンをロードするよりもはるかに簡単です。 使ってみませんか?



  (option "smart-moves" from) (option "sliding-puzzle" true)
      
      





マジックモジュールは2番目のオプションで接続されます。 最初の図には、より友好的な人物の動きが含まれています。 新しいパズルを説明するには、他に何が必要ですか? ボードとプレイヤーを説明するための定型コードの少し:



  (players You) (turn-order You) (board (grid (start-rectangle 0 0 100 100) (dimensions ("a/b/c/d/e" (100 0)) ; files ("3/2/1" (0 100)) ; ranks ) (directions (n 0 -1) (s 0 1) (e 1 0) (w -1 0)) ) )
      
      





ボードのサイズが5x3でない場合、グリッド線をわずかに編集する必要があります。 次に、数字自体(タイル)について説明します。



 (define T (piece (name $1$2) (help " ") (image You "images/$1.bmp") (attribute value $2) (moves (step n) (step s) (step w) (step e) ) ) ) (T R0000 1) (T R0010C 2) (T R0001P 2) (T R0100C 3) (T R1000C 3) (T R0010P 4) (T R0001C 4) (T R0000P 5) (T R0100P 6) (T R1000P 6) (T R0000C 7) (T R0000 8) (T R0000 9)
      
      





「T」と呼ばれるマクロは、単調な記述の多くから私たちを救います。 図名の1と0は、ボード上のタイルの表示に使用される画像をエンコードします。 それらに追加される番号はグループ識別子です。 一致するタイルは一緒に移動します(これは、このような移動の可能性を確認するだけでなく、マジックスクリプトによって提供されます)。 数字の最初の配置を記述することは残っています:



  (board-setup (You (R00001 b3) (R0010C2 c3) (R0001P2 c2) (R0100C3 d3) (R1000C3 e3) (R0010P4 a2) (R0001C4 a1) (R0000P5 b2) (R0100P6 d2) (R1000P6 e2) (R0000C7 b1) (R00008 c1) (R00009 d1) ) )
      
      





そしてゲームの目標:



  (win-condition (You) (and (absolute-config R0010C2 (a2 b2 c2 d2 e2)) (absolute-config R0100C3 (a2 b2 c2 d2 e2)) (absolute-config R1000C3 (a2 b2 c2 d2 e2)) (absolute-config R0001C4 (a2 b2 c2 d2 e2)) (absolute-config R0000C7 (a2 b2 c2 d2 e2)) ))
      
      





すべてをまとめると、ほぼ正直なZRFファイルが得られますZillions of Gamesで実行すると、2つの理由で失敗します。



  1. 従来のZillions of Gamesは、「 スライディングパズル 」オプションについて何も知りません
  2. また、数値属性をサポートしていません(しかし、それは価値があります)


今、 Z2Jが登場しまし -これは、ZRFファイルをDagazにとってより理解しやすいものに変えるための特別なユーティリティです。 Xalan XSLTプロセッサを使用してJavaで記述されています



 /usr/bin/java -classpath "./z2j.jar:./log4j-1.2.jar:./xalan-2.7.1.jar:./serializer-2.7.1.jar" com.gluk.z2j.app.App ./twins.zrf
      
      





起動後、ZRFファイルが配置された同じディレクトリに、さらに2つのファイルが表示されます(XMLファイルは無視できます。デバッグ用です)。 JavaScriptファイルには、モデルを構成するために必要なものがすべて含まれており、 htmlファイルは便宜上作成されています。 開始できます。





原則として、ZRFファイルを記述してJavaScriptコードに変換するこの部分はすべて、必要な設定をすべて手で入力することで省略できますが、この方法で入力することは非常に多く、間違いを犯しやすいです。 最も一般的なボード構成と移動パターンの作成をサポートする小さなライブラリを作成することを考えています。 これを行うと、ZRFファイルを作成できなくなり、JavaScriptコードの開発に制限されます。



結果は何ですか



私が選んだアプローチは、その価値を証明しています。 コードは無料ライセンスの下でレイアウトされており、希望する人はそれを使用できます。 ZRFファイルの中間作成は一部の人にとっては冗長に思えるかもしれませんが、私にとっては、Zillions of Gamesのアプリケーション開発の経験からすると、これは便利です。 ただし、このステップをオプションにするように取り組んでいます。 ボードゲームを起動するための重要な(そして非常に複雑な)モジュールと、もちろんボットがまだいくつかあります。 私もこれに取り組んでいます。 止まらない ボードゲームがたくさんあります 。 長い間十分です。




All Articles