SuperSpinBot

From Robowiki
Revision as of 11:07, 4 September 2017 by MultiplyByZer0 (talk | contribs) (Add infobox)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
SuperSpinBot
Author(s) CrazyBassoonist
Extends AdvancedRobot
Targeting Segmented Mean Circular Targeting
Movement Pattern Movement
Current Version 1.0
Code License Public domain
Download

SuperSpinBot is a part of the Super Sample Bots set by CrazyBassoonist. It is intended to provide new Robocoders with a new challenge after beating all of the sample robots. This robot is currently far more difficult to beat than the other Super Samples, but expect them to get harder soon too.

Movement

SuperSpinBot moves in circles, changing speed and turn rate every turn. It also randomly changes turn and movement direction when the enemy fires.

Targeting

SuperSpinBot uses a averaged velocity circular gun for aiming, segmented on enemy velocity. This is a decent gun in itself, and I expect it could be modified very easily to make it almost rumble-quality. This robot is a good starting point for learning very simple segmentation.

Code

package supersample;

import robocode.*;
import java.awt.*;
import robocode.util.*;
import java.awt.geom.*;

/**
 * SuperSpinBot - a Super Sample Robot by CrazyBassoonist based on the robot Spinbot by Mathew Nelson and maintained by Flemming N. Larsen
 * <p/>
 * Circular movement, Circular targeting.... Everything is circles.
 *                                                                                      
 * 		       S                            S                                             		
 *              R       P                    R       P                                         
 *             E         I                  E         I                                         
 *            P     O     N                P     O     N                                       
 *             U         B                  U         B                                         
 *               S     O                     S       O                                        
 *                  T                            T
 */





public class SuperSpinBot extends AdvancedRobot {
	//gun variables
	static double enemyVelocities[][]=new double[400][4];
	static int currentEnemyVelocity;
	static int aimingEnemyVelocity;
	double velocityToAimAt;
	boolean fired;
	double oldTime;
	int count;
	int averageCount;
	
	//movement variables
	static double turn=2;
	int turnDir=1;
	int moveDir=1;
	double oldEnemyHeading;
	double oldEnergy=100;
	public void run(){
		// Set colors
		setBodyColor(Color.blue);
		setGunColor(Color.blue);
		setRadarColor(Color.black);
		setScanColor(Color.yellow);

		setAdjustGunForRobotTurn(true);
		setAdjustRadarForGunTurn(true);
		do{
			turnRadarRightRadians(Double.POSITIVE_INFINITY);
		}while(true);
	}
	public void onScannedRobot(ScannedRobotEvent e){
		double absBearing=e.getBearingRadians()+getHeadingRadians();
		Graphics2D g=getGraphics();
		
		//increase our turn speed amount each tick,to a maximum of 8 and a minimum of 4
		turn+=0.2*Math.random();
		if(turn>8){
			turn=2;
		}
		
		//when the enemy fires, we randomly change turn direction and whether we go forwards or backwards
		if(oldEnergy-e.getEnergy()<=3&&oldEnergy-e.getEnergy()>=0.1){
			if(Math.random()>.5){
				turnDir*=-1;
			}
			if(Math.random()>.8){
				moveDir*=-1;
			}
		}
		
		//we set our maximum speed to go down as our turn rate goes up so that when we turn slowly, we speed up and vice versa;
		setMaxTurnRate(turn);
		setMaxVelocity(12-turn);
		setAhead(90*moveDir);
		setTurnLeft(90*turnDir);
		oldEnergy=e.getEnergy();
		
		
		//find our which velocity segment our enemy is at right now
		if(e.getVelocity()<-2){
			currentEnemyVelocity=0;
		}
		else if(e.getVelocity()>2){
			currentEnemyVelocity=1;
		}
		else if(e.getVelocity()<=2&&e.getVelocity()>=-2){
			if(currentEnemyVelocity==0){
				currentEnemyVelocity=2;
			}
			else if(currentEnemyVelocity==1){
					currentEnemyVelocity=3;
			}
		}
		
		//update the one we are using to determine where to store our velocities if we have fired and there has been enough time for a bullet to reach an enemy
		//(only a rough approximation of bullet travel time);
		if(getTime()-oldTime>e.getDistance()/12.8&&fired==true){
			aimingEnemyVelocity=currentEnemyVelocity;
		}
		else{
			fired=false;
		}
		
		//record a new enemy velocity and raise the count
		enemyVelocities[count][aimingEnemyVelocity]=e.getVelocity();
		count++;
		if(count==400){
			count=0;
		}
		
		//calculate our average velocity for our current segment
		averageCount=0;
		velocityToAimAt=0;
		while(averageCount<400){
			velocityToAimAt+=enemyVelocities[averageCount][currentEnemyVelocity];
			averageCount++;
		}
		velocityToAimAt/=400;
		
		
		//pulled straight out of the circular targeting code on the Robowiki. Note that all I did was replace the enemy velocity and
		//put in pretty graphics that graph the enemies predicted movement(actually the average of their predicted movement) 
		//Press paint on the robot console to see the debugging graphics.
		//Note that this gun can be improved by adding more segments and also averaging turn rate.
		double bulletPower = Math.min(2.4,Math.min(e.getEnergy()/4,getEnergy()/10));
		double myX = getX();
		double myY = getY();
		double enemyX = getX() + e.getDistance() * Math.sin(absBearing);
		double enemyY = getY() + e.getDistance() * Math.cos(absBearing);
		double enemyHeading = e.getHeadingRadians();
		double enemyHeadingChange = enemyHeading - oldEnemyHeading;
		oldEnemyHeading = enemyHeading;
		double deltaTime = 0;
		double battleFieldHeight = getBattleFieldHeight(), 
		       battleFieldWidth = getBattleFieldWidth();
		double predictedX = enemyX, predictedY = enemyY;
		while((++deltaTime) * (20.0 - 3.0 * bulletPower) < 
		      Point2D.Double.distance(myX, myY, predictedX, predictedY)){		
			predictedX += Math.sin(enemyHeading) * velocityToAimAt;
			predictedY += Math.cos(enemyHeading) * velocityToAimAt;
			enemyHeading += enemyHeadingChange;
			g.setColor(Color.red);
			g.fillOval((int)predictedX-2,(int)predictedY-2,4,4);
			if(	predictedX < 18.0 
				|| predictedY < 18.0
				|| predictedX > battleFieldWidth - 18.0
				|| predictedY > battleFieldHeight - 18.0){

				predictedX = Math.min(Math.max(18.0, predictedX), 
				    battleFieldWidth - 18.0);	
				predictedY = Math.min(Math.max(18.0, predictedY), 
				    battleFieldHeight - 18.0);
				break;
			}
		}
		double theta = Utils.normalAbsoluteAngle(Math.atan2(
		    predictedX - getX(), predictedY - getY()));

		setTurnRadarRightRadians(Utils.normalRelativeAngle(
		    absBearing - getRadarHeadingRadians())*2);
		setTurnGunRightRadians(Utils.normalRelativeAngle(
		    theta - getGunHeadingRadians()));
		if(getGunHeat()==0){
			fire(bulletPower);
			fired=true;
		}
	}
}