NekoNinja1.3 原码分析
来源:互联网 发布:2016年网络病毒 编辑:程序博客网 时间:2024/05/21 03:27
NekoNinja1.3 原码分析
import robocode.*;
import java.awt.Color;
import java.awt.geom.Point2D;
/**
* NekoNinja - a ninja by Martin Y Lepsoy at mlepsoy@yahoo.no
*
* 18.12.2002 - Version 1.30 - codesize 745
*
* Now even the gun is based on the, soon to be released, Predator 1.50. A pattern analyzer that actually works
* Is extremely hard to hit constantly.
* Even SandBoxDT 1.61 and Duelist 0.1.6 will have a hard time predicting where it will go next time
* This copy readable, but codesize too big. Download the released version from www.robocoderepository.com
*
*
* 15.12.2002 - Version 1.20 - codesize 618
*
* Completely new robot, now only specializes in 1v1 combat
* Aim is a random amount of calculated aim at a distance over 400
* No dodging anymore, movement based on Predator's successful movement
*
*
* 09.11.2002 - Version 1.1 - codesize 542
*
* New radar management: The radar spins while we are tracking the closest target
* Aim with average velocity
* New dodging, better and less predictable ( I think )
* Won't get slaughtered in melee like before ( but it's not that good :)
*
*
* 14.10.2002 - Version 1.0 - codesize 534
*
* NekoNinja is a 1v1 specialist
*
*/
/**
* NekoNinjia是目前世界上公认最好的1v1 microbot,其中1.30版本又是它所有版本中最好的(作者自己都承认)
* 他的特点是运动采用随机运动,射击采用模式分析
* 由于是microbot,受codesize<750的限制,所以代码写的很精简(这几乎是所有mini,micro,nano bot的共同特点)
* 所以给原码分析带来很多困难,加上分析者水平有有限,分析错误之处在所难免,欢迎读者不吝批评指正。:)
* 分析说明:分析中作者原来所带的英文注释均加以保留,一些基础的,浅显易懂的(比如说像setAdjustRadarForGunTurn(true);
* setColors( c , c , new Color( 162 , 244 , 89 ) );这样的语句)均没有分析,主要分析的是作者的设计思路。
* ----分析者:iiley
*/
public class NekoNinjaReadableVersion extends AdvancedRobot
{
static double nextMove; //the time before our next move
final static int storedInfo = 800; //how many frames we store in our pattern analyzer.
//not too large to get fresh details on target quickly,
//but large enough to remember the opponents behavior a little while
static double[][] pattern = new double[storedInfo][4]; //all stored info about our enemy
public void run() {
setAdjustRadarForGunTurn(true);
setAdjustGunForRobotTurn(true);
Color c = Color.darkGray.brighter();
setColors( c , c , new Color( 162 , 244 , 89 ) ); //new and better ninja colors:-p
while( true ) {
turnRadarRightRadians( Double.POSITIVE_INFINITY ); //turn radar to find a target
}
}
public void onScannedRobot(ScannedRobotEvent e) {
int time = (int) getTime() % storedInfo; // store time to save codesize
double targetBearing = getHeadingRadians() + e.getBearingRadians();
double ourX = getX(); //store own coordinates
double ourY = getY(); //-"-
double firePower = Math.min( 3 , 30 * getEnergy() / e.getDistance() ); //powersaving when far from target and low on energy
//movement code
/**
* 在场地中随机寻找一点作为运动的目标点(这一点要满足离墙不能太近,而且如果要过去这一点,我需要的用方向要满足不能和当前正在运动的方向相差太少
* 也就是要>minimumAngleDifference,也不能于相对敌人的方向相差太少,要>2 * minimumAngleDifference,意思就是说,方向要变多些,不能看起来
* 跟没改变差不多,也不能向着敌人冲过去。minimumAngleDifference是一个自己设定的数,因该是经过测试和塞选出来的,为什么要跟a有关,也就是为什么
* 循环到后面minimumAngleDifference越小?因为万一前面找不到满足条件的角度呢?那么后面,限制就因该小一些)
* nextMove = e.getDistance() / ( 29 - 3 * firePower );if ( nextMove-- <= 0 )的意思是在敌人第二发子弹快要发出的时候改变运动目标点
*/
if ( nextMove-- <= 0 ) { //it's time to make our next move
for ( double a = 0 ; a < 500 ; a++ ) {
double testX = Math.random() * getBattleFieldWidth(); //make random test points
double testY = Math.random() * getBattleFieldHeight(); //-"-
double distToWall = Math.min( testX , getBattleFieldWidth() - testX ) * Math.min( testY , getBattleFieldHeight() - testY ); //check the product of the distance to the shortest walls
if ( distToWall > 7600 ) { //make sure the point is within the current wall tolerance (which is always 7600 in this bot which is good for a 800 x 600 battlefield)
//use point if angle to point is a certain amount from angle to target
double ourAngleToPoint = getAngle( ourX , ourY , testX , testY ); //angle to the testpoint
double minimumAngleDifference = ( ( 500 - a ) / 500 ) * Math.PI / 6; //minimumAngleDifference is the smallest angle difference to accept
if ( Math.abs( angle_180( targetBearing ) - ourAngleToPoint ) > 2 * minimumAngleDifference
&& Math.abs( angle_180( getHeadingRadians() ) - ourAngleToPoint ) > minimumAngleDifference ) {
double turnAngle = angle_180( getAngle( ourX , ourY , testX , testY ) - getHeadingRadians() ); //calculate angle to turn to next point
//decide which direction to go to reach our point as soon as possible
double moveDirection = 1; //use front if next check is false
if ( Math.abs( turnAngle ) > Math.PI / 2 ) { //if angle is greater than PI / 2 in either directions
moveDirection = - 1; //switch direction
turnAngle += Math.acos( moveDirection ); //and change turnangle acordingly
}
setTurnRightRadians( angle_180( turnAngle ) ); //make turn
setAhead( moveDirection * Point2D.Double.distance( ourX , ourY , testX , testY ) ); //move towards point
break;
}
}
}
//make nextMove a little before a bullet will reach you next time
nextMove = e.getDistance() / ( 29 - 3 * firePower ); //use own firePower here to save space. The enemy is likely to use about the same power as us since firepower often is based on own energy
}
setMaxVelocity( getTurnRemaining() > 45 ? 0.001 : 8 ); //adjust velocity when turning to make sharper turns
//end of movement
//pattern analyzer
/**
* 射击策略主要思路是用一个800长度的数组纪录一个直线提前量射击策略的PredictionAngle
* 每个记录点都记录从自己子弹到敌人这段时间(子弹假定能量为3,敌人假定为不动,虽然这样不精确,但是也只能这样,你知道敌人怎样动?如果知道你还计算啥?)
* 里PredictionAngle的累加
* 需要射击时,寻找一个历史中(所有以前的记录节点中)完成了累加的,而且与目前的PredictionAngle最相似的记录节点(也就是以PredictionAngle最相似
* 就视为运动方式最相似),那么,敌人以后的运动因该和历史中的那段运动情况很相似(也就是历史重现)。
* 找到了历史要重现的地方了,那么用那段历史中的平均PredictionAngle作为射击Angle射击
*
* 这种射击方式就是寻找历史中和你现在运动相似的情况,所以如果你的运动有规律的话,他能很好的找出你下一步会怎样走,那么,你被命中的几率就很大
* 这也正是作者的运动采用随机运动的原因。
*/
int match = 0;
pattern[ time ][0] = e.getDistance() / ( 20 - 3 * firePower ); //store time before we will use this angle in our analyzer
pattern[ time ][1] = e.getVelocity() * Math.sin( e.getHeadingRadians() - targetBearing ); //store linear prediction angle
/**
* pattern[ time ][1] = e.getVelocity() * Math.sin( e.getHeadingRadians() - targetBearing );
* 正弦定理e.getVelocity()/Math.sin(predictionAngle)==myBulletVelocity/Math.sin(e.getHeadingRadians() - targetBearing);
* 所以pattern[ time ][1]==myBulletVelocity*Math.sin(predictionAngle);
* 也就是说pattern[ time ][1]记录的是直线提前量的射击角度与自己子弹速度的乘积
*/
pattern[ time ][2] = pattern[ time ][3] = 0; //reset values used to store our target's actual move
for ( int a = 0; a < storedInfo; a++ ) {
//每个记录点pattern[a]中,如果当前时间是在我的子弹到达敌人之前则累加计算到的myBulletVelocity*Math.sin(predictionAngle)值;
//同时记录累加了多少次(pattern[ a ][3]的值)
if ( pattern[ a ][0] > 0 ) { //if angle is under evaluation
pattern[ a ][2] += e.getVelocity() * Math.sin( e.getHeadingRadians() - targetBearing ); //add angle to prediction
pattern[ a ][0]--; //decrease time before use
pattern[ a ][3]++; //increase counter for number of angles used
}
}
//在历史中(所有记录中)寻找一个和目前的myBulletVelocity*Math.sin(predictionAngle)值最相近的记录点(这个纪录点必须是累加完毕的点pattern[a][0]<0)
//把这个纪录点的数组下表记录到match中
for ( int a = 0; a < storedInfo; a++ ) { //cycle all our stored values
double testAngle = pattern[ time ][1]; //store the angle this turn to save codesize
if ( pattern[ a ][0] < 0 && Math.abs( testAngle - pattern[ a ][1] ) < Math.abs( testAngle - pattern[ match ][1] ) ) { //if this value is better than our current match
match = a; //change match to this value
}
}
//计算需要射击的角度linearPredictionAngle
//这角度是在我子弹到达敌人这段时间里的predictionAngle的平均值
double linearPredictionAngle = pattern[ match ][2] / ( pattern[ match ][3] * ( 20 - 3 * firePower ) ); //prediction angle with our best match
//end of pattern analyzer
linearPredictionAngle = linearPredictionAngle >= 0 ? linearPredictionAngle : 0;
setTurnGunRightRadians( angle_180( targetBearing - getGunHeadingRadians() + linearPredictionAngle ) ); //turn gun to target with an offset as predicted in our analyzer
setTurnRadarRightRadians( Math.tan( targetBearing - getRadarHeadingRadians() ) * 3 ); //turn radar to target enemy
if ( getEnergy() > Math.min( e.getEnergy() + firePower + 0.1 , 3.1 ) ) { //make sure we won't kill ourself when shooting, also let the enemy run out of energy before you
setFire( firePower ); //fire
}
scan(); //scan to see if our target is still here
}
//helpers
/**
* 返回角度ang的-PI到PI相对应的值(弧度表示)
*/
public double angle_180( double ang ) { //get the relative angle where -180 < angle < 180
return Math.atan2( Math.sin( ang ), Math.cos( ang ) );
}
/**
* 返回点(x2,y2)到(x1,y1)连线的绝对角度(战场场地参照系)
*/
double getAngle( double x1 , double y1 , double x2 , double y2 ) { //get the angle between two points
return Math.atan2( x2 - x1 , y2 - y1 );
}
}
- NekoNinja1.3 原码分析
- Perl原码分析3
- webrtc原码分析
- recommenderjob原码分析
- atoi原码分析
- N-Gram原码分析
- PERL原码分析2
- 原码、反码、补码分析
- OKHttp原码分析(一)
- IDL_原函数分析3
- 欢乐时光病毒原码分析
- 计算机中的原码、反码、补码分析
- 原码, 反码和补码分析
- 机智云程序原码分析
- Spark2.X 原码分析 ---- Rpc初探
- OKHttp原码分析(五)之Interceptor
- OKHttp原码分析(六)之RealConnection
- OKHttp原码分析(七)之HttpStream
- csdn
- LINUX学习-之-基本命令列表
- 远程唤醒源代码
- 经典Robocode例子代码
- 只言片语(一)
- NekoNinja1.3 原码分析
- 只言片语(二)
- 前段时间写了个邮件xml的xsl
- 操作系统中系统调用的必要性与实现
- Shark与Adapter设计模式
- Java中的路径及Resource
- 无法启动OracleOraHome81ManagementServer的解决方法
- JSP安全编程实例浅析(一)
- 第一章:Direct3D的初始化