apeescape2.com
  • メイン
  • 仕事の未来
  • 設計プロセス
  • ブランドデザイン
  • 収益と成長
Webフロントエンド

バトルスクリプトの紹介:ボット、船、騒乱!

プログラミングは、アプリケーションの構築、目標の達成、プロジェクトの仕様を満たすことだけである必要はありません。それはまた、楽しむこと、のプロセスを楽しむことについてである可能性があります 何かを作成する 。多くの人々は、このスキルのプログラミングと開発をレクリエーションの一形態として扱っています。 ApeeScapeでは、コミュニティ内で何か面白いことを試してみたかったのです。戦艦を中心にボット対ボットのゲームプラットフォームを構築することにしました。 オープンソース 。

バトルスクリプトの紹介:ボット、船、騒乱!

社内での最初の立ち上げ以来、このプラットフォームは、コミュニティ内のいくつかの素晴らしいボットメーカーの注目を集めています。コミュニティのメンバーの一人が ApeeScapeエンジニアQuanLe 、構築された Battlescriptsボットを簡単にデバッグするためのツール 。この発表はまた、さまざまなゲームタイプとさまざまなルールをサポートする独自のボット対ボットエンジンを作成することへの関心をいくつかの人々の間で引き起こしました。 Battlescriptsが発表された瞬間から素晴らしいアイデアが流れ始めました。本日、Battlescriptsをオープンソースにすることができました。これにより、私たちのコミュニティや他のすべての人が、コードを探索したり、貢献したり、フォークしてコードを完全に別のものにする機会が得られます。



バトルスクリプトの構造

Battlescriptsは、いくつかの非常に単純なコンポーネントを使用して構築されています。 Node.jsで実行され、次のような最も人気があり、適切に実装されたパッケージのいくつかを使用します。 Express 、 マングース 、など。バックエンドは純粋なJavaScriptであり、フロントエンドスクリプトも同様です。このアプリケーションの2つの外部依存関係は次のとおりです。 MongoDB そして Redis 。ボット用にユーザーが送信したコードは、 「vm」モジュール Node.jsに付属しています。生産中、 Docker 安全性を高めるために使用されますが、Battlescriptsの強い依存関係ではありません。

バトルスクリプト

Battlescriptsのコードは GitHubで入手可能 BSD3条項ライセンスの下で。含まれています README.md ファイルには、リポジトリのクローンを作成してアプリケーションをローカルで起動する方法の詳細な手順が含まれています。

Webサーバー

このアプリケーションは、単純なExpress.jsWebアプリケーションと同様の構造を持っていることに気付くでしょう。 app.jsファイルは、データベースへの接続を確立し、いくつかの一般的なミドルウェアを登録し、いくつかのソーシャル認証戦略を定義することにより、サーバーをブートストラップします。さらに、すべてのモデルとルートは「lib /」ディレクトリ内で定義されています。完全にアプリケーションに必要なモデルは、バトル、ボット、チャレンジ、コンテスト、パーティー、ユーザーです。ボット間の戦闘は、Webサーバーノードの外部でシミュレートされ、Node.jsパッケージKueを使用して行われます。これにより、エンジンを他のWebアプリケーションから分離できるため、戦闘シミュレーションエンジンがWebサーバーに干渉する可能性が低くなり、Webアプリケーション自体の応答性と安定性が向上します。

ボットとエンジン

ボットはJavaScriptで実装されることが期待されており、それがNode.jsのバックエンドにあるものとまったく同じであるため、エンジンの構築が簡単でした。ユーザーが送信したコードの実行に関して、最大の課題の1つは、コードがサーバー上で悪意のあることを行わないようにすること、またはバグのあるコードがシステム全体の安定性を妨げないようにすることです。 Node.jsの標準ライブラリには、このタスクの一部を非常に簡単にするこのすばらしいモジュールが付属しています。 「vm」モジュールは、より簡単にするために導入されました Node.js開発者 信頼できないコードを別のコンテキストで実行します。公式ドキュメントによると、信頼できないコードを別のプロセスで実行することが重要ですが、それは本番サーバーで行うことです。ローカル開発中、「vm」モジュールとそれが提供する機能は問題なく機能します。

レスポンシブウェブデザインのためのデバイスの寸法
それがまだ合法である間、ボットを互いに戦わせてください! つぶやき

JavaScriptの実行

Node.jsで別のコンテキストで任意のJavaScriptコードを実行する場合は、次のように「vm」モジュールを使用できます。

var vm = require(‘vm’) var ctxObj = { result: ‘’ } vm.runInNewContext(‘ result = “0xBEEF” ’, ctxObj ) console.log(ctxObj); // { result: “0xBEEF” }

この「新しいコンテキスト」内では、実行するコードは「console.log」にアクセスすることすらできません。これは、そのコンテキストではそのような関数が存在しないためです。ただし、「ctxObj」の属性として渡すことにより、元のコンテキストの「context.log」関数を新しいコンテキストに公開することができます。

Battlescriptsでは、バトルをシミュレートするノードは、個別のNode.js「vm」コンテキストで各ボットを実行します。エンジンは、ゲームのルールに従って、両方のボットのコンテキストの状態を同期する責任を負います。

分離されたコンテキストでJavaScriptコードを実行することは、このモジュールが行うことのすべてではありません。 「runInNewContext」関数は、このコード実行の3つの追加の側面を制御できる3番目のパラメーターとしてオブジェクトを受け入れます。

  • この実行に関連する生成されたスタックトレースで使用されるファイル名。
  • エラーをstderrに出力するかどうか。
  • タイムアウトする前に実行を続行できるようにするミリ秒数。

この「vm」モジュールの落とし穴の1つは、メモリ使用量を制限する手段を提供しないことです。これは、モジュールの他のいくつかの制限とともに、Dockerの使用、およびエンジンノードの実行方法を通じてサーバー上で回避されます。 「vm」モジュールは、非常に頻繁に使用されると、追跡や解放が困難なメモリのリークをゆっくりと開始します。コンテキストオブジェクトが再利用されても、メモリ使用量は増え続けます。この問題は、簡単な戦略に従って解決しました。ワーカーノードで戦闘がシミュレートされるたびに、ノードは終了します。次に、本番サーバーのスーパーバイザープログラムがワーカーノードを再起動します。ワーカーノードは、ほんの一瞬で次の戦闘シミュレーションを処理できるようになります。

ノードjsとは何ですか

拡張性

Battlescriptsは元々、戦艦の標準ルールに基づいて設計されました。内部のエンジンはあまり拡張可能ではありませんでした。ただし、Battlescriptsがリリースされた後、最も一般的なリクエストの1つは、新しいゲームタイプを導入することでした。アプリケーションのユーザーは、一部のゲームが他のゲームよりもボットで征服しやすいことにすぐに気づきました。たとえば、TicTacToeとChessを比較すると、前者の状態空間ははるかに小さいため、ボットはゲームに勝つか、引き分けでゲームを終了するソリューションを簡単に思い付くことができます。

Battlescriptsエンジンは最近少し変更され、新しいタイプのゲームを簡単に導入できるようになりました。これは、いくつかのフックのような関数を含む構造に従うだけで実行できます。追加のゲームタイプであるTicTacToeが、追跡しやすいため、コードベースに追加されました。このゲームタイプに関連するものはすべて、「lib / games /tictactoe.js」ファイル内にあります。

ただし、この記事では、戦艦ゲームタイプの実装について見ていきます。 TicTacToeゲームコードの調査は、後の演習として残すことができます。

戦艦

ゲームがどのように実装されているかを見る前に、Battlescriptの標準ボットがどのように見えるかを見てみましょう。

function Bot() {} Bot.prototype.play = function(turn) { // ... }

それはほとんどそれです。すべてのボットは、1つのメソッド「play」を持つコンストラクター関数として定義されています。このメソッドは、1つの引数で毎ターン呼び出されます。どのゲームでも、引数はボットがそのターンに移動できるようにする1つのメソッドを持つオブジェクトであり、ゲームの状態を表すいくつかの追加の属性を付けることができます。

先に述べたように、エンジンは少し最近変更されました。戦艦固有のロジックはすべて、実際のエンジンコードから抽出されています。エンジンは依然として重労働を行うため、戦艦ゲームを定義するコードは非常にシンプルで軽量です。

s corp ccorpパートナーシップ
function Battleships(bot1, bot2) { return new Engine(bot1, bot2, { hooks: { init: function() { // ... }, play: function() { // ... }, turn: function() { // ... } } }) } module.exports = exports = Battleships

ここでは、init、play、turnという3つのフックのような関数を定義しているだけであることに注意してください。各関数は、エンジンをコンテキストとして使用して呼び出されます。コンストラクター関数内から、エンジンオブジェクトがインスタンス化されるときの「init」関数。通常、これは、エンジンのすべての状態属性を準備する必要がある場所です。すべてのゲームで準備する必要があるそのような属性の1つは、「グリッド」と(オプションで)「ピース」です。これは常に、ゲームボードの状態を表す2つの要素(各プレーヤーに1つ)を持つ配列である必要があります。

for(var i = 0; i

2番目のフック「play」は、ゲームが始まる直前に呼び出されます。これにより、ボットに代わってゲームのピースをボードに配置するなどのことができるので便利です。

for(var botNo = 0; botNo = consts.gridSize.width || yn >= consts.gridSize.height || this.grids[botNo][yn][xn].pieceNo >= 0) { return false } } return true; }.bind(this))) switch(true) { case square.direction === 'h': for(var k = square.x; k

これは最初は少し圧倒されるように見えるかもしれませんが、このコードが達成する目標は単純です。ボットごとに1つずつ、ピースの配列を生成し、それらを対応するグリッドに均一に配置します。すべてのピースについて、グリッドがスキャンされ、すべての有効な位置が一時的な配列に格納されます。有効な位置は、2つのピースが重なり合ったり、隣接するセルを共有したりしない場所です。

最後に、3番目と最後のフックが「回転」します。他の2つのフックとは異なり、これは少し異なります。このフックの目的は、ボットのplayメソッドを呼び出す際の最初の引数としてエンジンが使用するオブジェクトを返すことです。

return { attack: _.once(function(x, y) { this.turn.called = true var botNo = this.turn.botNo var otherNo = (botNo+1)%2 var baam = false var square = this.grids[otherNo][y][x] square.attacked = true if(square.pieceNo >= 0) { baam = true this.turn.nextNo = botNo var pieceNo = square.pieceNo var pieces = this.pieces[otherNo] var piece = pieces[pieceNo] piece.hits += 1 if(piece.hits === piece.size) { piece.dead = true baam = { no: pieceNo, kind: piece.kind, size: piece.size, x: piece.x, y: piece.y, direction: piece.direction } } var undead = false for(var i = 0; i

この方法では、ボットが正常に移動したことをエンジンに通知することから始めます。どのターンでもどのゲームでも攻撃的な動きをしなかったボットは、自動的にゲームを失います。次に、移動が船にうまく当たった場合、船が完全に破壊されたかどうかを判断します。そうであった場合は、破壊された船の詳細を返します。そうでない場合は、追加情報なしでヒットが成功したことを示すために「true」を返します。

これらのコード全体で、「this」で使用できるいくつかの属性とメソッド名に遭遇しました。これらはEngineオブジェクトによって提供され、それぞれにいくつかの単純な動作特性があります。

eスポーツ業界の規模
  • this.turn.called:これは、すべてのターンの前にfalseとして始まり、ボットがそのターンに行動したことをエンジンに通知するには、trueに設定する必要があります。

  • this.turn.botNo:このターンにプレイしたボットに応じて、これは0または1になります。

  • this.end(botNo):ボット番号を使用してこれを呼び出すと、ゲームが終了し、ボットが勝利としてマークされます。 -1で呼び出すと、引き分けでゲームが終了します。

  • this.track(botNo、isOkay、data、failReason):これは、ボットの移動の詳細、または移動が失敗した理由を記録できる便利なメソッドです。最終的に、これらの記録されたデータは、フロントエンドでのシミュレーションを視覚化するために使用されます。

基本的に、このプラットフォームでゲームを実装するためにバックエンドで実行する必要があるのはこれだけです。

ゲームのリプレイ

戦闘シミュレーションが終了するとすぐに、フロントエンドはゲームのリプレイページにリダイレクトされます。ここでシミュレーションと結果が視覚化され、その他のゲーム関連データが表示されます。

このビューは、バックエンドによって「views /」の「battle-view-battleships.jade」を使用してレンダリングされ、すべての戦闘の詳細がコンテキストに含まれます。ゲームのリプレイアニメーションは、フロントエンドJavaScriptを介して行われます。エンジンの「trace()」メソッドを介して記録されたすべてのデータは、このテンプレートのコンテキストで利用できます。

function play() { $('.btn-play').hide() $('.btn-stop').show() if(i === moves.length) { i = 0 stop() $('.ul-moves h4').fadeIn() return } if(i === 0) { $('.ul-moves h4').hide() $('table td').removeClass('warning danger') $('.count span').text(0) } $('.ul-moves li').slice(0, $('.ul-moves li').length-i).hide() $('.ul-moves li').slice($('.ul-moves li').length-i-1).show() var move = moves[i] var $td = $('table').eq((move.botNo+1)%2).find('tr').eq(move.data.y+1).find('td').eq(move.data.x+1) if(parseInt($td.text()) >= 0) { $td.addClass('danger') } else { $td.addClass('warning') } ++i $('.count span').eq(move.botNo).text(parseInt($('.count span').eq(move.botNo).text())+1) var delay = 0 switch(true) { case $('.btn-fast').hasClass('active'): delay = 10 break case $('.btn-slow').hasClass('active'): delay = 100 break case $('.btn-slower').hasClass('active'): delay = 500 break case $('.btn-step').hasClass('active'): stop() return } playTimer = setTimeout(function() { play() }, delay) } function stop() { $('.btn-stop').hide() $('.btn-play').text(i === 0 ? 'Re-play' : ($('.btn-step').hasClass('active') ? 'Next' : 'Resume')).show() clearTimeout(playTimer) } $('.btn-play').click(function() { play() }) $('.btn-stop').click(function() { stop() })

次は何?

Battlescriptsがオープンソースになったので、貢献を歓迎します。現在の段階のプラットフォームは成熟していますが、改善の余地がたくさんあります。新機能、セキュリティパッチ、バグ修正など、リポジトリに問題を作成して対処をリクエストするか、リポジトリをフォークしてプルリクエストを送信してください。そして、これがまったく新しいものを構築するようにあなたを刺激するなら、私たちに知らせて、下のコメントセクションにそれへのリンクを残してください!

退屈なアイコンをすばやくオリジナルの傑作に変える方法

Uiデザイン

退屈なアイコンをすばやくオリジナルの傑作に変える方法
デザイン思考プロセスの内訳

デザイン思考プロセスの内訳

Uxデザイン

人気の投稿
同じマシンでのMySQLマスタースレーブレプリケーション
同じマシンでのMySQLマスタースレーブレプリケーション
TypeScript、依存性注入、Discordボットの操作
TypeScript、依存性注入、Discordボットの操作
3つの医療技術革新:より良い結果とより低いコストの推進
3つの医療技術革新:より良い結果とより低いコストの推進
Calabashを使用したAndroidおよびiOSUIテスト
Calabashを使用したAndroidおよびiOSUIテスト
Node.js / TypeScript REST APIの構築、パート2:モデル、ミドルウェア、およびサービス
Node.js / TypeScript REST APIの構築、パート2:モデル、ミドルウェア、およびサービス
 
最高のデータ視覚化ツールの完全な概要
最高のデータ視覚化ツールの完全な概要
機械学習理論とその応用の紹介:例を含むビジュアルチュートリアル
機械学習理論とその応用の紹介:例を含むビジュアルチュートリアル
AngularJS開発者が犯す最も一般的な18の間違い
AngularJS開発者が犯す最も一般的な18の間違い
GoogleスプレッドシートとAppsScriptの操作
GoogleスプレッドシートとAppsScriptの操作
自然言語処理アプリを構築する方法
自然言語処理アプリを構築する方法
人気の投稿
  • WebUIデザインのベストプラクティス
  • ユーザーインターフェイススタイルガイドテンプレート
  • レール4とレール5
  • 実生活における需要例の価格弾力性
  • htmlcssとjavascriptを使用してモバイルアプリを構築する
  • オプション値の計算方法
カテゴリー
その他 バックエンド エンジニアリング管理 技術 製品ライフサイクル Webフロントエンド 財務プロセス データサイエンスとデータベース 人とチーム モバイルデザイン

© 2021 | 全著作権所有

apeescape2.com