/* * ---------------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * <martinv@students.zcu.cz> wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Martin Vítek * ---------------------------------------------------------------------------------- */ package cz.zcu.martinv.MyRobocodeRobots; import robocode.*; import static robocode.util.Utils.normalRelativeAngleDegrees; import java.awt.Color; import java.util.ArrayList; import java.util.Random; /** * Simple robot, which is realy bad. * Robots bahaviour is based on hard-coded behaviour and state machine. * * @author Martin Vítek */ public class BadBot extends AdvancedRobot { /** * All posible states of BadBot. */ private enum States { SCANNING, APROACHING, FIGHTING, RUNNING, RAMMING; } private RobotStatus status; private States state; private ArrayList<EnemyRobotStatus> enemyRobots; private int target; private int radarTurnDirection = 1; private int fightDirection = 1; private double previousEnergy; private String lastHitBy; /** * Main method - here is all robot logic. * It's called by RoboCode. */ @Override public void run() { out.format("Hi, I'm your bad robot!%n"); //Robot initialization setBodyColor(Color.GREEN); setRadarColor(Color.WHITE); setGunColor(Color.BLACK); setScanColor(Color.YELLOW); setAdjustGunForRobotTurn(true); //Gun movement is independent on body setAdjustRadarForGunTurn(true); //Radar movement is independent on body setAdjustRadarForRobotTurn(true); //Radar movement is independent on gun enemyRobots = new ArrayList<EnemyRobotStatus>(2); state = States.SCANNING; while(true) { switch(state) { case SCANNING: scanning(); break; case APROACHING: aproaching(); break; case FIGHTING: fighting(); break; case RUNNING: running(); break; case RAMMING: ramming(); break; } execute(); } } /** * This method is called when another robot is scanned. * It's called by RoboCode. * @param e passed by RoboCode */ @Override public void onScannedRobot(ScannedRobotEvent e) { switch(state) { case SCANNING: scanningOnScannedRobot(e); break; case APROACHING: aproachingOnScannedRobot(e); break; case FIGHTING: fightingOnScannedRobot(e); break; case RUNNING: runningOnScannedRobot(e); case RAMMING: rammingOnScannedRobot(e); break; } scan(); } @Override public void onHitByBullet(HitByBulletEvent e) { //state = States.RUNNING; //findNewTarget(); } @Override public void onHitRobot(HitRobotEvent e) { turnGunRight(normalRelativeAngleDegrees(getHeading() - getGunHeading() + e.getBearing())); setFire(3.0); setAhead(-100); setTurnRight(90.0); } @Override public void onHitWall(HitWallEvent e) { turnRight(180.0); ahead(250); } @Override public void onRobotDeath(RobotDeathEvent e) { findNewTarget(); } /** * This method is called when this robot wins. * It's called by RoboCode. * @param e passed by RoboCode */ @Override public void onWin(WinEvent e) { out.format("I'm not so bad after all :)%n"); turnRight(360); } private void scanning() { setTurnRadarRight(360.0); } private void scanningOnScannedRobot(ScannedRobotEvent e) { if (enemyRobots.contains(new EnemyRobotStatus(e))) return; enemyRobots.add(new EnemyRobotStatus(e)); //We have scaned all robots in current battle if (enemyRobots.size() == getOthers()) { out.format("We have scanned all (%d) enemy robots%n", enemyRobots.size()); //Select weakest weakest (od nearest) robot as target target = getNearest(); out.format("Selected: %s%n", enemyRobots.get(target).getName()); state = States.APROACHING; } } private void aproaching() { scanning(); } private void aproachingOnScannedRobot(ScannedRobotEvent e) { updateEnemyRobots(e); if (enemyRobots.size() == 0) return; EnemyRobotStatus enemy = enemyRobots.get(target); //Turn to enemy double turnAngle = enemy.getBearing(); turnRight(turnAngle); turnGunRight(turnAngle); if (enemy.getDistance() > 600.0) { setAhead(enemy.getDistance()-150.0); } else if (enemy.getDistance() < 100.0) { setAhead(enemy.getDistance()-200.0); } else { setTurnRight(90.0); state = States.FIGHTING; } } private void fighting() { scanning(); Random rand = new Random(); setAhead(rand.nextInt(150)-75); setTurnRight((double)(rand.nextInt(30)-15)); } private void fightingOnScannedRobot(ScannedRobotEvent e) { updateEnemyRobots(e); if (enemyRobots.size() == 0) return; EnemyRobotStatus enemy = enemyRobots.get(target); //If we have low energy, go to running mode if (getEnergy() < 20.0) { state = States.RUNNING; return; } //Fire setTurnGunRight(normalRelativeAngleDegrees(getHeading() - getGunHeading() + enemy.getBearing())); waitFor(new TurnCompleteCondition(this)); if (getGunHeat() == 0.0) { double firePower; if (enemy.getVelocity() < 0.2) firePower = 3.0; else firePower = Math.min(300.0/enemy.getDistance(), 3.0); setBulletColorWrapper(firePower); setFire(firePower); } double energyChange = previousEnergy - enemy.getEnergy(); previousEnergy = enemy.getEnergy(); //Dodge bullet if ((energyChange > 0.0) && (energyChange <= 3.0)) { ahead(100.0 * fightDirection); fightDirection *= -1; } //Ram if enemy have low energy if (enemy.getEnergy() < 15.0) { state = States.RAMMING; return; } //Face at 90° if difference is > 45° setTurnRight(normalRelativeAngleDegrees(enemy.getBearing()+90.0)); //Get closer or leave space if ((enemy.getDistance() < 40.0) || (enemy.getDistance() > 700.0)) { state = States.APROACHING; return; } } private void ramming() { scanning(); } private void rammingOnScannedRobot(ScannedRobotEvent e) { updateEnemyRobots(e); if (enemyRobots.size() == 0) return; EnemyRobotStatus enemy = enemyRobots.get(target); //Face enemy setTurnRight(normalRelativeAngleDegrees(enemy.getBearing())); setTurnGunRight(normalRelativeAngleDegrees(getHeading() - getGunHeading() + enemy.getBearing())); execute(); setAhead(enemy.getDistance() + 10); waitFor(new MoveCompleteCondition(this)); fire(3.0); } private void running() { scanning(); setTurnRight(360); setAhead(10000); } private void runningOnScannedRobot(ScannedRobotEvent e) { updateEnemyRobots(e); for (EnemyRobotStatus enemy : enemyRobots) { turnGunRight(normalRelativeAngleDegrees(getHeading() - getGunHeading() + enemy.getBearing())); fire(2.0); } if (getEnergy() > 40.0) { findNewTarget(); state = States.SCANNING; } } private void updateEnemyRobots(ScannedRobotEvent e) { EnemyRobotStatus robotToUpdate = new EnemyRobotStatus(e); int index = enemyRobots.indexOf(robotToUpdate); if (index < 0) return; enemyRobots.set(index, robotToUpdate); } private void findNewTarget() { target = 0; enemyRobots.clear(); state = States.SCANNING; } private int getWeakest() { if (enemyRobots.size() < 2) return 0; int weakest = 0; boolean allSame = false; for(int i=1; i<enemyRobots.size(); i++) { if (enemyRobots.get(weakest).getEnergy() > enemyRobots.get(i).getEnergy()) { weakest = i; } if (enemyRobots.get(weakest).getEnergy() != enemyRobots.get(i).getEnergy()) { allSame = true; } } if (allSame) return getNearest(); else return weakest; } private int getNearest() { int nearest = 0; for(int i=1; i<enemyRobots.size(); i++) { if (enemyRobots.get(nearest).getDistance() > enemyRobots.get(i).getDistance()) { nearest = i; } } return nearest; } /** * Wrapper for setBulletColor(). * Sets bullet color based on power. * @param power bullet power in range 0.0 - 3.0 */ private void setBulletColorWrapper(double firePower) { if ((firePower >= 0.0) && (firePower < 1.0)) setBulletColor(Color.WHITE); else if ((firePower >= 1.0) && (firePower < 2.0)) setBulletColor(Color.YELLOW); else if ((firePower >= 2.0) && (firePower <= 3.0)) setBulletColor(Color.RED); else return; } }