robocode机器人案例

1、游戏规则:

生命规则:

​ 相撞损失:撞到墙时,生命点损伤度=Math.abs (velocity) * 0.5 -1。撞到另一个坦克时,移动停止,生命点损失6点,扣除积分1.2分。
​ 击中损失:当子弹能量为1时,我们生命点损失=4 * power,如果子弹能量大于1,那么我们的生命损失+= 2 * (power-1)。
​ 发射损失:如果我们的子弹打中别的坦克,我们可以从子弹那窃取到3*power的能量。

炮弹规则:

​ 子弹能量:子弹能量是通过凼数getPower()得到的。它大于等于0.1,小于等于3。
​ 子弹速度:每一颗子弹有着自身的速度,这在处理敌人向你开炮前的秱动策略可是很有帮助的。子弹的速度也和它的能量有关: speed = 20 - 3 * power。由于能量范围在0.1到3之间我们可求得子弹的速度范围:11 <= bullet speed <= 19.7。

炮管规则:

​ 旋转速率:炮管在每一个时间周期内旋转速率=20 度/帧(frame)
​ 炮管热量:当我们开火时,炮管产生的热量由子弹开火时的能量决定。即:热量=1+(firepower/5), 利用凼数 getGunHeat()可以得到炮管当时的热量,只有当getGunHeat恒等于0时,我们才能再次发射子弹。
​ 冷却度:有热度当然就有冷却度,丌冷却我们的炮管会永远丌会开火的。系统设定的默认冷却速度是0.1/tick(时间周期),我们可通过凼数 getGunCoolingRate()得到这个参数值。

雷达规则:

​ 旋转速度:雷达以每时间周期45度的速度旋转。也即45 degrees/frame.
​ 扫描面积: 雷达扫描是呈扇形的,它的开始位置到终止位置的长度大约为1200。只要我们放大屏幕可以通过眼睛估算出这个面积。
​ 扫描排列:扫描到的数据有墙,目标,子弹等等。这些是按扫描距离来排列,从离雷达最近的物体开始到最后扫描到的物体。

运行规则:

​ 前进速度:坦克最大的速度(Velocity)为8,凼数getVelocity()迒回了坦克当前的速度。
​ 加/减速度:加速度为 1 像素(pixel)/帧frame ,减速度为 2 pixel/frame。
​ 参考公式: 设s为距离,Vt为终速度,Vo为初速度,t为时间,a 为加速度:
​ 位秱公式 s=Vot+att/2
​ 速度公式 Vt =Vo +a
t
​ 平均速度公式 v=(Vt + Vo)/2=s/t
​ 加速度公式 a=(Vt - Vo)/t
​ (这些公式大家都学过吧?)

旋转规则:

​ 旋转速度:机器人的旋转速度和当前的速度有关即旋转速度=10 - 0.75 * getVelocity()。
​ 相互作用参数:雷达安装在炮上,炮安装在机器人上,它们会相互影响。如果我们向左转动炮管,而使雷达向右转动,那么雷达只会向右转动(45-20) =25度;如果两者都向右转动,雷达将向右转(45+20)=65度。同样的道理炮和机器人也是方向同相加,方向反相减。

积分规则:

​ Robot Name - 机器人的名字;
​ Total Scroe - 为这次比赛你的总共得分;
​ Survival - 是你存活率的得分;
​ Last Survivor Bonus:你是赢的次数相对对手的分红得分;
​ Bullet Dmg:是你的子弹损失得分也即发射的子弹数的得分;
​ Bonus:是子弹数的分红得分;
​ Ram Dmg *2是你的撞击得分;
​ Bonus:是你撞击得分分红;
​ 最后两项Survival 1sts,是你赢的次数,丌算做分数。

部分接口:

部分重要的接口函数介绍(全部函数参考安装文件夹下的Javadoc文件夹):
    坦克属性:
    double getBattleFieldHeight() 战场高度
    double getBattleFieldWidth() 战场宽度   
    double getHeight() 坦克高度
    String getName() 坦克名称
    double getWidth() 坦克宽度   
    double getGunHeading() 炮管角度
    double getHeading() 坦克角度
    double getRadarHeading() 雷达角度   
    double getX() 坐标X
    double getY() 坐标Y   
    double getGunHeat() 炮管热量
    double getEnergy() 能量数值
    double getGunCoolingRate() 炮管冷却比例   
    double getVelocity() 坦克速度

    运行控制:
    void ahead(double distance) 前进
    void back(double distance) 后退
    void doNothing()void fire(double power) 开火   
    void setAdjustGunForRobotTurn(boolean independent)/车同向
    void setAdjustRadarForGunTurn(boolean independent)/雷达同向
    void setAdjustRadarForRobotTurn(boolean independent) 雷达/车同向   
    void turnRadarLeft(double degrees) 雷达左转角度
    void turnRadarRight(double degrees) 雷达右转角度
    void turnGunLeft(double degrees) 炮左转角度
    void turnGunRight(double degrees) 炮右转角度
    void turnLeft(double degrees) 车左转角度
    void turnRight(double degrees) 车右转角度

    战斗事件:
    void onBulletHit(BulletHitEvent event) 子弹击中坦克
    void onBulletHitBullet(BulletHitBulletEvent event) 子弹击中子弹
    void onBulletMissed(BulletMissedEvent event) 子弹没有击中目标
    void onDeath(DeathEvent event) 坦克被消灭的时候
    void onHitByBullet(HitByBulletEvent event) 被子弹击中
    void onHitRobot(HitRobotEvent event) 被坦克撞击
    void onHitWall(HitWallEvent event) 撞墙
    void onRobotDeath(RobotDeathEvent event) 坦克死亡
    void onScannedRobot(ScannedRobotEvent event) 扫描到坦克
    void onWin(WinEvent event) 胜利   
    void run() 运行 voidscan() 扫描

    ScannedRobotEvent –雷达扫描:
    double getBearing() 获得相对自己坦克方向的角度
    double getBearingRadians() 获得相对自己坦克方向的弧度
    double getDistance() 获得距离
    double getEnergy() 获得运行能量
    double getHeading() 获得方向角度
    double getHeadingRadians() 获得方向弧度
    String getName() 获得坦克名称
    double getVelocity() 获得运行速度

    构造坦克的方式:
        Robot (常用) –支持较为全面的简单控制逻辑;
        TeamRobot –支持团队作战模式;
        AdvancedRobot –支持自定义事件.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uDgVfsQd-1573645318604)(C:\Users\root\Desktop\assets\1573610781554.png)]

2、机器人Demo

import robocode.*;

import java.awt.Color;

/**

 * SnippetBot - a robot by Alisdair Owens

 * This bot includes all sorts of useful snippets.  It is not

 * designed to be a good fighter (although it does well 1v1),

 * just to show how certain things are done

 * Bits of code lifted from Nicator and Chrisbot

 * Conventions in this bot include: Use of radians throughout

 * Storing absolute positions of enemy bots rather than relative ones

 * Very little code in events

 * These are all good programming practices for robocode

 * There may also be methods that arent used; these might just be useful for you.

 */

public class SnippetBot extends AdvancedRobot

{

    /**

     * run: SnippetBot's default behavior

     */

    Enemy target;                   //our current enemy  代表对手,包括了对手的所有有用参数

    final double PI = Math.PI;          //just a constant 

    int direction = 1;              //direction we are heading...1 = forward, -1 = backwards

                                    //我们坦克车头的方向

    double firePower;                   //the power of the shot we will be using - set by do firePower() 设置我们的火力

 

    public void run() 

    {

        target = new Enemy();               //实例化Enemy()类

        target.distance = 100000;           //initialise the distance so that we can select a target

        setColors(Color.red,Color.blue,Color.green);    //sets the colours of the robot

        //the next two lines mean that the turns of the robot, gun and radar are independant

        //让gun,radar独立于坦克车

        setAdjustGunForRobotTurn(true);

        setAdjustRadarForGunTurn(true);

        turnRadarRightRadians(2*PI);            //turns the radar right around to get a view of the field 以弧度计算旋转一周

        

        while(true) 

        {

            doMovement();               //Move the bot 移动机器人

            doFirePower();              //select the fire power to use 选择火力

            doScanner();                //Oscillate the scanner over the bot 扫描

            doGun();                    //move the gun to predict where the enemy will be 预测敌人,调整炮管

            out.println(target.distance);       

            fire(firePower);            //所有动作完成后,开火

            execute();              //execute all commands  上面使用的都为AdvancedRobot类中的非阻塞调用

                                    //控制权在我们,所有这里用阻塞方法返回控制给机器人

        }

    }

 

    /*

      * This simple function calculates the fire power to use (from 0.1 to 3)

      * based on the distance from the target.  We will investigate the data structure

      * holding the target data later.

      */

    void doFirePower() 

    {

        firePower = 400/target.distance;//selects a bullet power based on our distance away from the target 

                                        //根据敌人距离来选择火力,因为本身前进,后退为300,所以火力不会过大

    }

 

    /*

      * This is the movememnt function.  It will cause us

      * to circle strafe the enemy (ie move back and forward,

      * circling the enemy.  if you don't know what strafing means

      * play more quake.

      * The direction variable is global to the class.  Passing a

      * negative number to setAhead causes the bot to go backwards

      * 以目标主中心来回摆动

      */

    void doMovement() 

    {

        if (getTime()%20 == 0)  //?过20的倍数时间就反转方向

        {

            //every twenty 'ticks'

            direction *= -1;        //reverse direction

            setAhead(direction*300);    //move in that direction

        }

        setTurnRightRadians(target.bearing + (PI/2)); //every turn move to circle strafe the enemy 

                                                      //每一时间周期以敌人为中心绕圆运动

    }

    /*

    * this scanner method allows us to make our scanner track our target.

    * it will track to where our target is at the moment, and some further

    * in case the target has moved.  This way we always get up to the minute

    * information on our target   雷达锁定目标

    */

    void doScanner() 

    {

        double radarOffset;  //雷达偏移量

        if (getTime() - target.ctime > 4) //???why来回扫了4个回合都没扫到意味失去了目标,再全扫一遍

        {

            //if we haven't seen anybody for a bit....

            radarOffset = 360;      //rotate the radar to find a target

        } 

        else 

        {

            //next is the amount we need to rotate the radar by to scan where the target is now

            //通过扫描决定雷达旋转的弧度,"见基本原理方向剖析及目标锁定www.robochina.org".雷达弧度-敌人角度得到两者相差为旋转值

            radarOffset = getRadarHeadingRadians() - absbearing(getX(),getY(),target.x,target.y);

            //this adds or subtracts small amounts from the bearing for the radar to produce the wobbling

            //and make sure we don't lose the target

            //在得到的角度中加或减一点角度,让雷达很小的范围内摆而不失去目标

            if (radarOffset < 0)

            radarOffset -= PI/8;  //(0.375)

            else

            radarOffset += PI/8; 

        }

        //turn the radar

        setTurnRadarLeftRadians(NormaliseBearing(radarOffset)); //左转调整转动角度到PI内

    }

    /*

    * This simple method moves the gun to the bearing that we predict the

    * enemy will be by the time our bullet will get there.

    * the 'absbearing' method can be found in the helper functions section

    * the nextX and nextY method can be found in the 'Enemy' class description

    */

    void doGun() 

    {

        //works out how long it would take a bullet to travel to where the enemy is *now*

        //this is the best estimation we have 

        //计算子弹到达目标的时间长speed = 20 - 3 * power;有计算公式,距离除速度=时间

        long time = getTime() + (int)(target.distance/(20-(3*firePower)));

        //offsets the gun by the angle to the next shot based on linear targeting provided by the enemy class

        //以直线为目标,偏移子弹下一次发射的角度。(这样让子弹射空的几率减少。但对付不动的和做圆运动的机器人有问题)

        //target.guesssX(),target.guessY()为目标移动后的坐标

        double gunOffset = getGunHeadingRadians() - absbearing(getX(),getY(),target.guessX(time),target.guessY(time));

        setTurnGunLeftRadians(NormaliseBearing(gunOffset));  //调整相对角度到2PI内

    }

    /*

    * This set of helper methods.  You may find several of these very useful

    * They include the ability to find the angle to a point.

    */

    //if a bearing is not within the -pi to pi range, alters it to provide the shortest angle

    double NormaliseBearing(double ang) 

    {

        if (ang > PI)

        ang -= 2*PI;

        if (ang < -PI)

        ang += 2*PI;

        return ang;

    }

    //if a heading is not within the 0 to 2pi range, alters it to provide the shortest angle

    double NormaliseHeading(double ang) 

    {

        if (ang > 2*PI)

        ang -= 2*PI;

        if (ang < 0)

        ang += 2*PI;

        return ang;

    }

    //returns the distance between two x,y coordinates '**'

    //以两边长求得与对手之间的距离

    public double getrange( double x1,double y1, double x2,double y2 )

    {

        double xo = x2-x1;

        double yo = y2-y1;

        double h = Math.sqrt( xo*xo + yo*yo ); 

        return h;   

    }

    //gets the absolute bearing between to x,y coordinates

    //根据x,y的坐标求出绝对角度,见"坐标锁定"利用直角坐标系来反求出角度。???

    public double absbearing( double x1,double y1, double x2,double y2 )

    {

        double xo = x2-x1;

        double yo = y2-y1;

        double h = getrange( x1,y1, x2,y2 );

        if( xo > 0 && yo > 0 )

        {

            //反正弦定义,对边除斜边得弧度.以robocode中的绝对方向系及坐标系参照

            //x,y为正右上角为0-90,x正y负右下角为90-180,x,y负左下角180-270,x负,y正右上角270-360

            //此处要理解robocode中的绝对角度是上为0,下为180,如以中心为点划分象限则得到下面的结果

            return Math.asin( xo / h );

        }

        if( xo > 0 && yo < 0 )

        {

            return Math.PI - Math.asin( xo / h ); //x为正,y为负第二象限角

        }

        if( xo < 0 && yo < 0 )

        {

            return Math.PI + Math.asin( -xo / h ); //第三象限内180+角度

        }

        if( xo < 0 && yo > 0 )

        {

            return 2.0*Math.PI - Math.asin( -xo / h ); //四象限360-角度

        }

        return 0;

    }

    /**

    * onScannedRobot: What to do when you see another robot

     * 扫描事件,也是初始化目标数据的过程

    */

    public void onScannedRobot(ScannedRobotEvent e) 

    {

        //if we have found a closer robot....

        if ((e.getDistance() < target.distance)||(target.name == e.getName())) 

        {

            //the next line gets the absolute bearing to the point where the bot is

            //求得对手的绝对弧度

            double absbearing_rad = (getHeadingRadians()+e.getBearingRadians())%(2*PI);

            //this section sets all the information about our target

            target.name = e.getName();

            //求得对手的x,y坐标,见"robocode基本原理之坐标锁定"文章

            target.x = getX()+Math.sin(absbearing_rad)*e.getDistance(); //works out the x coordinate of where the target is

            target.y = getY()+Math.cos(absbearing_rad)*e.getDistance(); //works out the y coordinate of where the target is

            target.bearing = e.getBearingRadians();

            target.head = e.getHeadingRadians();

            target.ctime = getTime();               //game time at which this scan was produced 扫描到机器人的游戏时间

            target.speed = e.getVelocity();         //得到敌人速度

            target.distance = e.getDistance();

        }

    }

    public void onRobotDeath(RobotDeathEvent e) 

    {

        if (e.getName() == target.name)

        target.distance = 10000; //this will effectively make it search for a new target

    }   

 

}

 

 

/*

* This class holds scan data so that we can remember where enemies were

* and what they were doing when we last scanned then.

* You could make a hashtable (with the name of the enemy bot as key)

* or a vector of these so that you can remember where all of your enemies are

* in relation to you.

* This class also holds the guessX and guessY methods. These return where our targeting

* system thinks they will be if they travel in a straight line at the same speed

* as they are travelling now.  You just need to pass the time at which you want to know

* where they will be.

* 保存我们扫描到的目标的所有有用数据,也可用hashtable,vector方法处理所有和我们有关的目标数据(用于群战)

* 中间的guessX,guessY方法是针对做直线均速运动机器人一个策略

*/

class Enemy 

{

    /*

     * ok, we should really be using accessors and mutators here,

     * (i.e getName() and setName()) but life's too short.

     */

    String name;

    public double bearing;

    public double head;

    public long ctime; //game time that the scan was produced

    public double speed;

    public double x,y;

    public double distance;

    public double guessX(long when)

    {

        //以扫描时和子弹到达的时间差 * 最大速度=距离, 再用对手的坐标加上移动坐标得到敌人移动后的坐标

        long diff = when - ctime;

        return x+Math.sin(head)*speed*diff; //目标移动后的坐标

    }

    public double guessY(long when)

    {

        long diff = when - ctime;

        return y+Math.cos(head)*speed*diff;

    }

}

3、机器人强化版


import robocode.*;
import java.awt.*;
	import java.awt.Event;
	import javax.lang.model.element.ExecutableElement;
	import javax.swing.text.Document;
	import robocode.AdvancedRobot;
	import robocode.HitByBulletEvent;
import robocode.HitWallEvent;
import robocode.Robot;
 import robocode.ScannedRobotEvent;
 public class YanAn extends AdvancedRobot
 {
 	private double eDist; //对方的距离
 	private double move; //移动的距离
 	private double radarMove = 45; //雷达移动的角度
 	private double dFirePower; //火力
 	boolean movingForward;

 /**

- run: Crazy's main run function
  */
  public void run() 
  {
  eDist = 300;
  // 颜色
  setColors(Color.ORANGE, Color.BLUE, Color.RED, Color.WHITE, Color.GRAY);
  while(true)
  {
      //每过一个周期,运动随机的距离
  	double period = 4*((int)(eDist/80)); //周期;敌人越接近,周期越短,移动越频繁
  	//周期开始,则移动
  	if(getTime()%period == 0)
  	{
  		move = (Math.random()*2-1)*(period*8 - 25);
  	    setAhead(move + ((move >= 0) ? 25: -25));
  	}
  	//避免撞墙
  	double heading = getHeadingRadians(); //取得bot方向的弧度数
  	double x = getX() + move*Math.sin(heading); //移动move后将要达到的x坐标
  	double y = getY() + move*Math.cos(heading); //移动move后将要达到的y坐标
  	double dWidth = getBattleFieldWidth(); //战场的宽度
  	double dHeight = getBattleFieldHeight(); //战场的长度
  	//当(x,y)超过指定的范围,则反向移动move
  	if(x < 30 || x > dWidth-30 || y < 30 || y > dHeight-30)
  	{
  		setBack(move);
  	}
      turnRadarLeft(radarMove); //转动雷达
      execute();
  }
  }

 public void onHitWall(HitWallEvent e) 
 {
 	// Bounce off!
 	reverseDirection();
 }

 public void reverseDirection() 
 {
 	if (movingForward) {
 		setBack(40000);
 		movingForward = false;
 	} else {
 		setAhead(40000);
 		movingForward = true;
 	}
 }

 /**

- onScannedRobot:  Fire!
  */
  //onScannedRobot()每当‒在一个动作中‒看到另一个机器人时,游戏就会调用您的方法。它会发送一个事件,该事件可以告诉我们有关机器人的信息-机器人的名称,寿命,位置,前进方向,运行速度等。
  public void onScannedRobot(ScannedRobotEvent e) {
  eDist = e.getDistance(); //取得对方距离
  radarMove = -radarMove; //设置雷达
  double eBearing = e.getBearingRadians(); //取得和对方相对角度的弧度数
  //将bot转动相对的角度,以后bot的运动将是以对方为圆心的圆周运动
  setTurnLeftRadians(Math.PI/2 - eBearing);
  //转动炮管指向对方
  setTurnGunRightRadians(robocode.util.Utils.normalRelativeAngle(getHeadingRadians() + eBearing - getGunHeadingRadians()));
  //根据对方距离射击
  dFirePower = 400/eDist;
  if (dFirePower > 3)
  {
     dFirePower = 3;
  }
  fire(dFirePower);
  }

 /**

- onHitRobot:  Back up!
  */
  public void onHitRobot(HitRobotEvent e) 
  {
  // If we're moving the other robot, reverse!
  if (e.isMyFault()) 
  {
  	reverseDirection();
  }
  }
  }

4、网站

机器人官网

https://robocode.sourceforge.io/

IDEA环境开发机器人

https://my.oschina.net/kanlianhui/blog/1556868


ve = -radarMove; //设置雷达
 double eBearing = e.getBearingRadians(); //取得和对方相对角度的弧度数
 //将bot转动相对的角度,以后bot的运动将是以对方为圆心的圆周运动
 setTurnLeftRadians(Math.PI/2 - eBearing);
 //转动炮管指向对方
 setTurnGunRightRadians(robocode.util.Utils.normalRelativeAngle(getHeadingRadians() + eBearing - getGunHeadingRadians()));
 //根据对方距离射击
 dFirePower = 400/eDist;
 if (dFirePower > 3)
 {
    dFirePower = 3;
 }
 fire(dFirePower);
 }

/**

- onHitRobot:  Back up!
 */
 public void onHitRobot(HitRobotEvent e) 
 {
 // If we're moving the other robot, reverse!
 if (e.isMyFault()) 
 {
 	reverseDirection();
 }
 }
 }

4、网站

机器人官网

https://robocode.sourceforge.io/

IDEA环境开发机器人

https://my.oschina.net/kanlianhui/blog/1556868


  • 5
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值