#はじめに
前回記事で構築したRobocodeを遊びながら攻略していきます。
https://qiita.com/abemaki/items/54712e50e4a4a25c229b
ゲームを起動すると以下のような画面が出てきます。
初期段階でもステージ0であれば、五分五分の戦いです。
今回は軽く触りながら、ステージ0での勝率を高めていきたいと思います。
反響があればGithubに改良版をアップしたり続編を書いてみようかな。
#ソースコードを理解する
##公式の説明を読む前にちょっとだけソースコードを見ていきます
ソースコードを見ていくと
boss-.jsといたファイルとmyrobot.jsといったファイルがあるのがわかります。
myrobot.jsは自機で、boss-.jsは敵機を表しているものであることがファイル名からわかると思います。
ファイルを開いてみると、何やらファンクションがずらりと並んでいるのがわかりますがこのままだと詳細がよくわかりません。
この理解のまま先には進めません。
##公式の説明を読んでみる
公式のロボットHOWTOを見てみると以下のことがわかります
入手可能な情報:
自己情報
・ me.id
・ me.x
・ me.y
・ me.hp
・ me.angle-現在の角度(タンク角度+タレット角度)
・ me.tank_angle
・ me.turret_angle
敵情報
・ enemy-spot [N] .id
・ enemy-spot [N] .hp
・ enemy-spot [N] .angle-敵に対する角度(方向)
シーケンシャルアクション:
・turn_left(角度)
・turn_right(角度)
・move_forwards(距離)
・move_backwards(距離)
・move_opposide(distance)-このアクションはOnWallCollide()でのみ使用できます
並列アクション:
・turn_turret_left(角度)
・turn_turret_right(角度)
・シュート()
・yell(メッセージ)
イベント:
OnIdle()-アイドル時にトリガーされます(実装する必要があります)
OnWallCollide()-タンクが壁に衝突したとき
OnHit()-弾丸が当たったとき
OnEnemySpot()-砲塔が敵に直接面している場合(発砲しない理由はないようです!)
##試しに自機と敵機のセリフを変えてみます。
セリフはyell(メッセージ)で定義します。
ファイルを変更したら保存して、ブラウザを更新しましょう
ファイルに変更を加えるとしっかりと結果に反映されるのがわかります。
#ソースコードを改良して、勝率100%を目指してみる。
##現状の勝率が何故5割程度なのか整理してみる
両者同じような動きをしていて
クルクル回って、相手を見つけたら弾を発射するだけなので、そのあと発見場所から近い場所を探す等の動作をせずに
またひたすらクルクル相手を探しはじめます。 その為、五分五分の戦いをしていることがわかります。
・自分の動き
右に動き回りながら相手を探して見つけたら弾を発射するだけ
上記を繰り返す
・相手の動き
クルクル砲台を回転させながら相手を探して見つけたら弾を発射するだけ
上記を繰り返す
##敵に対面した後の動作を変更してみる
そこで小刻みに右に動き回って
相手を見つけたら、できるだけ近い場所で相手を左利回りに探して
攻撃をしかけるようにソースを修正してみようかと思います。
小刻みに敵を探して、敵を発見したらできるだけ近い場所を探して敵を攻撃するように修正してみます。
対面フラグを追加してアイドル時の処理を以下のように分岐させます。
■アイドル時
対面フラグ=敵を未発見(false)の際の処理:
小刻みに右回りで敵を探す
対面フラグ=敵を発見(true)の際の処理:
小刻みに左回りで敵を探す
この際に敵を発見できなかった場合に対面フラグを対面フラグを敵を未発見(false)に変更します
■敵発見時
攻撃をしかけて
対面フラグを敵を発見(true)に変更します
###修正前後の自機のソースコード(myrobot.js)
修正前のmyrobot.js(クリックして展開)
// Generated by LiveScript 1.2.0
(function(){
var MyRobot, tr;
importScripts('../base-robot.js');
MyRobot = (function(superclass){
var prototype = extend$((import$(MyRobot, superclass).displayName = 'MyRobot', MyRobot), superclass).prototype, constructor = MyRobot;
prototype.onIdle = function(){
this.move_forwards(50);
this.turn_turret_left(10);
this.turn_right(90);
};
prototype.onWallCollide = function(){
this.move_opposide(10);
this.turn_left(90);
};
prototype.onHit = function(){
this.yell("Oops!");
};
prototype.onEnemySpot = function(){
this.yell("Fire!");
this.shoot();
};
function MyRobot(){
MyRobot.superclass.apply(this, arguments);
}
return MyRobot;
}(BaseRobot));
tr = new MyRobot("MyRobot");
function extend$(sub, sup){
function fun(){} fun.prototype = (sub.superclass = sup).prototype;
(sub.prototype = new fun).constructor = sub;
if (typeof sup.extended == 'function') sup.extended(sub);
return sub;
}
function import$(obj, src){
var own = {}.hasOwnProperty;
for (var key in src) if (own.call(src, key)) obj[key] = src[key];
return obj;
}
}).call(this);
修正後のmyrobot.js(クリックして展開)
// Generated by LiveScript 1.2.0
(function(){
var MyRobot, tr;
importScripts('../base-robot.js');
MyRobot = (function(superclass){
var discoveryFired,prototype = extend$((import$(MyRobot, superclass).displayName = 'MyRobot', MyRobot), superclass).prototype, constructor = MyRobot;
// 対面フラグ
discoveryFired = false;
// アイドル時にトリガーされます(実装する必要があります)
prototype.onIdle = function(){
if(this.discoveryFired){
// 対面後の動作 小刻みに左に動いで相手を探す
// 前進(距離)
this.move_forwards(10);
// 砲塔を左に向ける(角度)
this.turn_turret_left(10);
// 左に曲がる(角度)
this.turn_left(10);
// 対面フラグリセット
this.discoveryFired = false;
} else {
// 対面前の動作 小刻みに右に動いで相手を探す
// 前進(距離)
this.move_forwards(10);
// 砲塔を右に向ける(角度)
this.turn_turret_right(10);
// 右に曲がる(角度)
this.turn_right(10);
}
};
// タンクが壁に衝突したとき
prototype.onWallCollide = function(){
// 反対に移動(距離)
this.move_opposide(10);
// 左に曲がる(角度)
this.turn_left(90);
};
// 自機に弾丸が当たったとき
prototype.onHit = function(){
// セリフ
this.yell("痛いっ");
};
// 砲塔が敵に直接面している場合(発砲しない理由はないようです!)
prototype.onEnemySpot = function(){
// セリフ
this.yell("当たれ~っ");
// 発射
this.shoot();
// 対面フラグを立てる
this.discoveryFired = true;
};
function MyRobot(){
MyRobot.superclass.apply(this, arguments);
}
return MyRobot;
}(BaseRobot));
tr = new MyRobot("MyRobot");
function extend$(sub, sup){
function fun(){} fun.prototype = (sub.superclass = sup).prototype;
(sub.prototype = new fun).constructor = sub;
if (typeof sup.extended == 'function') sup.extended(sub);
return sub;
}
function import$(obj, src){
var own = {}.hasOwnProperty;
for (var key in src) if (own.call(src, key)) obj[key] = src[key];
return obj;
}
}).call(this);
#改良した戦車で闘ってみる
圧勝です。 このステージに関しては勝率100%です。
遊びながらちゃんとエンジニアの基礎中の基礎が経験できるような仕組みになっているのは面白いですね。
・既存ソースコードを見て把握する
・公式ドキュメントを読んで理解を深める
・既存ソースコードに公式ドキュメントで得た理解をコメント文に落とし込んでみる
・現状の動きから課題点を洗い出す
・課題点を改善する方法を考える
・課題点を改善する
・動作確認して結果に超自己満足(←超大事)
ちなみに今回の改良でステージ0は余裕ですが以降はステージが進むにつれて勝率が下がっていきます。