본문 바로가기
Technote/JAVA

JAVA Robocode

by Pooh0216 2009. 5. 21.

JAVA Robocode

2007 대회 우승자 소스
 
package kdh;

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

public class LambOfGod extends AdvancedRobot 
{	
	double frameFigure = 1, prevEnergy = 100, counter = 0;			
	double enemyLatVelocity, enemyVelocity, lastenemyVelocity, lastenemyLatVelocity;		
	double lastVelocityChangeTime;
	double wallDistance, reverseWallDistance;	
	double nextAngle, qualifiedAngle; 
	double enemyDirection, firePower;
	boolean yAxis;
	
	Point2D myPosition, enemyPosition, nextPosition, centerPosition, predictedPosition;
	Rectangle2D battleField, movingField, meleeField;

	static int MIDDLE_FACTOR = 16;
	static int TOTAL_FACTORS = 33;	
	static double[][][][][][][] Data1 = new double[3][5][5][5][10][3][TOTAL_FACTORS];
	static double[][][][][][][] Data2 = new double[3][5][5][5][8][3][TOTAL_FACTORS];

	Wave root, current;	
	
	public void run() 
	{		
		setColors(new Color(200,0,50), new Color(150,0,50), new Color(100,0,50), Color.red, Color.pink);
		setAdjustGunForRobotTurn(true);
		setAdjustRadarForGunTurn(true);
		
		do {
			turnRadarRightRadians(Double.POSITIVE_INFINITY);	
			execute();
		} while (true);
	}

	public void onScannedRobot(ScannedRobotEvent e) 
	{
		double enemyDistance = e.getDistance(); 
		double enemyAbsBearing = e.getBearingRadians() + getHeadingRadians();
		double optimumAngle = enemyAbsBearing;
		double battleFieldWidth = getBattleFieldWidth(), battleFieldHeight = getBattleFieldHeight();
		boolean melee = (getOthers() > 2);
		
		if(melee)
		{
			setTurnRadarRightRadians(Utils.normalRelativeAngle(enemyAbsBearing - getRadarHeadingRadians()) * Math.PI*4);
		}else
		{
			setTurnRadarRightRadians(Utils.normalRelativeAngle(enemyAbsBearing - getRadarHeadingRadians()) * Math.PI/2);
		}
	
	
		firePower = Math.min(e.getEnergy()/4, ( enemyDistance > 250 ? 1.9 : 3));		
		if(melee)
		{
			if(getEnergy() < 10) firePower *= 0.5;
		}else
		{
			if(getEnergy() < 10) firePower = 0;
			if(getEnergy() < 10 && e.getEnergy() < 0.7) firePower = e.getEnergy()/4;
		}	
	
		double bulletVelocity = 20 - 3 * firePower;								
		
		lastenemyLatVelocity = enemyLatVelocity;
		lastenemyVelocity = enemyVelocity;
		enemyVelocity = e.getVelocity();
		
		myPosition = new Point2D.Double(getX(), getY());
		centerPosition = new Point2D.Double(battleFieldWidth / 2, battleFieldHeight / 2);
		enemyPosition = project(myPosition, enemyAbsBearing, enemyDistance);		
						
		battleField = new Rectangle2D.Double(18, 18, battleFieldWidth - 36, battleFieldHeight - 36);
		movingField = new Rectangle2D.Double(50, 50, battleFieldWidth - 100, battleFieldHeight - 100);
		meleeField = new Rectangle2D.Double(150, 150, battleFieldWidth - 300, battleFieldHeight - 300);
		
		enemyLatVelocity = enemyVelocity * Math.sin(e.getHeadingRadians() - enemyAbsBearing);
		enemyDirection = (enemyLatVelocity >= 0 ? 1 : -1) * Math.asin(8 / bulletVelocity);
	
		wallDistance = 1.1;
		while (wallDistance >= 0.1 && !battleField.contains(project(myPosition, enemyAbsBearing + (wallDistance -= 0.1) * enemyDirection, enemyDistance)));
		
		reverseWallDistance = 1.1;
		while (reverseWallDistance >= 0.1 && !battleField.contains(project(myPosition, enemyAbsBearing - (reverseWallDistance -= 0.1) * enemyDirection, enemyDistance)));
		
		double moveTime = bulletVelocity * lastVelocityChangeTime++ / enemyDistance;
		
		int accelIndex = (int)Math.round(Math.abs(enemyVelocity) - Math.abs(lastenemyVelocity));		
		if (accelIndex != 0) accelIndex = accelIndex > 0 ? 2 : 1;
		
		int velIndex = (int)Math.abs(enemyLatVelocity/2);		
		int fastVelIndex = (int)Math.abs(enemyLatVelocity/2.66);
		
		int timerIndex = moveTime < 0.4 ? 1 : moveTime < 0.8 ? 2 : moveTime < 1.2 ? 3 : 4;		
		int fastTimerIndex = moveTime < 0.6 ? 1 : 2;	
				
		int wallIndex = (int)(wallDistance * 3);
		int fastWallIndex = (int)(wallDistance * 1.5);
		
		int distanceIndex = (int)enemyDistance / 240;		
		int fastDistanceIndex = (int)enemyDistance / 360;
				
		int reverseWallIndex = (int)(reverseWallDistance * 2);
		int fastReverseWallIndex = (int)(reverseWallDistance * 1.25);
		
		if (accelIndex > 0) 
		{
			lastVelocityChangeTime = 0;
			timerIndex = fastTimerIndex = 0;
		}
			
		Wave wave = new Wave();
		
		wave.bulletOrigin = myPosition;
		wave.targetOrigin = wave.currentTarget = project(enemyPosition, e.getHeadingRadians(), enemyVelocity);
		wave.bulletAngle = Math.atan2(wave.targetOrigin.getX() - wave.bulletOrigin.getX() ,wave.targetOrigin.getY() - wave.bulletOrigin.getY());
		wave.bulletVelocity = bulletVelocity;
		wave.fireTime = wave.lastTime = getTime() - 1;
		wave.enemyDirection = enemyDirection;
		
		wave.Segment1 = Data1[accelIndex][velIndex][timerIndex][wallIndex][distanceIndex][reverseWallIndex];
		wave.Segment2 = Data2[accelIndex][fastVelIndex][fastTimerIndex][fastWallIndex][fastDistanceIndex][fastReverseWallIndex];
		
		if (getGunHeat() == 0) wave.real = true;
		
		if (root == null) current = root = wave;
		else current = (current.next = wave);			
				
		while (root != null && root.update(getTime(), enemyPosition)) root = root.next;	
		
		if (root != null) 
		{
			Wave waveIterator = root.next;
			while (waveIterator != null) 
			{					
				waveIterator.update(getTime(), enemyPosition);
				waveIterator = waveIterator.next;
			}
		}
	
		int bestIndex = MIDDLE_FACTOR;
		double bestValue = smoothed(bestIndex,wave.Segment1,TOTAL_FACTORS) + smoothed(bestIndex,wave.Segment2,TOTAL_FACTORS);
		for (int i = MIDDLE_FACTOR * 2 - 1; i >= 1; i--) 
		{	
			double currentValue = smoothed(i,wave.Segment1,TOTAL_FACTORS) + smoothed(i,wave.Segment2,TOTAL_FACTORS);
			if(currentValue > bestValue)
			{
				bestIndex = i;
				bestValue = currentValue;
			}
		}
	
		
		if(melee)
		{
			double deltaTime = 0;
			predictedPosition = enemyPosition;
			while((++deltaTime) * bulletVelocity < myPosition.distance(predictedPosition)){		
				predictedPosition.setLocation(
				predictedPosition.getX() + Math.sin(e.getHeadingRadians()) * enemyVelocity,
				predictedPosition.getY() + Math.cos(e.getHeadingRadians()) * enemyVelocity);
				
				if(!battleField.contains(predictedPosition))
				{
					predictedPosition.setLocation(
					Math.min(Math.max(18.0, predictedPosition.getX()), battleFieldWidth - 18.0),
					Math.min(Math.max(18.0, predictedPosition.getY()), battleFieldHeight - 18.0));
					break;
				}
			}
			double theta = Arctangent(myPosition, predictedPosition);			
			setTurnGunRightRadians(Utils.normalRelativeAngle(theta - getGunHeadingRadians()));
		} else
		{
			double reviseAngle = enemyDirection * (bestIndex / (double)MIDDLE_FACTOR - 1);
			setTurnGunRightRadians(Utils.normalRelativeAngle(enemyAbsBearing - getGunHeadingRadians() + reviseAngle));
		}
		setFireBullet(firePower);
		
		
		if (frameFigure-- < 0) 
		{		
		if(melee)
		{				
			if(counter==0)
			{
				nextPosition = new Point2D.Double(
				(getX() > battleFieldWidth/2 ? battleFieldWidth - getX() : getX()),
				(getY() > battleFieldHeight/2 ? battleFieldHeight - getY() : getY()));
								
				if(nextPosition.getX() < nextPosition.getY())
				{
					if(getX() > battleFieldWidth/2) Initialize(Math.PI/2, nextPosition.getX(), -1);
					else Initialize(-Math.PI/2, nextPosition.getX(), 1);
					yAxis = true;
				} else
				{	
					if(getY() > battleFieldHeight/2) Initialize(0, nextPosition.getY(), 1);
					else Initialize(Math.PI, nextPosition.getY(), -1);
					yAxis = false;
				}
				counter++;						
			}
							
			if(Math.atan(Math.tan(getTime() * Math.PI/40)) > 0) 
			{
				do { nextPosition = new Point2D.Double(Math.random() * battleFieldWidth, Math.random() * battleFieldHeight);
				} while (!movingField.contains(nextPosition) || meleeField.contains(nextPosition));	
		
				setAhead(yAxis ? nextPosition.getY() - getY() : nextPosition.getX() - getX());
			}		
			optimumAngle = getHeadingRadians();
		} else
		{		
			do {				
				while(!movingField.contains(nextPosition = new Point2D.Double(Math.random() * battleFieldWidth ,Math.random() * battleFieldHeight)));	
				nextAngle = Arctangent(myPosition, nextPosition);
				
				if (Comparison(nextAngle,enemyAbsBearing) > Comparison(optimumAngle,enemyAbsBearing)) optimumAngle = nextAngle; 			
			} while (Comparison(optimumAngle,enemyAbsBearing) < Math.PI/2);
		}
				
			qualifiedAngle = nextAngle = Utils.normalRelativeAngle(optimumAngle - getHeadingRadians());
			while(qualifiedAngle < -Math.PI/2) qualifiedAngle += Math.PI;
			while(qualifiedAngle > Math.PI/2) qualifiedAngle -= Math.PI;	
										
			setTurnRightRadians(qualifiedAngle);
			
			double movement = (qualifiedAngle == nextAngle ? 1 : -1) * myPosition.distance(nextPosition);
			if(Math.random() > 0.7) movement *= -frameFigure/Math.PI/2;
			if(!melee) setAhead(movement);	
						
			double deltaEnergy = e.getEnergy() - prevEnergy;
			if(deltaEnergy >= -3 && deltaEnergy < 0) frameFigure = enemyDistance / (20 - 3 * deltaEnergy);
			prevEnergy = e.getEnergy();	
			frameFigure *= (frameFigure >= 0 ? 1 : -1);
		}
	}

	public double Comparison(double angle1,double angle2)
	{
		return Math.abs(Math.tan(angle1 - angle2));
	}

	public double Arctangent(Point2D point1, Point2D point2)
	{
		return Utils.normalAbsoluteAngle(Math.atan2(point2.getX() - point1.getX(), point2.getY() - point1.getY()));
	}

	public void Reposition(Point2D target)
	{
		double targetX, targetY;
		targetX = (getX() > getBattleFieldWidth()/2) ?  getBattleFieldWidth() - target.getX() : target.getX();
		targetY = (getY() > getBattleFieldHeight()/2) ?  getBattleFieldHeight() - target.getY() : target.getY();
		
		target.setLocation(targetX, targetY);
	}

	public void Initialize(double angle, double distance, double sign)
	{		
		turnRightRadians(Utils.normalRelativeAngle(angle - getHeadingRadians()));
		ahead(distance - 25);
		turnRightRadians(sign * Math.PI/2);		
	}

	public Point2D project(Point2D position, double angle, double distance) 
	{
		return new Point2D.Double(position.getX() + Math.sin(angle) * distance, position.getY() + Math.cos(angle) * distance);
	}

	public double Section(double min, double max, double value) 
	{
		return value > max ? max : value < min ? min : value;
	}

	public double findGF(double startAngle, double newAngle, double enemyDirection, double middleFactor) 
	{	
		return Section(1, middleFactor * 2 - 1, Math.round((1 + Utils.normalRelativeAngle(newAngle - startAngle) / enemyDirection) * middleFactor));
	}

	public double smoothed(int GF, double[] seg, int TOTAL_FACTORS) 
	{
		double x = 0;
		for (int y = 1; y < TOTAL_FACTORS - 1; y++) 
		{
			x += (double)seg[y] / Math.sqrt((double)(Math.abs(GF - y) + 1.0));
		}
		return x;
	}

	class Wave 
	{
		Wave next;				
		Point2D bulletOrigin, targetOrigin, currentTarget;
		
		double bulletAngle, bulletVelocity, enemyDirection;
		double fireTime, lastTime;		
		double[] Segment1, Segment2;				
		boolean real = false;
		
		boolean update(double time, Point2D enemy) 
		{
			double deltaX = (enemy.getX() - currentTarget.getX()) / (time-lastTime);
			double deltaY = (enemy.getY() - currentTarget.getY()) / (time-lastTime);
			
			do{ if(bulletOrigin.distance(currentTarget) <= bulletVelocity * (lastTime - fireTime)) 
				{					
					double currentAngle = Arctangent(bulletOrigin, currentTarget);
					int index = (int)findGF(bulletAngle, currentAngle, enemyDirection, MIDDLE_FACTOR);
					
					double weightReal = 1;
					if(real) weightReal = 5;
					
					for (int i = 1; i < MIDDLE_FACTOR * 2; i++) 
					{
						Segment1[i] /= (1+weightReal / Segment1[0]);
						Segment2[i] /= (1+weightReal / Segment2[0]);
					}	
				
					Segment1[0] += weightReal;					
					Segment2[0] += weightReal;
					Segment1[index] += (weightReal / Segment1[0]);
					Segment2[index] += (weightReal / Segment2[0]);
					
					return true;
				}
				lastTime++;
				currentTarget.setLocation(currentTarget.getX() + deltaX, currentTarget.getY() + deltaY);				
			}while (lastTime < time);
		
			return false;
		}
	}	
}																			
 

'Technote > JAVA' 카테고리의 다른 글

RoboCode -ActionSchool Team - 2rd  (0) 2009.05.29
10주차 10번문제  (0) 2009.05.14
10주차 9번문제  (0) 2009.05.14
10주차 8번문제  (0) 2009.05.14
10주차 7번문제  (0) 2009.05.14