・ドロイドの仕様 ・動作概要 ・リーダーから命令を受け取り,リーダーを守りながら協力して敵を迎撃する.ドロイドは通常のロボットと比べて体力が高いため,リーダーを守るタンクとしての役割に適していると考えた. ・プログラム仕様 ・共通変数 なし ・関数(メソッド) void onMessageReceived() 引数:MessageEvent e,戻り値:なし 機能:リーダーから,または通常の戦車からメッセージを受け取った時に実行する関数である.ドロイドは以下の流れで動く. 1.ラウンド開始時,リーダーからメッセージを受け取り,リーダーとドロイドが位置する場所からお互いの最短距離の壁へ向けて壁から100px離れた位置まで直進する.リーダーとドロイドが位置する場所からお互いの最短距離の壁の判断は,リーダーとドロイドが位置を両端とした線分んお垂直2等分線を求め,その垂直2等分線と交わる壁とする. 2.リーダーからリーダーとドロイドの距離をレーダーで測りながら,リーダーの進行方向斜め前に半径200pxの円の範囲に常に位置し続ける. 3.リーダー戦車が前方600pxまたは後方300pxの範囲に敵のロボットがいると確認したら,リーダーから受け取った敵の位置に向けてエネルギー3.0で弾を発射する.前方600pxまたは後方300pxと設定した理由は,この範囲に敵が位置するとリーダー戦車とドロイドで敵を挟んで2対1の状況を作れると判断したためである.また,前方600pxまたは後方300pxの範囲に敵のロボットが位置しない場合,エネルギー1.0で弾を発射する. 4.リーダーが倒された場合,もう1体の戦車からメッセージを受け取り,もう1体の戦車と全く同じ動きをする. ・動作概要との関連 リーダーの常に近くに位置するため,リーダーへの攻撃をドロイドが受けることでリーダーへの被弾を減らすことができる.また,リーダーの常に近くに位置するため,リーダーがレーダーで敵の位置を捕捉したらすぐさまリーダーと2体で敵のロボットへ攻撃することができる. ・通常戦車 ¥subsection{戦術} 普通戦車の基本戦術は、単独攻撃を優先し、リーダーが死ぬと、ドロイドに指示を出す。攻撃する際は、偏差撃ちを利用し、相手の攻撃は円形に回避することを基本とする。 ¥subsection{アルゴリズム} リーダーが生存している場合、戦車はレーダーで敵を探知し、追跡する。その敵をトラッカーのような動きで攻撃する。攻撃の際には、偏差打ちを利用し、敵の攻撃は円形に回避する。敵に対して、10発撃った場合、敵から離れて、360°再スキャンし敵を見つけ、一番近い敵を攻撃する。¥¥ リーダーが死んでしまい、ドロイドが生き残っている場合、戦車はドロイドに自身と同じ動きをさせる。このとき 逃げることはせず、完全に同じ敵に対する攻撃に特化する。 ¥subsection{プログラム仕様} 共通変数はint moveDirectionで、戦車の進行方向を表す。初期値は1である。¥¥ void run()は、この戦車の機体やレーダーなどの色を決め、また、レーダーを右回りに回し続けることと、機体が回る際、大砲の向きを固定する機能を持つ。¥¥ void onScannedRobot(ScannedRobotEvent e)は、敵戦車をスキャンした際の行動を決める。変数absBearingで敵戦車の絶対的な角度をとり、latVelで敵戦車の将来の予測速度を計算する。変数gunTurnAmtで大砲をどの程度回すかを決める。また自機の速度は乱数を用いて計算する。今、敵戦車との距離が150より大きければ、e.getDistanceで距離を測り、140になるまで近づいて最大火力で射撃する。このとき、目指す地点はabsBearingとlatVelを用いて計算した敵戦車が来るであろう予測地点である。逆に近すぎた場合は距離が140になるまで単純に離れるようにする。また、この戦車は、射撃回数をカウントする変数iを用いて、i$>$10となれば一旦敵戦車から離れて、再スキャンする。これの繰り返しで攻撃する。¥¥ OnHitByBullet()では敵戦車に攻撃された場合の対処を決める。bearingを0以上360以下の乱数とし、turnRight(bearing)でランダムに円形回避する。¥¥ onHitWall(HitWallEvent e)では、壁に戦車が衝突した際にmoveDirection=-moveDirectionとして進行方向を反転させる。¥¥ \section{リーダー戦車} \subsection{戦術} リーダー戦車は撃破されると味方のエネルギーが減少してしまうため、普通戦車と比較して、より生存を重視した立ち回りを 行う。具体的には、弾が360度あらゆる方向から飛んでくる戦場の中央を避けて壁際を移動し、スキャンで自機と敵機の判別を行いながら ドロイドに指示を出す、という立ち回りを行う。これは、一度自作したプログラムとサンプルプログラムのWallsを戦わせたときに ほとんど弾を命中させることができないまま負けてしまったため、Wallsの逃げる動きを取り入れることにしたためである。\par また、攻撃重視という全体戦略とリーダーとしての生存重視という一見相反する戦略を共存させるために、 ドロイドとともに相手を挟み込むようにして2対1を作り出し、スキャンで体力の少ない敵を見つけて狙うことで撃破を目指す。 攻撃時は偏差撃ちを利用する。 \subsection{アルゴリズム} リーダー戦車のアルゴリズムは、\par 壁際への移動とドロイドとの合流 → 壁の周りを移動しながらスキャンで敵を発見 → ドロイドと挟み撃ちできるように動く → 偏差撃ちで攻撃\\ というようになっている。これらの詳細を次のように定めた。 \begin{enumerate} \item 試合が開始した瞬間に、スキャンで味方ドロイドの位置を探索する。\label{scanDroidL} \begin{enumerate} \item ドロイドが見つからない場合、ドロイドに戦場中心の座標を送信し移動させる。 \label{forceToMoveL} \end{enumerate} \item リーダーとドロイド両方から最も近い壁に向かってドロイドとともに走る。 \label{runL} \item ドロイドと一定の距離を保ちながら壁の近くを時計回りに移動する。 \label{turnL} \item スキャンで敵を発見したら、レーダーでとらえ続ける。 \label{scanEnemyL} \begin{enumerate} \item 敵機をドロイドと挟めるような位置に移動する。 \label{moveToFireL} \item 敵の未来位置を予測する。 \label{predictL} \item ドロイドに射撃位置を送信する。\label{broadcastL} \item ドロイドとともに射撃を行う。 \label{fireL} \end{enumerate} \item 自機に弾が当たった場合は円運動を描くように回避行動を行う。\label{avoidanceL} \item 壁に当たった場合は反転する。\label{WallL} \end{enumerate} \subsection{プログラム仕様} \begin{itemize} \item クラス \begin{itemize} \item public class Leader extends TeamRobot\\ リーダー戦車のメインクラスであり、TeamRobotクラスの拡張クラスとして Leader を定める。 \end{itemize} \item 共通変数 \begin{itemize} \item int moveDirection (初期値 : 1)\\ 機体の進行方向を指定する。 \item int droidCount (初期値 : 0)\\ ドロイドのスキャン回数をカウントする。 \end{itemize} \item メソッド \begin{itemize} \item public void run() \begin{itemize} \item 引数 : なし \item 戻り値 : なし \item 機能 : 機体の基本動作である。 \begin{enumerate} \item この戦車の機体やレーダーなどの色を決める。\\ setBodyColor、setGunColor、setRadarColor、setScanColor、setBulletColorを用いる。 \item 砲台とレーダーの向きに対する機体の回転を無視する。\\ setAdjustGunForRobotTurn、setAdjustRadarForRobotTurnを用いる。 \item レーダーを右方向に回転させ続ける。\\ turnRadarRightRadiansを用いる。 \item 味方の名前リストを作成しておく。\\ getTeammates、getNameと名前用配列String namesを作りこれらを用いる。\\ 参考 : https://robowiki.net/wiki/Teams\#Teammates\_of\_any\_mix\_of\_classes \end{enumerate} \end{itemize} \item public void onScannedRobot(ScannedRobotEvent e) \begin{itemize} \item 引数 : ScannedRobotEvent e\\ スキャンしたロボットについての情報に対する参照である。 \item 戻り値 : なし \item 機能 : 機体をスキャンしたときに行う動作である。 \begin{enumerate} \item ドロイドのスキャン回数カウンタ i が0であるかを判断する。\\ if 文を用いる。 \begin{enumerate} \item i = 0 の場合、味方のドロイドかどうかを判断する。\\ if 文の条件式でgetNameと名前用配列String namesを用いる。 \begin{enumerate} \item ドロイドの場合、自身とドロイドの座標から近い壁と進む方向を導出し、 メッセージで進むべき座標を送信してドロイドを動かし、自身も壁際に動く。\\ 自身とドロイドの座標にはgetX、getYおよびe.getX、e.getYを用いる。メッセージ送信にはbroadcastMessageを用いる。 \item ドロイドでない場合、メソッドを終了する。\\ returnを用いる。 \end{enumerate} \item i = 0 でない場合、敵か味方かを判断する。 \begin{enumerate} \item 味方である場合、メソッドを終了する。\\ returnを用いる。 \item 敵である場合、体力が低ければ敵の未来位置を予測する。\\ e.getEnergy、e.getBearingRadians、e.getVelocity、e.getHeadingRadiansを用いる。 \end{enumerate} \item ドロイドにメッセージを送り、移動する。\\ メッセージ送信にbroadcastMessageを用いる。setAheadで移動する。 \item 予測した位置に対して射撃を行う。\\ setFireを用いる。 \end{enumerate} \end{enumerate} \end{itemize} \item public void onHitByBullet(HitByBulletEvent e) \begin{itemize} \item 引数 : HitByBulletEvent e \item 戻り値 : なし \item 機能 : 弾がこの機体に当たったときに行う動作である。 \begin{enumerate} \item 円を描くように回避する。\\ 45度右を向いてから100下がり、 45度左を向く。この動作を繰り返す。 \end{enumerate} \end{itemize} \item public void onHitWall(HitWallEvent e) \begin{itemize} \item 引数 : HitWallEvent e \item 戻り値 : なし \item 機能 : この機体が壁にぶつかったときに行う動作である。\\ int moveDirectionの値を―1にする。 \end{itemize} \end{itemize} \end{itemize} \subsection{動作概要との関連} 各モジュールとアルゴリズムについて、 \begin{itemize} \item void onScannedRobot(ScannedRobotEvent e) : アルゴリズム\ref{scanDroidL} ~ \ref{fireL} を担当している。 これにより、壁際を移動しドロイドに指示を出すという動作、ドロイドとともに体力の少ない敵を見つけて狙うという動作を達成する。 \item void onHitByBullet(HitByBulletEvent e) : アルゴリズム\ref{avoidanceL}を担当している。 \item void onHitWall(HitWallEvent e) : アルゴリズム\ref{WallL}を担当している。 \end{itemize}