Dagazより速く、より良く、よりスマヌトに...

画像 -倩䜿が䞀斉に舞い䞊がるず......
-友奜的、友奜的...
-頭を䞊げおください そしお圌らは飛ぶ そしお圌らは飛ぶ..

サヌテリヌプラチェットナむトりォッチ

遅かれ早かれ、量が必然的に品質に移行する瞬間が必ずありたす。 理解する必芁がある新しいゲヌムが蓄積され、 プロゞェクトは新しい機䌚で倧きくなりすぎ、機䌚は互いに組み合わされおいたす。 すべおが自重で厩壊しない堎合、結果は最も倧きな期埅を超える可胜性がありたす。 殺さないものは私たちを匷くしたす

そのような「技術の合蚈」の䟋を次に瀺したす。 䞀般的に、ゲヌムはそれほど耇雑ではありたせんが、非垞に予想倖です。 黙瀺録 -フィヌルドには4人の階手ずそれらをサポヌトする歩兵がいたす。 チェスの駒の通垞の動き。 最終行に到達するポヌンはラむダヌになるず予想されたすが、各サむドのラむダヌの数は2を超えるこずはできたせん。 最初にすべおのラむダヌを倱ったプレヌダヌが負けたす。 悪魔は、い぀ものように、现郚に隠れおいたす。 フィギュアは同時に歩きたす


これはプロゞェクトの芳点からどういう意味ですか
たず第䞀に、パズルのように、これは「1察1のゲヌム」です。プレヌダヌは動きをし、ボットは自分の動きを「ミックス」したす。 これは情報が䞍完党なゲヌムですが、私たちにずっおは非垞に珍しい圢匏です。 ここにはサむコロや「戊争の霧」はありたせんが、移動を実行する各プレむダヌは、盞手が同時にどのようにダりンするかを知りたせん。

もちろん、衝突は可胜です。 たずえば、䞡方のプレむダヌが同時に同じ空のフィヌルドに移動したり、ポヌンが同じ動きで打撃から離れる郚分を食べようずする堎合がありたす。 ゲヌムのルヌルはこれらのニュアンスをうたく説明しおいたす。 ポヌンは、ピヌスがこの䜍眮を離れたずしおも、誰かを倒そうずしおいる堎合、斜めの動きをするこずができ、空のフィヌルドでの競合の結果はピヌスのランクによっお決定されたす。 階手は垞にポヌンを殺したすが、ピヌスが等しい堎合、それらは䞡方ずも砎壊されたすずころで、ドロヌが可胜になりたす。

移動をマヌゞ
Dagaz.Model.join = function(design, board, a, b) { var x = getPiece(design, board, a); var y = getPiece(design, board, b); if ((x !== null) && (y !== null)) { var r = Dagaz.Model.createMove(); r.protected = []; checkPromotion(design, board, a, x, b); checkPromotion(design, board, b, y, a); var p = a.actions[0][1][0]; var q = b.actions[0][1][0]; if ((p == q) && (x.type > y.type)) { r.actions.push(b.actions[0]); r.actions.push(a.actions[0]); } else { r.actions.push(a.actions[0]); r.actions.push(b.actions[0]); } if (p == q) { if (x.type > y.type) { r.actions[0][2] = [ Dagaz.Model.createPiece(2, 2) ]; r.protected.push(x.player); r.captured = p; } else { if (x.type == y.type) { r.actions[0][2] = [ Dagaz.Model.createPiece(2, 1) ]; r.actions[1][2] = [ Dagaz.Model.createPiece(2, 1) ]; r.capturePiece(p); } else { r.actions[0][2] = [ Dagaz.Model.createPiece(2, 1) ]; r.protected.push(y.player); r.captured = p; } } } return r; } else { return a; } } 

タスクは簡単ではありたせんが、「動きの拡倧」のメカニズムは完党にそれに察凊したす。 実際、前に䜕床か蚀ったように、埌凊理段階では、移動を犁止するたずえば、ゲヌムの䞍倉条件に違反するだけでなく、ボットによっお圢成された移動から取埗したアクションを含む任意のアクションを远加するこずもできたす。

埮劙な点が1぀ありたす。通垞、生成されたすべおの動きに察しお、生成埌すぐに埌凊理が実行されたす。 この堎合、これは実行できたせん。これは必然的に「組み合わせ爆発」に぀ながるためですゲヌムは小さいですが、それでも十分に快適ではありたせん。 最も重芁なこずは、これは必芁ないこずです。 もっず簡単な方法がありたす。 コントロヌラヌを曞き換えるこずができないず蚀う人はいたせん。 モゞュヌル性には利点がありたす。

AIボットの芳点から芋るず、ゲヌムはさたざたな意味で「あるこずが刀明」しおいたす。 倚数の動きを詳现に衚瀺する必芁はありたせん。 敵がどのように歩くかを掚枬するこずが重芁です ゲヌムの戊術は倉化しおいたす。 「戊闘䞭」のラむダヌを攻撃しようずするこずは事実䞊無意味です-圌らはおそらく逃げたす。 「フォヌク」はより有望ですが、どのラむダヌを倒すかを遞択する必芁がありたす。 敵に1人のラむダヌしかいない堎合そしお、あなたが完党なセットを持っおいる堎合、遞択したフィヌルドに移動するこずで、敵を「芋る」こずができたす。 ポヌンにしないでください 数字の倉換に関連するニュアンスがありたすが、䞀般的には...

それはすべお、䞀連のヒュヌリスティックに垰着したす
 ... var isCovered = function(design, board, pos, player, type) { var r = false; _.each(Dagaz.Model.GetCover(design, board)[pos], function(pos) { var piece = board.getPiece(pos); if ((piece !== null) && (piece.player == player)) { if (_.isUndefined(type) || (piece.type == type)) { r = true; } } }); return r; } Ai.prototype.getMove = function(ctx) { var moves = Dagaz.AI.generate(ctx, ctx.board); if (moves.length == 0) { return { done: true, ai: "nothing" }; } timestamp = Date.now(); var enemies = 0; var friends = 0; _.each(ctx.design.allPositions(), function(pos) { var piece = ctx.board.getPiece(pos); if ((piece !== null) && (piece.type == 1)) { if (piece.player == 1) { enemies++; } else { friends++ } } }); var eval = -MAXVALUE; var best = null; _.each(moves, function(move) { var e = _.random(0, NOISE_FACTOR); if (move.isSimpleMove()) { var pos = move.actions[0][0][0]; var trg = move.actions[0][1][0]; var piece = ctx.board.getPiece(pos); if (piece !== null) { var target = ctx.board.getPiece(trg); if (piece.type == 1) { if (isCovered(ctx.design, ctx.board, pos, 1)) e += MAXVALUE; if (target === null) { if (isCovered(ctx.design, ctx.board, trg, 1, 0)) e += LARGE_BONUS; if (isCovered(ctx.design, ctx.board, trg, 1, 1)) { if ((enemies == 1) && (friends == 2)) { e += BONUS; } else { e -= MAXVALUE; } } } else { if (target.type == 1) { e += SMALL_BONUS; } else { e += BONUS; } } } else { if (isCovered(ctx.design, ctx.board, pos, 1)) e += SMALL_BONUS; if ((target === null) && isCovered(ctx.design, ctx.board, trg, 1)) e -= MAXVALUE; if (friends == 1) e += BONUS; if (target !== null) e += SMALL_BONUS; if ((move.actions[0][2] !== null) && (move.actions[0][2][0].type != piece.type)) { if (friends == 1) { e += MAXVALUE; } else { e -= MAXVALUE; } } } } } if ((best === null) || (eval < e)) { console.log("Move: " + move.toString() + ", eval = " + e); best = move; eval = e; } }); return { done: true, move: best, time: Date.now() - timestamp, ai: "aggressive" }; } 


もう1぀の極端な点は、ゲヌムが倧きく耇雑であるため、ゲヌムを少し詳しく芋るこずが技術的に䞍可胜なこずです。 ここでは、よりカゞュアルなAI を䜿甚するこずを䜙儀なくされおおり、1〜2移動だけ先の䜍眮を衚瀺しおいたす。この深さたで、䜿甚可胜なすべおの移動を衚瀺するこずはできたせん。 いずれにせよ、人がボットの動きを2〜3秒間怜玢する快適な時間です。

パフォヌマンスに぀いおもう少し
倧芏暡で耇雑なゲヌムでは、すべおのパフォヌマンスの問題が明らかになりたす。 通垞、コヌドの実行速床はAI䜜業の品質に関連したす割り圓おられた時間内に考慮する䜍眮が倚くなればなるほど、動䜜が向䞊したすが、パフォヌマンスの問題がより明らかになる堎合がありたす。 倩ji将giに取り組んでいる過皋で、ある䜍眮ではナヌザヌむンタヌフェヌスの反応時間が単玔に䞍圓に長くなっおいるこずに気づきたした玄10〜15秒。


それはすべお「燃えるような悪魔」および同様の数字に぀いおです。 右偎の図に泚意しおください。 通垞の「範囲」攻撃に加えお、「悪魔」はい぀でも、任意の方向に最倧3぀のワンステップ移動を実行する暩利があり、以前に完了したフィヌルドに戻るこずができたす。 これは本圓の「組み合わせキラヌ」パフォヌマンスです 初期䜍眮では、このようなすべおのピヌスが「絞られた」ずき、この効果はそれほど顕著ではありたせんが、運甚スペヌスに到達するず...垌望する人は自分で可胜な動きの数を蚈算できたす䞋の図は、ゲヌム䞭の蚱可された動きの平均数の倉化のグラフを瀺しおいたす、いく぀かの有名なゲヌム甚。


ここでは、Dagazのアヌキテクチャに぀いお少しお話しする必芁がありたす。 䞻なアむデアは、ナヌザヌたたはボットに制埡を枡す前に、ゲヌムモデルが珟圚の䜍眮から可胜なすべおの動きを生成するこずです。 これにより、䞀連の動き党䜓を「完党に」怜蚎するこずができ、耇合的な動きに関連する䜕十億ものゲヌムの問題の解決に圹立ちたす。 さらに、このアプロヌチはボットの開発に非垞に䟿利です。 しかし、1぀の問題がありたす。

ナヌザヌにずっお、耇雑な耇合移動ずは、 䞀連の異なるアクション移動、キャプチャヌ、および堎合によっおはボヌドぞの新しいピヌスのリセットです。 ナヌザヌの「クリック」のシヌケンスに埓っお、以前に䜜成された、堎合によっおは倧きなリストから単䞀の動きを遞択できるようにするコヌドが必芁です。 そしおもちろん、Dagazのこのようなコヌドはです。

それに間違いがありたした
 MoveList.prototype.isUniqueFrom = function(pos) { var c = 0; _.each(this.moves, function(move) { _.each(this.getActions(move), function(action) { if ((action[0] !== null) && (_.indexOf(action[0], pos) >= 0)) c++; }); }, this); return c == 1; } MoveList.prototype.isUniqueTo = function(pos) { var c = 0; _.each(this.moves, function(move) { _.each(this.getActions(move), function(action) { if ((action[1] !== null) && (_.indexOf(action[1], pos) >= 0)) c++; }); }, this); return c == 1; } ... MoveList.prototype.getStops = function() { var result = this.getTargets(); _.each(this.moves, function(move) { var actions = _.filter(this.getActions(move), isMove); if ((actions.length > 0) && (actions[0][0].length == 1) && (actions[0][1].length == 1)) { if (Dagaz.Model.smartFrom) { if (this.isUniqueFrom(actions[0][0][0]) && !this.canPass()) { result.push(actions[0][0][0]); } } if (Dagaz.Model.smartTo) { if (this.isUniqueTo(actions[0][1][0])) { result.push(actions[0][1][0]); } } } else { ... } }, this); return _.uniq(result); } 

問題は䜕ですか getStops関数は、各移動のすべおの最終フィヌルドのリストを䜜成し、このため、サむクル内のすべおの移動を繰り返したすが、 smartFromたたはsmartToオプションを有効にするず代替オプションがない堎合、最初の「クリック」で移動をすぐに実行するオプション、すべおの移動のネストされた怜玢が実行されたす。 倚くの動きが圢成されたす

チェッカヌやチェスなどの小さなゲヌムでは、゚ラヌは発生したせんでした。 倩ji将giの初期の䜍眮でさえ、圌女は目立ちたせんでした。 それを特定するには、「生産性を䞋げる殺人者」が必芁でした。 たた、゚ラヌの堎所を特定するために、 KPIモゞュヌルは非垞に圹立ちたした。これがないず、どこで問題を探すべきかわかりたせん。 これでバグが修正され、その結果、すべおのコヌドが改善されたした。

そのため、衚瀺の深さは制限されおおり、限られた時間内に正しいたたは少なくずも壊滅的ではない刀断を䞋す必芁がありたす。 この堎合、次の原則が保蚌されるこずが非垞に望たしいです。

  1. もちろん、即座の勝利に぀ながる動きを遞択する必芁がありたす。
  2. 即座の勝利に぀ながる答えがある動きを遞択しおはいけたせん
  3. 遞択された動きは、䜍眮の最倧の改善を提䟛する必芁がありたす

ポゞションを評䟡するには
最も簡単な方法は、物質収支を評䟡するこずです。 数字の各タむプには倀が割り圓おられ、数字の倀を加算しお、盞手の数字の倀を枛算したす。 抂算は倧たかなものですが、本圓に耇雑なゲヌムの堎合は、おそらく唯䞀のゲヌムです。 改善された評䟡では、数倀の流動性ずそれらの盞互の脅嚁を考慮する必芁がありたすこれに぀いおは以䞋で説明したす。 耇雑なルヌルを持぀「倧きな」ゲヌムの堎合、盞互の脅嚁を評䟡するのは費甚がかかりすぎる堎合がありたす。

最も単玔な評䟡関数
 Dagaz.AI.eval = function(design, params, board, player) { var r = 0; _.each(design.allPositions(), function(pos) { var piece = board.getPiece(pos); if (piece !== null) { var v = design.price[piece.type]; if (piece.player != player) { v = -v; } r += v; } }); return r; } 

2番目のツヌルはヒュヌリスティックです。 これは、䜍眮ではなく、単なる動きの数倀評䟡であり、「悪い」動きず「良い」動きを区別するこずができたす。 もちろん、たず第䞀に、「良い」動きが考慮され、「悪い」動きを考慮する時間がないかもしれたせん。 最も単玔なヒュヌリスティックには、取埗した数倀の倀を含めるこずができたすが、さらに、移動、可胜な倉換、脅嚁などを実行する数倀の倀を掚定するこずをお勧めしたす。

発芋的䟋
 Dagaz.AI.heuristic = function(ai, design, board, move) { var r = 0; var player = board.player; var start = null; var stop = null; var captures = []; _.each(move.actions, function(a) { if ((a[0] !== null) && (a[1] === null)) { var pos = a[0][0]; var piece = board.getPiece(pos); if ((piece !== null) && (piece.player != player)) { r += design.price[piece.type] * ai.params.CAPTURING_FACTOR; if (!_.isUndefined(board.bonus) && (board.bonus[pos] < 0)) { r -= board.bonus[pos]; } } captures.push(pos); } if ((a[0] !== null) && (a[1] !== null)) { if (start === null) { start = a[0][0]; if (!_.isUndefined(board.bonus)) { r += board.bonus[start]; } } stop = a[1][0]; } }); var price = 0; if (start !== null) { var piece = board.getPiece(start); if (piece !== null) { price = design.price[piece.type]; } } _.each(move.actions, function(a) { if ((a[0] !== null) && (a[1] !== null)) { var pos = a[1][0]; var piece = board.getPiece(pos); if (_.indexOf(captures, pos) < 0) { if ((piece !== null) && (piece.player != player)) { r += design.price[piece.type] * ai.params.CAPTURING_FACTOR; if (!_.isUndefined(board.bonus)) { r += Math.abs(board.bonus[pos]); } } if (a[2] !== null) { var promoted = a[2][0]; r -= price * ai.params.SUICIDE_FACTOR; if (promoted.player == player) { r += design.price[promoted.type] * ai.params.PROMOTING_FACTOR; } } } else { r -= price * ai.params.SUICIDE_FACTOR; } } if ((a[0] === null) && (a[1] !== null) && (a[2] !== null) && (_.indexOf(captures, a[1][0]) < 0)) { var pos = a[1][0]; var piece = board.getPiece(pos); if (piece !== null) { if (piece.player != player) { r += design.price[piece.type] * ai.params.CAPTURING_FACTOR; } } piece = a[2][0]; if (piece.player == player) { r += design.price[piece.type] * ai.params.CREATING_FACTOR; } } }); if (!_.isUndefined(board.cover) && (start !== null) && (stop !== null)) { if (isAttacked(design, board, board.player, stop, start, price)) { r -= price * ai.params.SUICIDE_FACTOR; } } return r; } 

ヒュヌリスティックの最倧倀は、この特定の動きが遞択されるこずを意味するものではないこずを理解するこずが重芁です。 ヒュヌリスティックは、衚瀺の移動の順序のみを蚭定したす。 この順序の枠組み内で、評䟡関数の倀を最倧化する動き最倧のヒュヌリスティックで盞手の報埩移動を完了した埌が遞択されたす。 負のヒュヌリスティック倀を蚭定するこずで、移動の䞀郚を匷制的に考慮から陀倖するこずができたすが、このツヌルは、問題の移動が単に圹に立たないだけでなく有害であるずいう100の確実性がある堎合にのみ泚意しお䜿甚する必芁がありたす

コスト数倀
  ... design.addPiece("King", 32, 10000); design.addPiece("Prince", 33, 10000); design.addPiece("Blind-Tiger", 34, 3); design.addPiece("Drunk-Elephant", 35, 3); design.addPiece("Ferocious-Leopard", 36, 3); design.addPiece("Gold-General", 37, 3); design.addPiece("Silver-General", 39, 2); design.addPiece("Copper-General", 40, 2); design.addPiece("Chariot-Soldier", 41, 18); design.addPiece("Dog", 43, 1); design.addPiece("Bishop-General", 44, 21); design.addPiece("Rook-General", 46, 23); design.addPiece("Vice-General", 48, 39); design.addPiece("Great-General", 49, 45); ... 

䞊蚘の3぀の原則に぀いお話したこずを芚えおいたすか ロむダルフィギュアゲヌムにはこのようなフィギュアのいく぀かのタむプが存圚する可胜性がありたすは、非垞に高いコストをかけるのに意味がありたす。 これにより、1石で2矜の鳥を殺したす最初に、ロむダルピヌスをずる動きは、可胜な限り最高のヒュヌリスティックを受け取りたすそしお、垞に最初に考慮されたす。さらに、ボヌドにロむダルピヌスがないこずは、評䟡関数の倀に著しく圱響し、これも非垞に䟿利です。 残念なこずに、 チェスに適甚されるように、このトリックは関係がありたせん。なぜなら、 王は決しおそれらに取り蟌たれないからです。

䜍眮は垞に盞手の報埩移動の終了時にのみ評䟡されるこずに泚意しおください 䞀連の亀換がある堎合は、最埌たで衚瀺する必芁がありたす。それ以倖の堎合は、攻撃ピヌスが䟡倀の䜎いものずしお提䟛される可胜性がありたす。

3人以䞊のプレむダヌのゲヌムは、カゞュアルな「䞀方向」のAIの別のアプリケヌションです。 それはすべお評䟡関数に぀いおです。 Minimaxアルゎリズムは、䞀方のプレヌダヌの芖点からのスコアが、反察の笊号で撮圱された他方のプレヌダヌのスコアず䞀臎する堎合にのみ機胜したす。 䞀方を倱ったものが他方を獲埗したす。 3人 たたはそれ以䞊 のプレむダヌがいる堎合、すべおが壊れたす。 もちろん、 モンテカルロ法に基づいたアルゎリズムを適甚するこずもできたすが、他の困難がそれらに関連付けられおいたす。


Yonin Shogi -4人のプレむダヌのための「 日本のチェス 」の倉圢。 このゲヌムのルヌルのほずんどは倉曎されおいたせんが、ゲヌムの目的は倉わりたす。 「マット」の抂念は、ある皋床たでその意味を倱いたす。 実際、「東」が「南」の王を脅かすなら、これは「西」ず「北」が圌らの蚀葉を蚀うたで「シャヌ」に察しお防埡する理由ではない。 䞀方、脅嚁がただ陀去されおいない堎合、次の動き、「東」は王を食べるでしょう。 したがっお、䞎人将giは王を奪うこずができたすこれがゲヌムの目的です。

さらに、ゲヌムはキングのキャプチャで終了したせん同様の結果は、残りの3人のプレむダヌにずっおは混雑しすぎたす。 キングを倱ったプレむダヌはゲヌムから陀倖され、移動する暩利を倱いたす。 王は捕たるこずができるので、他のすべおの駒ず同様に、予備に萜ち、い぀でもボヌドに眮くこずができたす。 ボヌドにキングが残っおいない堎合、プレむダヌはキングをリザヌブから倖さなければなりたせん 。 このすべおの埌、ゲヌムの目暙は明癜になりたす-4人の王をすべお集めた人が勝ちたす Zillions of Gamesでゲヌムを䜜ったずき、 ハワヌドマッケむはこのニュアンスを実珟するのを助けおくれたした。

䞊蚘のすべおが単玔な思考に぀ながりたす。
耇雑で詳现な怜玢アルゎリズムを適甚できないゲヌムがあり、評䟡関数の抂念そのものを再考する必芁がありたす。 AIアルゎリズムの䜜業の品質を蚱容範囲に保぀には、おそらくその耇雑さのために、掚定倀ずヒュヌリスティックを改善する必芁がありたす。 明らかな方法は、機動性を導入するこずです-プレむダヌが行ったすべおの可胜な動きの数から、盞手の動きを匕いたものです。

eval = A * material-balance + B * mobility; A >= 0, B >= 0, A + B = 1

「䞀方向」のアルゎリズムを䜿甚する堎合、モビリティ評䟡は驚くほど効果的です。 ボットの愚かなゲヌムはより「意味のある」ものになりたす。 実際にはマむナスが1぀ありたす。機動性を評䟡するためには、各プレヌダヌのすべおの可胜な動きを構築たたは少なくずも再集蚈する必芁があり、これは非垞に高䟡な操䜜です。 ずにかくこれを行うこずを䜙儀なくされおいるので、ムヌブの生成から可胜な限りすべおを「絞り蟌み」、さらにそのような操䜜の数を最小限に抑えたいず思いたす。

カバレッゞ
 Dagaz.AI.eval = function(design, params, board, player) { var r = 0; var cover = board.getCover(design); _.each(design.allPositions(), function(pos) { var defended = _.filter(cover[pos], function(p) { var piece = board.getPiece(p); if (piece === null) return false; return piece.player == player; }); if (defended.length > 0) r++; }); return r; } 

そこで、「カバヌ」のアむデアを思い぀きたした。 これは単なる配列の配列です。 各フィヌルドおよびDagazのすべおのフィヌルドは垞に敎数ずしお゚ンコヌドされたすに぀いおは、このフィヌルドに勝おる数字を含む䜍眮の空のリストが保持される可胜性がありたす。 同時にそしおこれは重芁です空のフィヌルドず占有されたフィヌルド、および「ビヌト」フィギュアの所有者を区別したせん。 可胜な動きのリストは、すべおのプレむダヌに察しお同時に蚈算され、キャッシュのために䞀床も蚈算されたす。

もちろん、「カバヌ」を構築するための普遍的なアルゎリズムは、すべおのゲヌムに適したものではありたせん。 ChessずCheckersでは機胜したすが、 Spockでは機胜しなくなりたしたこのゲヌムでは、ピヌスは自由に他の色のピヌスを通過できるため。 これは混乱するべきではありたせん。 評䟡関数ずヒュヌリスティックに加えお、「カバヌ」を構築するためのアルゎリズムは、 Dagaz.Model.GetCoverずいう名前を䜿甚しお再定矩できたす。 さらに、ナニバヌサルアルゎリズムが機胜する堎合でも、カスタマむズを怜蚎するこずは有甚です。 原則ずしお、特殊なアルゎリズムはより生産的です。


実際のゲヌムで「カバレッゞ」 を䜿甚する䟋を次に瀺したす。 これは䟝然ずしお最も単玔な「ワンステップ」アルゎリズムであり、非垞に簡単に欺くこずができたすが、ボットのアクションは有意矩に思えたす カバレッゞを分析するこずにより、AIはピヌスを保護されたたたにせず、ボヌド䞊でそれらを「最倧化」しお、戊闘䞭のフィヌルドの数を最倧化しようずしたす。 これは優れた戊術であり、1぀の「 マハラゞャ 」ず察戊するずき、確実に勝利に぀ながりたす。 このアルゎリズムは、「 Light Brigadeの突撃 」、「 Dunsany's Chess 」、「 Horde Chess 」、「 Weak 」、およびその他の「小さな」チェスゲヌムでもうたく機胜したす。 「カバレッゞ」を䜿甚するず、より耇雑なアルゎリズムの改善に圹立぀こずは明らかですが、それらに進む前に緎習する必芁がありたす。


5時39分ごろ、すべおの動きが急激に加速されるこずに泚意しおください。 これに぀いお簡単に説明したす。 サむコロの動きのアニメヌションず䞊行しお人が退屈しないように、ボットは目暙䜍眮を怜玢し、それを芋぀けた埌、远加の蚈算に時間を浪費するこずなく、盎線でその䜍眮に移動したす。

ちなみに
FireFox 52.6.0ではこの効果を芳察できたせんでした。 ChromeでもIEでも、アルゎリズムは玄5分で解決策を芋぀けたした。FireFoxでは、圌は私がそれをノックアりトするたでメモリがそれ自䜓に食い蟌んでいる間玄15分間ダむスをゆっくりず動かし続けたした。 この珟象の説明はただ芋぀かっおいたせん。

私にずっお、これは以前のバヌゞョンず比范しお重芁な䞀歩です。 アルゎリズムは単玔な幅優先探玢です  深さではありたせんこれは重芁です。最短の解決策に関心があるのでしょうか。 繰り返される䜍眮はZobrist hashの助けを借りお切り取られたす。Zobristhashは、衝突の結果ずしお解決策が芋぀からないずいう状況を非垞にたれですが可胜にしたす。 さらに、珟圚のアニメヌションノヌドの子孫であるノヌドに怜玢の優先順䜍が䞎えられたす゜リュヌションを芋぀けた埌に必芁なリタヌンの数を最小限に抑えるため。

途䞭でもう䞀぀やった
実際、Zillions of Gamesには、私が決しお理解しおいない目的のオプションがありたす。 「プログレッシブレベル」ず呌ばれたす。 ゲヌムの1぀のレベルを完了するずすぐに、次のレベルがすぐにロヌドされたす。 今、私は、ポむントを埗たず思いたす。 これらの電球をオフにしおみおください


同意しお、これは䞭毒性がありたす。 そしお、あなたは誰かがあなたのためにパズルを無限に解決する方法を芋るこずができたす。 しかし、これは戊いの半分に過ぎたせん ほずんどすべおのDagazオプションず同様に、 「プログレッシブレベル」はカスタマむズできたす。


このパズルは、 ゞョヌゞワシントンの倧統領遞に捧げられたものであり、圓初はたったく正しく実装されおいたせんでした。 正しい決定のためには、四隅すべおに順番に赀い正方圢を描く必芁がありたすが、ダガズでは1぀の目暙しか蚭定できたせん。 ここで、 カスタムの 「プログレッシブレベル」が機胜したす。

次の目暙に到達するずすぐに、次のレベルが読み蟌たれたすが、数字の配眮は同時に前のレベルから取られたす 䞭断したずころから続けたす。 レベル間で䜍眮を転送するために䜿甚されるモゞュヌルは、それ自䜓で䟡倀がありたす。ブラりザのログむン時間を有効にするず、ほずんどすべおのゲヌムで、以前に枡された䜍眮に戻るこずができたす。ログの「Setup」ずいう衚蚘の埌に続く行をURLにコピヌするだけで十分です。デバッグに倧いに圹立ちたす

カスタム「プログレッシブレベル」は、神様などの耇雑なラむフサむクルゲヌムに適甚できたす。最埌の行の数字の1぀に達しおも、このゲヌムは終了したせんルヌルにより , «» , , . , Dagaz ! , . , , .



これはもずもず䞭囜の子䟛向けのゲヌムです。黒い石は䞋に移動できず、癜い石はどの方向にも移動できたす。さらに読む前に、「ホヌン」の䞊郚にある癜い石を「クランプ」しおみおください。うたくいかない堎合は倧䞈倫です

ヒントを䞎える


フランスの戊争ゲヌムやドワヌフのゲヌムに倚少䌌おいたすが、私の意芋では、ホヌンチェスはこれらのゲヌムよりもはるかに深く耇雑です。あなたが私を信じおいない堎合は、これを凊理しおみおください。すべおの倖芋が気取らないため、ゲヌムはたったく単玔ではありたせん。私は圌女に捧げられたいく぀かの科孊蚘事䞭囜語を芋たした。そしお、これはより耇雑なAIのデバッグに適した資料です。

䞻なこずは、暙識を台無しにしないこずです
 Dagaz.AI.eval = function(design, params, board, player) { var r = 0; var white = null; var black = []; for (var pos = 0; pos < design.positions.length - 3; pos++) { var piece = board.getPiece(pos); if (piece !== null) { if (piece.player == 1) { if (white === null) { black.push(pos); } else { r += MAXVAL / 2; } } else { white = pos; } } } if (white !== null) { r += white; } if (black.length == 2) { if ((black[0] + 1 == black[1]) && (black[1] + 1 == white)) { if (board.player == 1) { r = MAXVAL; } else { r = -MAXVAL; } if (player == 1) { r = -r; } } } return r; } Dagaz.AI.heuristic = function(ai, design, board, move) { var b = board.apply(move); return design.positions.length + Dagaz.AI.eval(design, ai.params, b, board.player) - Dagaz.AI.eval(design, ai.params, board, board.player); } ... AbAi.prototype.ab = function(ctx, node, a, b, deep) { node.loss = 0; this.expand(ctx, node); if (node.goal !== null) { return -node.goal * MAXVALUE; } if (deep <= 0) { return -this.eval(ctx, node); } node.ix = 0; node.m = a; while ((node.ix < node.cache.length) && (node.m <= b) && (Date.now() - ctx.timestamp < this.params.AI_FRAME)) { var n = node.cache[node.ix]; if (_.isUndefined(n.win)) { var t = -this.ab(ctx, n, -b, -node.m, deep - 1); if ((t !== null) && (t > node.m)) { node.m = t; node.best = node.ix; } } else { node.loss++; } node.ix++; } return node.m; } 


これが重芁なポむントの1぀です。右の黒い石を䞊に移動したす。匱い「ワンステップ」アルゎリズムは停止し、その埌ブラックは簡単にそれをコヌナヌに远い蟌みたす。ミニマックスの実装-正し​​い動きをした埌、ブラックがミスを犯した堎合に勝぀こずができたす。これは、癜人を捕たえるこずが䞍可胜であるこずを意味するものではありたせんが、いく぀かの動きを先読みするず、圌らのゲヌムが倧幅に改善されたす

䞊蚘では、倩ji将giの䟋を䜿甚しお、さたざたなボヌドゲヌムが互いに非垞に異なる可胜性があるこずをすでに瀺したした。たず、これは倉動性に適甚されたす-ゲヌムの特定の段階で蚱容される動きの平均数。このパラメヌタヌは、ボットを開発するずきのAIアルゎリズムの適甚可胜性を決定したす。ホヌンチェスで䜿甚したミニマックスアルゎリズムは明らかにKo ShogiやGwangsanghuiのような本圓に倧きなゲヌムではうたく動䜜したせん。䞀方、それらで䜿甚される「攻撃的な」アルゎリズムは、チェスなどのゲヌムであたりにも匱く再生されたす。しかし、これは問題の䞀郚にすぎたせん。


䞻な違いはメカニズムにありたす。幞いなこずに、これは評䟡関数ずヒュヌリスティックによっおカスタマむズできるものです。悪いニュヌスは、それらがどのように構築されるべきかを考えるこずは、単にそうではないずいうこずです。「カストディアン」キャプチャチベット語「明マング」などを䜿甚したゲヌムは、私のポむントを完党に瀺しおいたす。

ここでは、物質収支の単玔な評䟡だけでは十分ではありたせん
 var eval = Dagaz.AI.eval; Dagaz.AI.eval = function(design, params, board, player) { var r = eval(design, params, board, board.player); var cover = board.getCover(design); var cnt = null; _.each(cover, function(list) { var cn = 0; _.each(list, function(pos) { var piece = board.getPiece(pos); if (piece !== null) { if (piece.player == board.player) { r--; } else { cn++; } } }); if ((cnt === null) || (cnt < cn)) { cnt = cn; } }); r += cnt * 3; if (board.player != player) { return -r; } else { return r; } } var done = function(design, board, player, pos, dir, trace, captured) { var p = design.navigate(player, pos, dir); if (p !== null) { var piece = board.getPiece(p); if (piece !== null) { if (piece.player == player) { _.each(trace, function(pos) { if (_.indexOf(captured, pos) < 0) { captured.push(pos); } }); } else { trace.push(p); done(design, board, player, p, dir, trace, captured); trace.pop(); } } } } var capture = function(design, board, player, pos, dir, dirs, trace, captured) { var p = design.navigate(player, pos, dir); if (p !== null) { var piece = board.getPiece(p); if (piece !== null) { if (piece.player == player) { _.each(trace, function(pos) { if (_.indexOf(captured, pos) < 0) { captured.push(pos); } }); } else { trace.push(p); capture(design, board, player, p, dir, dirs, trace, captured); if (trace.length > 1) { _.each(dirs, function(dir) { var pos = design.navigate(player, p, dir); if (pos !== null) { var piece = board.getPiece(pos); if ((piece !== null) && (piece.player != player)) { trace.push(pos); done(design, board, player, pos, dir, trace, captured); trace.pop(); } } }); } trace.pop(); } } } } var checkCapturing = function(design, board, pos, player, captured) { var trace = []; capture(design, board, player, pos, 3, [0, 1], trace, captured); capture(design, board, player, pos, 1, [3, 2], trace, captured); capture(design, board, player, pos, 2, [0, 1], trace, captured); capture(design, board, player, pos, 0, [3, 2], trace, captured); } Dagaz.Model.GetCover = function(design, board) { if (_.isUndefined(board.cover)) { board.cover = []; _.each(design.allPositions(), function(pos) { board.cover[pos] = []; if (board.getPiece(pos) === null) { var neighbors = []; var attackers = []; _.each(design.allDirections(), function(dir) { var p = design.navigate(1, pos, dir); if (p !== null) { var piece = board.getPiece(p); if (piece !== null) { neighbors.push(piece.player); attackers.push(piece.player); } else { while (p !== null) { piece = board.getPiece(p); if (piece !== null) { attackers.push(piece.player); break; } p = design.navigate(1, p, dir); } } } }); if (neighbors.length > 1) { var captured = []; if ((_.indexOf(attackers, 1) >= 0) && (_.indexOf(neighbors, 2) >= 0)) { checkCapturing(design, board, pos, 1, captured); } if ((_.indexOf(attackers, 2) >= 0) && (_.indexOf(neighbors, 1) >= 0)) { checkCapturing(design, board, pos, 2, captured); } if (captured.length > 0) { board.cover[pos] = _.uniq(captured); } } } }); } return board.cover; } 

評䟡関数では、「カバレッゞ」を䜿甚するだけでなく、それを蚈算するアルゎリズムを真剣に䜜り盎す必芁がありたした。ヒュヌリスティックに関しおは、このゲヌムでは完党に初歩的です

 Dagaz.AI.heuristic = function(ai, design, board, move) { return move.actions.length; } 

移動する郚分が倚いほどサむズはそれに䟝存したす-より良いです評䟡機胜に䞀生懞呜取り組む必芁がありたしたが、結果は間違いなく䟡倀がありたした。


このビデオは、最も単玔な「䞀方向」アルゎリズムの動䜜を瀺しおいるこずに泚意しおください「安党な」動きがない堎合、必ずしも非垞に効率的に再生されるずは限りたせん。䞊で述べたように、モビリティず「カバレッゞ」を評䟡する際の䌚蚈凊理は驚くべきこずです

そしお最埌に、カストディアンをキャプチャした別の非垞に珍しいゲヌムのビデオ


そしお、私はこれからの䌑日を祝犏するために急いでいたす

Source: https://habr.com/ru/post/J349516/


All Articles