チックタックトヌ「囜境なき」

䞉目䞊べ...誰もがそれらを挔奏した、ず確信しおいたす。 このゲヌムはシンプルで魅力的です。特に、レッスンのどこかでカップルをドラッグするず、ノヌトブックシヌトずシンプルな鉛筆以倖は手元にありたせん。 か぀お9マスに十字や円を描くこずを最初に掚枬したのは誰なのかわかりたせんが、それ以来、特に人々がそのバリ​​゚ヌションの倚くを考え出しお以来、ゲヌムは需芁を倱いたせんでした。



この蚘事では、チックタックトヌのこれらのバリ゚ヌションの1぀を再生するためにJavaScriptでAIを開発するプロセスに぀いお説明したす。かなり倚くの資料を入手したしたが、アニメヌションず写真で垌釈したした。 いずれにしおも、少なくずも詊しおみる䟡倀はありたす。
このバヌゞョンのゲヌムずオリゞナルの違いは次のずおりです。

  1. フィヌルドは任意に倧きくするこずができたすノヌトブックの長さ
  2. 勝者は、 5ピヌス あなたがそれらを呌び出すこずができる堎合を連続しお眮くものです。

すべおがシンプルであるず同時に耇雑です。叀兞的なアナログのように、ゲヌムの結果を事前に蚈算するこずはできたせん。 この「小さな投圱」は倚くの時間ず神経を奪いたした。 おもしろいず思いたす。

始める前に


蚘事のボリュヌムに぀いおは事前に謝眪せざるを埗ず、䞀郚の堎所ではたったくわかりにくい意芋を述べたしたが、コンテンツず品質を損なうこずなく矀れを絞るこずはできたせんでした。
最初に結果に慣れるこずをお勧めしたす。 コヌド

キヌボヌドショヌトカットずコマンド


始めたしょう


ゲヌム自䜓の実装から始める必芁がありたす。぀たり、 これたでのずころ、ボットなしで2人のプレヌダヌ甚のアプリケヌションを䜜成したす。 私の目的では、javascript + jquery + bootstrap4を䜿甚するこずにしたしたが、実際には䜿甚されおいたせんが、そのたたにしおおく方が良いでしょう。そうしないず、テヌブルが浮いおしたいたす。 䌝えるべき特別なものはありたせん。js、jquery、およびbootstrapには倚くの資料がありたす。 MVCを䜿甚したずしか蚀えたせん。 ずにかく、私は絶察にすべおのコヌドを説明したせん-それなしで倚くの材料がありたした。

それで、競技堎の準備ができたした。 セルに圢状を蚭定できたす。 しかし、どのプレむダヌの勝利も決しお決たっおいたせんでした。

ゲヌムスキャンの終了


プレむダヌの1人が5個を連続しお眮くず、ゲヌムは終了したす。 「簡単です」ず思いたした。 そしお、圌はフィヌルドのすべおのセルを完党にスキャンし始めたした。最初はすべお氎平、次に垂盎、そしお最埌に察角線です。

これは銬鹿げた方法ですが、うたくいきたした。 しかし、それは倧幅に改善される可胜性があり、私はそれを行いたした。ほずんどのセルはゲヌム䞭は空のたたです-競技堎が倧きすぎお完党に埋めるこずができたせん。 すべおの動きをスキャンする必芁があり、1぀の動きに1぀のピヌスのみが配眮されおいるため、このピヌスセルのみに焊点を合わせるこずができたす同じセルを所有するセルの氎平、垂盎および2぀の察角線のみをスキャンしたす

さらに、すべおの现胞株をスキャンする必芁はありたせん。 ゲヌムの終了は連続しお5個であるため、互いに6セル離れおいるピヌスは興味がありたせん。 䞡偎の5぀のセルをスキャンすれば十分です。 分かりたせんか 以䞋のアニメヌションをご芧ください。



コヌドを衚瀺
checkWin( cellX, cellY ){ var res = null; var newFig = getFig(cellX,cellY); if( ! newFig ) return false; var res; res = res || checkLine( cellX, cellY, 1, 0 ); //horizontal res = res || checkLine( cellX, cellY, 0, 1 ); //vertical res = res || checkLine( cellX, cellY, 1, 1 ); //diagonal 45 res = res || checkLine( cellX, cellY, 1, -1 ); //diagonal 135 return res; function getFig( x, y ){ return Model.Field[x] && Model.Field[x][y] ? Model.Field[x][y] : 'b'; } function checkLine( x, y, dx, dy ){ x = +x; y = +y; var score = 0; while( getFig( x - dx, y - dy ) == newFig ){ x -= dx; y -= dy; } while( getFig( x, y ) == newFig ){ x += dx; y += dy; score++; } if( score >= 5 ) return true; return false; } } 


ボット自䜓に取りかかりたしょう


そのため、すでにtic-tac-toeを䜿甚しおペヌゞを䜜成したした。 メむンタスク-AIに枡したす。
方法がわからない堎合は、コヌドを取埗しお䜜成するこずはできたせん。ボットのロゞックを考える必芁がありたす。

䞀番䞋の行は、競技堎、少なくずもその䞀郚を分析し、フィヌルド䞊の各セルの䟡栌重量を蚈算するこずです。 最も重みのあるセル-最も有望な-ボットはそこに数字を眮きたす。 䞻な問題は、1぀のセルの重みを蚈算するこずです。

甚語


十字ず぀た先は数字です。
攻撃は、同じ線䞊に䞊んで立っおいる耇数の同䞀人物ず呌ばれたす。 実際、これはたくさんありたす。 攻撃のピヌスの数はその力です。 1぀の独立した郚分も攻撃ですパワヌ1。

隣接する攻撃セル端には、空のセルたたは敵の駒が存圚する堎合がありたす。 「端」に2぀の空のセルがある攻撃は2぀の方向に展開できるず考えるのが論理的であり、より有望です。 攻撃の「端」にある空のセルの数は、そのポテンシャルず呌ばれたす。 電䜍は0、1、2のいずれかです。
攻撃を次のように衚したす [攻撃力、朜圚力] 。 たずえば、 攻撃[41] 。


図1.攻撃[41]

分析の過皋で、特定の領域に入るすべおのセルを評䟡したす。 各セルはその重みを蚈算したす 。 このセルが圱響するすべおの攻撃の重みに基づいお蚈算されたす。

分析の本質


競技堎では、すでに1人目ず2人目のプレヌダヌが䜕床か攻撃されおいるず想像しおください。 プレヌダヌの1人が移動したすクロスを蚱可したす。 圓然、圌は空のセルに移動したす。

  1. 攻撃を開発し、耇数の攻撃を開発しお、その力を高めおください。 新しい攻撃を開始するなど。
  2. 敵の攻撃の発生を防ぐか、完党にブロックしたす。

぀たり、䞻人公は攻撃ず防埡ができたす。 たたは、䞀床にすべおを䞀床に実行できたす。 圌にずっお、最初ず2番目の䞡方が重芁です。

分析の本質は次のずおりです。

  1. ボットは、チェックされたセル内の数字を眮換したす。最初は十字、次にれロです。
  2. 次に、圌はそのような動きによっお受信されたすべおの攻撃を怜玢し、それらの重みを芁玄したす。
  3. 受け取った量はセルの重量です。
  4. 同様のアルゎリズムが競技堎のすべおのセルに察しお実行されたす。



実際、このようなアルゎリズムを䜿甚しお、このように進むずどうなるかを確認したす...そしお、盞手がそのように進むずどうなるかを確認したす。 1぀のステップを楜しみにしお、最も適切なセルを遞択したす-最も高い重みを持ちたす。

セルの重みが他のセルよりも倧きい堎合、それはより危険な攻撃の䜜成に぀ながるか、匷力な敵の攻撃をブロックしたす。 すべおが論理的です...それは私には思えたす。
ペヌゞに移動しおコン゜ヌルにSHOW_WEIGHTS = trueず蚘述するず、アルゎリズムの動䜜を芖芚的に感じるこずができたすセルの重みが衚瀺されたす。

攻撃の重み


私は自分の頭を駆䜿しお、攻撃ず重みのこのような察応をもたらしたした。

 ATTACK_WEIGHT = [[],[],[],[],[],[]]; ATTACK_WEIGHT[1][1] = 0.1; ATTACK_WEIGHT[2][1] = 2; ATTACK_WEIGHT[3][1] = 4; ATTACK_WEIGHT[4][1] = 6; ATTACK_WEIGHT[5][1] = 200; ATTACK_WEIGHT[1][2] = 0.25; ATTACK_WEIGHT[2][2] = 5; ATTACK_WEIGHT[3][2] = 7; ATTACK_WEIGHT[4][2] = 100; ATTACK_WEIGHT[5][2] = 200; ATTACK_WEIGHT[5][0] = 200; 

経隓的に遞択-これはおそらく最良の遞択肢ではありたせん。

アレむに非垞に倧きな重みで5の攻撃力を远加したした。 これは、ボットがゲヌムを分析し、䞀歩前進を芋おいるずいう事実によっお説明できたすセル内の数字を眮き換えたす。 そのような攻撃をスキップするこずは、敗北に他なりたせん。 たあ、たたは勝利...誰に応じお。

高い可胜性のある攻撃はより高く評䟡されたす。

ほずんどの堎合、攻撃[42]がゲヌムの結果を決定したす。 プレむダヌがそのような攻撃を䜜成できた堎合、察戊盞手はそれをブロックできなくなりたす。 しかし、これは勝利ではありたせん。 フィヌルドに攻撃[42]がある堎合でも、敵はゲヌムをより速く終了できるため、その重みは5のべき乗の攻撃よりも小さくなりたす。䞋の䟋を参照しおください。


図2.攻撃[42]

匕き裂かれた攻撃


この段萜ではコヌドは瀺されおいたせん。 ここでは、攻撃ディバむダヌの抂念を玹介し、 「砎壊攻撃」の本質を説明したす。

次の状況を考慮しおください。5個以䞋の耇数の空のセルを削陀するためにFigureを眮き換える堎合、もう1぀が配眮されたす。

そしお、同じ行にある2぀の同䞀の数字...芖芚的には攻撃のように芋えたすが、実際にはそうではありたせん。 このような「砎壊された」攻撃も朜圚的な脅嚁になるため、順序ではありたせん。

特にそのような堎合、攻撃ごずに陀数を蚈算したす。 初期倀は1です。

  1. 私たちは、いく぀かの普通の「砎壊された」攻撃を提瀺したす
  2. 䞭倮の攻撃ず偎面の間の空のセルの数を数えたす
  3. 空のセルごずに、陀数が1ず぀増加したす
  4. 通垞通り䞭倮攻撃の重み、サむド攻撃の重みを蚈算したす-陀数で陀算したす


図3.「匕き裂かれた攻撃」の分析。 黄色の十字が付いたセルがスキャンされたす。

したがっお、匕き裂かれた攻撃もAIによっお考慮されたす。 実際、これらは通垞の攻撃ですが、スキャンされたセルから遠ざかるほど圱響が小さくなり、それに応じお重みが小さくなりたす仕切りのおかげ。

攻撃怜玢アルゎリズム


最初に、攻撃クラスを䜜成したす。 攻撃には3぀の属性がありたすが、これに぀いおは前に説明したした。

 class Attack{ constructor( cap = 0, pot = 0, div = 1 ){ this.capability = cap; // this.potential = pot; // this.divider = div; // } 

そしお、特定の攻撃の重みを返す1぀のメ゜ッド 

 countWeigth(){ return ATTACK_WEIGHT[ this.capability, this.potential ] / this.divider } } 

次。 1぀のセルに察するすべおの攻撃の怜玢を次のように分割したす。

  1. 氎平怜玢
  2. 垂盎怜玢
  3. 45床の察角怜玢
  4. 135床の斜め怜玢

これらはすべお行であり、これらの行に察する攻撃を怜玢するアルゎリズムは䞀般化できたす checkLineクラス 。

ただし、行党䜓をチェックする必芁はありたせん。 興味のある最倧の攻撃力は5です。もちろん、たずえば6の力で攻撃を䜜成するこずは可胜です。 しかし、次の動きのゲヌム状況を分析するAIの堎合、6たたは5ず同じです。これらの攻撃のいずれかを取埗する芋蟌みは、次の動きのゲヌムの終了を瀺したす。 したがっお、分析されたセルの重量は䞡方のケヌスで同じになりたす。

クラス属性

 class checkLine{ constructor(){ //,        this.subFig = "×"; //     .    «0» - . this.Attacks = []; //  this.curAttack = new Attack; // (      ) this.iter = 1; //,     this.checkEdge = false; 

問題が発生する可胜性があるため、ここで停止する必芁がありたす。最倧攻撃力が5の堎合、6番目のセルをチェックする理由です。

䟋は次のずおりです。画像内の1のべき乗の攻撃は、スキャンされた領域の境界にありたす。 この攻撃の可胜性を知るには、「海倖を芋る」必芁がありたす。


図 3. 6番目のセルをスキャンしたす。 6番目のセルをスキャンしないず、攻撃の可胜性を誀っお刀断できたす。

  //   this.attackplace = 1; } 

いく぀かの攻撃を完了するのに十分なスペヌスがない可胜性がありたす。 攻撃堎所をカりントするず、どの攻撃が芋蟌みがないかを事前に理解できたす。


図 4.攻撃する堎所

アルゎリズムは次のずおりです。

1䞭倮のセルから始めたしょう。 空にする必芁がありたすその䞭に移動したすかしかし、AIが次の移動の分析のためにこのセルの数倀を眮換する必芁があるこずを忘れないでください。眮換する数倀はthis.subfigです -デフォルトはクロスです。䞭倮のセルは眮換埌に最初に䜕らかの圢状を含むため、 this.curAttack攻撃のいく぀かの皮類に属したす。



これらすべおのポむントをデフォルトのコンストラクタ倀に衚瀺したした-䞊蚘のコヌドを参照しおください。

2次に、反埩子を枛らしお、スキャンしたセルの片偎の5぀のセルを敎理したす。 getAttacks関数cellX、cellY、subFig、dx、dyがこれを担圓したす。ここで、

cellX、cellY-チェックされたセルの座暙
subFig-チェックされたセルで眮換する図
dx、dy-サむクルのx座暙ずy座暙の倉化-これが探玢方向の蚭定方法です


ある意味では、これは怜玢ラむンに平行なベクトルです。 したがっお、1぀の関数で4方向の怜玢が可胜になり、DRY原則に再床違反するこずはありたせん。

機胜コヌド

 getAttacks( cellX, cellY, subFig, dx, dy ){ this.substitudeFigure( subFig ); //  –  ... for( var x = cellX - dx, y = cellY - dy; Math.abs( x - cellX ) <= 5 && Math.abs( y - cellY ) <= 5; x -= dx, y -= dy ) if( this.checkCell( x, y ) ) break; //: //    (  ) this.turnAround(); //  -    ... for( var x = cellX + dx, y = cellY + dy; Math.abs( x - cellX ) <= 5 && Math.abs( y - cellY ) <= 5; x += dx, y += dy ) if( this.checkCell( x, y ) ) break; return this.Attacks; } 

checkCellが䜕かを返すず、ルヌプが停止するこずに泚意しおください。

3これらのセルの数倀を確認したす。
checkCellx、y関数がこれを担圓したす。

たず、圢状をfig倉数に曞き蟌みたす。
Model.Fieldは私たちの競技堎です。

 checkCell( x, y ){ var fig = Model.Field[x] && Model.Field[x][y] !== undefined ? Model.Field[x][y] : 'b'; 

figは、「x」、「o」、「b」境界線、0空のセルです。



45番目のセルで図が䞭倮のセルず䞀臎する堎合、攻撃は境界に察しお「 停止 」し、攻撃の可胜性を刀断するには、「境界をチェック」する必芁がありたす this.checkEdge = true 。

 if( this.iter == 4 && fig == this.subFig ) // 5-  this.checkEdge = true; else if( this.iter == 5 ){ if( this.checkEdge ){ if( fig == this.curFig || fig == 0 ) this.curAttack.potential++; this.Attacks.push( this.curAttack ) } return 0; } this.iter++ 

checkCell関数の準備ができたした。 ただし、 checkLineクラスに぀いおは匕き続き䜜業したす。

5最初のサむクルを完了した埌、「向きを倉える」必芁がありたす。 むテレヌタを䞭心に倉換し、むンデックス0で䞭倮の攻撃を行い、攻撃の配列からそれを削陀しお珟圚の攻撃ずしお蚭定したす。

 turnAround(){ this.iter = 1; this.checkEdge = false; this.curAttack = this.Attacks[0]; this.Attacks.splice(0,1) } 

6次に、珟圚のセルの反察偎に移動しお、反埩子を増やしたす。
たったく同じ数字のチェック。 コヌドはすでに蚘述されおいたす-getAttacks関数

7すべお、1぀のアレむのラむン䞊にあったすべおの攻撃を収集したした。
これでcheckLineクラスを䜿甚するず、すべお...が完了したす。

それでは、すべおが簡単です。各ラむン氎平および垂盎の2぀の察角線に察しおcheckLineオブゞェクトを䜜成し、 getAttacks関数を呌び出したす。 ぀たり、 各行に察しお-独自のcheckLineオブゞェクトず、それに応じた独自の攻撃セット。

getAllAttacks関数がこれらすべおを担圓したす-すでに䞊蚘のクラスずは別に。

 getAllAttacks( cellX, cellY ){ // ,  , //       if( Model.Field[ cellX ][ cellY ] ) return false var cX = []; var cO = []; //   ... cX['0'] = this.getAttacksLine( cellX, cellY, '×', 1, 0 ); cX['90'] = this.getAttacksLine( cellX, cellY, '×', 0, 1 ); cX['45'] = this.getAttacksLine( cellX, cellY, '×', 1, -1 ); cX['135'] = this.getAttacksLine( cellX, cellY, '×', 1, 1 ); //  ... cO['0'] = this.getAttacksLine( cellX, cellY, '○', 1, 0 ); cO['90'] = this.getAttacksLine( cellX, cellY, '○', 0, 1 ); cO['45'] = this.getAttacksLine( cellX, cellY, '○', 1, -1 ); cO['135'] = this.getAttacksLine( cellX, cellY, '○', 1, 1 ); return { //     'x': cX, 'o': cO } } getAttacksLine( cellX, cellY, subFig, dx, dy ){ //      var C = new checkLine; C.getAttacks( cellX, cellY, subFig, dx, dy ); return this.filterAttacks( C ) //   } 

出力には、テスト察象のセルに察するすべおの攻撃を含むオブゞェクトがありたす。

ただし、䜕らかのフィルタヌ機胜に気付いおいるかもしれたせん。 そのタスクは、「無駄な」攻撃をふるいにかけるこずです。


ただし、攻撃のパワヌが5より倧きい堎合、フィルタヌはそれをスキップしたす。 ボットはこのような攻撃を確認する必芁がありたす。スクリヌニングを行うず、ゲヌム終了時に劚害が発生したす。

 filterAttacks( attackLine ){ var res = [] if( attackLine.attackplace >= 5 ) attackLine.Attacks.forEach( ( a )=>{ if( a.capability && a.potential || a.capability >= 5 ) res.push( a ) }) attackLine.Attacks = res; return res } 

ブレヌクポむント


はい...再び、ごめんなさい したがっお、1぀の間違った動きがゲヌムの結果を決定するずきに、ゲヌムの状況を呌び出したす。

たずえば、攻撃[32]はブレヌクポむントです。 察戊盞手が隣に駒を眮いおそれをブロックしなかった堎合、次の動きでは、すでにフィヌルドで攻撃[42]が行われおいたす。

たたは攻撃[41]。 䞀あくび-そしおゲヌムは簡単に完了するこずができたす。


図5.ブレヌクポむント

ここではすべおが明確で理解可胜なものであり、䞊蚘のアルゎリズムはすでにブレヌクポむントを考慮し、タむムリヌにそれらをブロックするこずができたす。 ボットは楜しみです。 圌は、次のタヌンで、敵が攻撃を䜜成できるこずを確認したす[51]。たずえば、その䜓重は200です。これは、unningなオタクがここに行くこずを意味したす。

ただし、プレヌダヌの1人がフィヌルドで2぀のブレヌクポむントを取埗する状況を想像しおください。 そしお、これは明らかに、盞手にチャンスを残したせん、なぜなら 䞀床にブロックできるブレヌクポむントは1぀だけです。 このような攻撃をブロックするようにAIに教える方法は


図6. 2ブレヌクポむント

セルを分析するずき、セル内のピヌスを代入するずき、次のタヌンで取埗するブレヌクポむントの数をカりントしたすボットは前方ぞの動きを芋お、忘れないでください。 2぀のブレヌクポむントをカりントするこずにより、セルの重みを100増やしたす。

そしお今、ボットはそのようなゲヌムの状況を防ぐだけでなく、それらを䜜成するこずができるようになり、より手ごわい盞手になりたした。

攻撃がブレヌクポむントであるこずを理解する方法


明癜なこずから始めたしょう4のべき乗を持぀攻撃はブレヌクポむントです。 たった1回のミスで、ゲヌムを完了する機䌚が䞎えられたす。 5個を䞀列に䞊べたす。

さらに、攻撃の可胜性が2である堎合、そのような攻撃をブロックするためにさらに1タヌンを費やしたす。぀たり、3のべき乗のブレヌクポむントが存圚するこずを意味したす。

そしおさらに難しい- 「匕き裂かれた攻撃」 。
䞭倮に空のセルが1぀だけある攻撃のみを怜蚎したす。 これは、2぀の空のセルを䞭倮に配眮しお攻撃を完了するには、少なくずも2回の移動が必芁であるためです-これは明らかにブレヌクポむントではありたせん。

私たちが思い出すように、私たちは砎れた攻撃をいく぀かの埓来の攻撃ず考えおいたす1぀の䞭倮攻撃ずサむド攻撃です。 䞭倮の攻撃はスキャンされたセルに属し、サむドディバむダヌには1以䞊がありたす-これは䞊蚘のずおりです。

ブレヌクポむントを芋぀けるためのアルゎリズム簡単、以䞋をお読みください

  1. 可倉スコアを玹介したす
  2. 私たちは䞭倮攻撃を取り、力を考慮したす
  3. 陀数が2倍以䞋の堎合、サむドの1぀を䜿甚したす。
  4. スコア -䞭倮およびサむド攻撃の力の合蚈
  5. 䞭倮およびサむド攻撃の可胜性が2である堎合、そのような攻撃をブロックするには、もう1タヌンを費やす必芁がありたす。 したがっお、スコアは1増加したす
  6. スコアが 4以䞊の堎合、これはブレヌクポむントです
    実際、ブレヌクポむントは単玔に列挙するこずができ、それらの倚くはありたせんが、すぐにはわかりたせんでした。

 isBreakPoint( attackLine ){ if( ! attackLine || ! attackLine.length ) return false; var centAtk; attackLine.forEach( ( a )=>{ if( a.divider == 1 ) centAtk = a; }) if( centAtk.capability >= 4 ) return true if( centAtk.potential == 2 && centAtk.capability >= 3 ) return true; var res = false; attackLine.forEach( ( a )=>{ var score = centAtk.capability; if( a.divider == 2 ){ //side attack if( centAtk.potential == 2 && a.potential == 2 ) score++; if( score + a.capability >= 4 ){ res = true; return; } } }) return res; } 

はい、最終的にすべおをたずめたす


したがっお、背埌にある䞻な地獄に぀いおは䞊で説明しおいたす。 それから機胜する䜕かを圢䜜る時です。 関数countWeightx、y -セルの座暙を入力ずしお受け取り、その重みを返したす。 圌女のフヌドの䞋には䜕がありたすか

最初に、セルが属するすべおの攻撃の配列を取埗したす。  getAllAttacksx、y 。 すべおの行を調べお、ブレヌクポむントの数をカりントしたす。 2぀のブレヌクポむントがある堎合、この状況がゲヌムの結果を決定し、セルの重みを100増やすこずができるこずを思い出しおください。
ただし、すべおのブレヌクポむントは1人のプレヌダヌに属しおいる必芁があるため、最初のクロス、次にれロの2぀のステップでチェックを実装する必芁がありたした。

攻撃の重みの配列 ATTACK_WEIGHTS [] で6以䞊のパワヌの攻撃を提䟛しなかったため、それらを5のパワヌの攻撃に眮き換える必芁がありたした。違いはありたせん。それらはすべおゲヌムの終わりに぀ながりたす。

さお、攻撃の重みを芁玄したす-それだけです。

別の小さな点ボットがゲヌムの終わりに銬鹿にならないように、既に4のべき乗で攻撃を構築し、珟圚の動きを考えおいる堎合、そのような攻撃を完了するにはセルの重量を倧幅に増やす必芁がありたす。 これがなければ、AIは単玔に、盞手の「危険な」攻撃から身を守るこずができたすが、ゲヌムは勝ったように芋えたす。 最埌の動きは重芁です。

 countWeight( x, y ){ var attacks = this.getAttacks( x, y ) if( ! attacks ) return; var sum = 0; sum += count.call( this, attacks.x, '×' ); sum += count.call( this, attacks.o, '○' ); return sum function count( atks, curFig ){ var weight = 0; var breakPoints = 0; [ "0", "45", "90", "135" ].forEach( ( p )=>{ if( this.isBreakPoint( atks[p] ) ){ debug( "Break point" ) if( ++breakPoints == 2 ){ weight += 100; debug( "Good cell" ) return; } } atks[p].forEach( ( a )=>{ if( a.capability > 5 ) a.capability = 5; if( a.capability == 5 && curFig == Model.whoPlays.char ) weight += 100; weight += a.getWeight(); }); }) return weight } } 

ここで、特定のセルに察しおこの関数を呌び出すず、その重みが取埗されたす。 すべおのセルに察しおこの操䜜を実行し、最適なものを遞択したす重みが最も高い。 そこに行く

残りのコヌドはgithubで芋぀けるこずができたす。 すでに倚くの資料があり、そのプレれンテヌションは、私が詊したこずがないので、望たれるものがたくさんありたす。 しかし、読者の皆さん、ここたで読んでいただければ、ありがたいです。

結果に察する私の意芋


さあはい、あなたは圌を倒すこずができたすが、それをするこずは私にずっお個人的に少し問題です。たぶん私は十分に泚意しおいたせん。あなたの匷さも詊しおください。

私はそれがより簡単に可胜であるこずを知っおいたすが、私は方法がわかりたせん。このようなボットの他の実装を知っおいる、たたは芋おいる人の話を聞きたいです。

私は䜕が良くなるかを知っおいたす。はい...ミニマックスなどの有名なアルゎリズムを䜿甚できたすが、そのためにはゲヌム理論の分野で知識ベヌスが必芁です。残念ながら、それは自慢できたせん。

将来的には、ブレヌクポむント分析を数ステップ先に远加しお、ボットをさらに深刻なラむバルにする予定です。しかし、珟圚、この実装に぀いお明確な考えがありたせん。私はちょうど今床のセッションず䞍完党な卒業蚌曞を持っおいたす-それは私を悲したせたす。

最埌たで読んでくれおありがずう。

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


All Articles