# MatchingMovementEX

This robot uses a new type of adaptive movement that I've been working on for a while but haven't been able to get anything too impressive out of, so I thought I'd post a bot using it just to see what people thought of it.

## The Movement

I was thinking about how there aren't many bots smaller than micros with effective adaptive movement, probably because it's not easy to shrink Wave Surfing down to that size. Similarly, relatively few small bots use GF guns (although there are more of those than wavesurfing small bots). This movement, which I am calling Matching Movement right now in the lack of a good name, has the same relationship to Pattern Matching that wave surfing has to GF targeting. What I do is keep a log of my movements, and mark the enemy robot's shots and hits. Then I use a pattern matching algorithm to find the most similar place in my history, and check to see if I was hit there. If I was hit, I move away from where the bullet hit me last time. An advantage to this movement is that it could theoretically be as effective as pattern matching is while still being small in terms of CodeSize. However, it hasn't done as well as I would've liked so far.

## The Robot

This robot is an example of "Matching Movement", albeit not a very good one. It segments on velocity and distance, and matches on the closest match as opposed to longest exact match. It also uses a pattern matching gun with the same segments as the movement (it actually uses the same algorithm for both gun and movement). Sadly, its movement doesn't do much better than a good random movement against most advanced targeting and doesn't have near the performance of wave surfing for dodging simple targeters. It also has issues with memory usage which could probably be easily fixed by a more experienced coder. Note that this robot can easily be turned into a micro without losing much performance, but that would result in even uglier code (which I apologize for by the way).

## The Code

package oog.mini; import java.awt.*; import java.awt.geom.*; import robocode.*; import robocode.util.*; public class MatchingMovementExperiment extends AdvancedRobot { final static Rectangle2D.Double fieldRect=new Rectangle2D.Double(18,18,764,564); final static double TWICE_MAX_TURN_RATE=Rules.MAX_TURN_RATE_RADIANS*2; final static int MATCH_LENGTH=30; final static int MAX_STORED_TICKS=750; static double movementsLog[][]=new double[6][1000000]; static int count=-1; static double eHeading; static double enemyEnergy; public void run(){ setAllColors(new Color(100,0,0)); setAdjustGunForRobotTurn(true); setAdjustRadarForGunTurn(true); setTurnRadarRightRadians(Double.POSITIVE_INFINITY); } public void onScannedRobot(ScannedRobotEvent e){ double absBearing=e.getBearingRadians()+getHeadingRadians(); double eDist; setTurnRadarRightRadians(Utils.normalRelativeAngle(absBearing-getRadarHeadingRadians())*2); Point2D.Double myPos=new Point2D.Double(getX(),getY()); Point2D.Double ePos=project(myPos,(eDist=e.getDistance()),absBearing); double turn=absBearing+Math.PI/2+getVelocity()*(500-e.getDistance())/3000; int dir=getVelocity()>0?1:-1; while(!fieldRect.contains(project(myPos,160*dir,turn-=0.1*dir))); setTurnRightRadians(Utils.normalRelativeAngle(turn-getHeadingRadians())); movementsLog[0][++count]=getVelocity(); movementsLog[2][count]=e.getVelocity(); movementsLog[3][count]=eHeading-(eHeading=e.getHeadingRadians()); movementsLog[4][count]=eDist; if(enemyEnergy-e.getEnergy()>=0.1&&enemyEnergy-e.getEnergy()<=3){ movementsLog[5][count]=1; } enemyEnergy=e.getEnergy(); movementsLog[5][count]=1; int moveIndex=findIndex(0); absBearing=0; int testCount; for(testCount=0;testCount<e.getDistance()/11D;testCount++){ if(movementsLog[1][moveIndex+testCount]==1){ break; } absBearing+=movementsLog[0][moveIndex+testCount]; } setAhead(absBearing>0?Double.NEGATIVE_INFINITY:Double.POSITIVE_INFINITY); double firePower=(e.getDistance()>100?(Math.min(Math.min(e.getEnergy()/4, getEnergy()/15),(e.getDistance()>200?2:2.5))):3); int gunIndex=findIndex(2); absBearing=e.getHeadingRadians(); for(int i=0;i<myPos.distance(ePos)/Math.min(19.9,Math.max(11,20-3*firePower));i++){ ePos=project(ePos,movementsLog[2][gunIndex+i],absBearing-=movementsLog[3][gunIndex+i]); } setTurnGunRightRadians(Utils.normalRelativeAngle(Utils.normalAbsoluteAngle(Math.atan2(ePos.x-myPos.x,ePos.y-myPos.y))-getGunHeadingRadians())); setFire(firePower); } public static int findIndex(int logType){ int index=0; double bestRating=Double.POSITIVE_INFINITY; for(int a=Math.max(MATCH_LENGTH,count-MAX_STORED_TICKS);a<count-MATCH_LENGTH;a++){ double rating=0; boolean hit=false; boolean shot=false; for(int i=0;i<MATCH_LENGTH;i++){ rating+=(Math.pow(Math.abs(movementsLog[logType][a-i]-movementsLog[logType][count-i])/16D,2)+ (logType==2?Math.pow(Math.abs(movementsLog[3][a-i]-movementsLog[3][count-i])/TWICE_MAX_TURN_RATE,2):0)+ Math.pow(Math.abs(movementsLog[4][a-i]-movementsLog[4][count-i])/1000D,2))/a; if(movementsLog[1][a+i]==1){ hit=true; } if(movementsLog[5][a-i]==1&&movementsLog[5][count-i]==1){ shot=true; } } if(rating<bestRating&&(logType==2||(hit&&shot))){ bestRating=rating; index=a+1; } } return index; } public void onHitByBullet(HitByBulletEvent e){ movementsLog[1][count]=1; } public static Point2D.Double project(Point2D.Double startPos,double dist,double heading){ return new Point2D.Double(startPos.x+dist*Math.sin(heading),startPos.y+dist*Math.cos(heading)); } }