t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

ゲームしながらプログラミング学習になるソフトRoboCode

土曜に以下の本を買ってきた。

Robocodeで学ぶ一歩先のJavaプログラミング

Robocodeで学ぶ一歩先のJavaプログラミング

前から気になっていたが色々と他にやりたいこともあってなかなか手が出せなかった本だ。
これは何かというと、プログラミングで自機を動かして敵を殲滅するゲームである。
コードを書くとそのアルゴリズムのとおりに自機が動く。

プレイ画面はこんな感じであるが、自機を操作するといったことはできず、この画面ではただ見ているだけである。
f:id:t-hom:20150202001846p:plain

ステージなどはなく、フィールドにどのロボットを何体投入するかは自分で決めて10ラウンドで最も生き残ったロボットが勝利となる。

以下がコーディング画面である。
f:id:t-hom:20150202003042p:plain
むしろ、こちらが本当のプレイ画面といって良い。

新規のロボットを作成すると上のひな形が挿入される。

ロボットの操作は単純で、前進・後退・本体旋回・大砲旋回・レーダー旋回・大砲発射の6種類の操作と、壁にあたった、敵の攻撃を食らった、他のロボットを発見したの3種類のイベントを組み合わせて行う。

英語だらけで分からんという方のために、コメントを和訳したソースコードを張っておく。

package thom;
import robocode.*;
//import java.awt.Color;

// API help : http://robocode.sourceforge.net/docs/robocode/robocode/Robot.html

/**
 * Thom01 - は (あなたの名前)によって作成されたロボットです。
 */
public class Thom01 extends Robot
{
	/**
	 * run: Thom01の標準の動作です。
	 */
	public void run() {
		// ロボットの初期化コードをこの下に書いてください。

		// ロボットの稼働を試した後、
		// 3行目のimport java.awt.Color;のコメントを外しましょう。
		// それと、次のsetColorsから始まる行もコメントを外してください。

		// setColors(Color.red,Color.blue,Color.green); // body,gun,radar

		// 以下がロボットのメインループです。
		while(true) {
			// 次の4行はあなたの好きな処理に書き換えてください。
			ahead(100);
			turnGunRight(360);
			back(100);
			turnGunRight(360);
		}
	}

	/**
	 * onScannedRobot: 他のロボットを発見したときの処理を書いてください。
	 */
	public void onScannedRobot(ScannedRobotEvent e) {
		// 次の行はあなたの好きな処理に書き換えてください。
		fire(1);
	}

	/**
	 * onHitByBullet: 攻撃を受けた時の処理を書いてください。
	 */
	public void onHitByBullet(HitByBulletEvent e) {
		// 次の行はあなたの好きな処理に書き換えてください。
		back(10);
	}
	
	/**
	 * onHitWall: 壁にぶつかった時の処理を書いてください。
	 */
	public void onHitWall(HitWallEvent e) {
		// 次の行はあなたの好きな処理に書き換えてください。
		back(20);
	}	
}

さて、コードを書いてみたが、早速書籍に出てくるフィールドの中央に移動せよという課題でつまづいた。
ロボットの初期の座標はランダムである。単に目的地(中央)とのタテ・ヨコ差分をとって、そのとおりにタテ・ヨコで移動すれば目的は達成できるのだが、それではあまりに芸が無い。
斜めに一直線に目的地を目指そうとしたときに角度と距離を求める必要があるが、ここで小一時間ほど三角関数のお勉強。。
YouTubeで講義を受けてようやく意味がわかった。
距離は三平方の定理、角度はアークタンジェントで求まる。

で、色々失敗しながら最終的にうまくいったが、ここでまた次なる効率化案を思いついた。
ロボットのモデルが戦車なので、前後にスピード差は無い。
本体の旋回にも時間がかかるので、目的角度と反対角で近い方を向いて、反対角になった場合はバックで移動すれば効率が良いということだ。

イメージは、以下の赤色の旋回
f:id:t-hom:20150202011608p:plain

一番簡単なのは、図の緑線のように、何も考えずに右旋回のみとするケースである。でもこれだと最悪359度旋回ということもありうる。
次に簡単なのは、図の青線のように、右か左で近い方に旋回するケース。これでも結構頭を使うが、さらに難しいのが、正面と正反対のどちらが近いかを判定して向きを変え、直進またはバックで最短距離をとる赤のケースである。

問題をややこしくさせているのは、自機が目標からみてどの方角にいるのかを判断しないといけないこと。
愚直にIfとかSwitch文をネストすれば達成できるが、そういう汚いコードではなくてもっと筋のとおった一般法則を見つけたいと思う。これが仕事だったらそんな自己満足を持ち込んでいるヒマは無いが、趣味なのでここは綺麗なコードに拘りたい。

それを考えているうちに一日終わってしまったので、今日のところは断念。
また解決したらコードを載せようと思う。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。