Skip to content
Snippets Groups Projects
BadBot.java 10.4 KiB
Newer Older
Martin Vítek's avatar
Martin Vítek committed
/*
 * ----------------------------------------------------------------------------------
 * "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;
Martin Vítek's avatar
Martin Vítek committed
import java.awt.Color;
import java.util.ArrayList;
import java.util.Random;
Martin Vítek's avatar
Martin Vítek committed


/**
 * 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.
     */
Martin Vítek's avatar
Martin Vítek committed
    private enum States
    {
        SCANNING, APROACHING, FIGHTING, RUNNING, RAMMING;
Martin Vítek's avatar
Martin Vítek committed
    }

    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;
Martin Vítek's avatar
Martin Vítek committed
    
    /**
     * 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;
Martin Vítek's avatar
Martin Vítek committed
                case FIGHTING: fighting();
                    break;
Martin Vítek's avatar
Martin Vítek committed
                case RUNNING: running();
                    break;
Martin Vítek's avatar
Martin Vítek committed
                case RAMMING: ramming();
                    break;
            }
Martin Vítek's avatar
Martin Vítek committed
        }
    }
    /**
     * 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);
Martin Vítek's avatar
Martin Vítek committed
                
            case APROACHING: aproachingOnScannedRobot(e);
                break;
                
            case FIGHTING: fightingOnScannedRobot(e);
                break;
                
            case RUNNING: runningOnScannedRobot(e);
                
            case RAMMING: rammingOnScannedRobot(e);
                break;
Martin Vítek's avatar
Martin Vítek committed
        }
        
Martin Vítek's avatar
Martin Vítek committed
    }
    
    @Override
    public void onHitByBullet(HitByBulletEvent e)
    {
        //state = States.RUNNING;
        //findNewTarget();
Martin Vítek's avatar
Martin Vítek committed
    }
    
    @Override
    public void onHitRobot(HitRobotEvent e)
    {
        turnGunRight(normalRelativeAngleDegrees(getHeading() - getGunHeading() + e.getBearing()));
        setFire(3.0);
        setAhead(-100);
        setTurnRight(90.0);
Martin Vítek's avatar
Martin Vítek committed
    }
    
    @Override
    public void onHitWall(HitWallEvent e)
    {
        turnRight(180.0);
        ahead(250);
    }
    
    @Override
    public void onRobotDeath(RobotDeathEvent e)
    {
        findNewTarget();
Martin Vítek's avatar
Martin Vítek committed
    }
    
    /**
     * 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");
Martin Vítek's avatar
Martin Vítek committed
        turnRight(360);
    }
    
    private void scanning()
    {
        setTurnRadarRight(360.0);
Martin Vítek's avatar
Martin Vítek committed
    }
    
    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
Martin Vítek's avatar
Martin Vítek committed
        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());
            
Martin Vítek's avatar
Martin Vítek committed
            state = States.APROACHING;
        }
    }
    
    private void aproaching()
    {
Martin Vítek's avatar
Martin Vítek committed
    }
    
    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();
Martin Vítek's avatar
Martin Vítek committed
        
        Random rand = new Random();
        setAhead(rand.nextInt(150)-75);
        setTurnRight((double)(rand.nextInt(30)-15));
Martin Vítek's avatar
Martin Vítek committed
    }
    
    private void fightingOnScannedRobot(ScannedRobotEvent e)
Martin Vítek's avatar
Martin Vítek committed
    {
        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))
Martin Vítek's avatar
Martin Vítek committed
        {
            ahead(100.0 * fightDirection);
            fightDirection *= -1;
Martin Vítek's avatar
Martin Vítek committed
        }
        
        //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;
Martin Vítek's avatar
Martin Vítek committed
    }
}