97
\$\begingroup\$

AlienWar

This game takes place in a very crowded planet where aliens are the superior race. Your task is to create your own alien and beat all other.

The Board

It is a 2 dimensional board.
The length of one side of the board is Math.ceil(sqrt(species * 100 * 2.5)) = ~40% of board used. The board is a planet, so if you walk out of the map in the west, you come back in the east. If you walk out in the north, you will find yourself in the south.

Abilities

Each species on the planet has abilities. Here they are:

Name        Benefit
life        HP = lifeLVL * 5 (reduces with every hit you take, 0 = dead), base HP = 10
strength    Your hits do a random int in range [1 to strengthLVL] damage
defense     Randomly select int in range [0 to (50 / defenseLVL + 1)], if int == 0 then dodge next attack
vision      Gives you visionLVL/2 fields around you vision
cleverness  Blurs (increases) every ability randomly in range [0 to clevernessLVL/2] when sending to other aliens

The Game

  • There will be 100 instances of each submission.
  • After instancing, each alien can set 10 ability points in total. You can set different points for every instance.
  • If you set more than 10 points, the instance dies.
  • A game consists of 1000 rounds. Each round:
    • Every alien has to return a move via move(char[] fields). This includes Move.STAY.
    • If several aliens are on a field, 2 will be randomly selected:
      • If both agree on peace (return false in wantToFight) they will stay where they are, else they will fight.
      • This loops until only one alien stays on a field or all agree on peace.
  • If an alien kills something, he gets 1/5 of each of his enemies abilities. The winners HP will be refilled with 2*enemyLifeLVL.

  • Winner is the one with the most abilities (sum of abilities of living aliens).

Fights

Both aliens will hit each other "at the same time", this means if you kill the other alien, he still can hit you one time.

Dodging: Before you get hit, the game will calculate if you can dodge the attack by using rand.nextInt(50 / defenseLvl + 1) == 0. defenseLvl will never be greater than 50 when calculating your dodge-skills (hence maximum dodge-chance is 50%).

Hitting: If you don't dodge the attack, you will get hit and your HP will be reduced by rand.nextInt(enemy.getStrengthLvl()) + 1.

A fight ends when either one or both alien involved are dead. The winner, if one exists, gets the reward.

Gamerules

  • Base level for every ability (without giving any ability points) is 1 (base HP is 10).
  • The values sent when asked to fight are life (not HP!), strength, defense and vision-levels.
  • Cleverness is NOT sent when asked to fight.
  • All floating numbers will be ROUNDED to nearest integer when using/sending them, but stored and increased as float.
  • Maximum dodge-chance is 50%. Otherwise fights may never terminate.

The Prey

There are 5 species which are already on the field. Since they are prey, they choose not to fight when asked to.

Whale:       lvl 10 life            Stays   
Cow:         lvl 10 strength        Random move
Turtle:      lvl 10 defense         South west
Eagle:       lvl 10 vision          Examines fields, tries to avoid danger      
Human:       lvl 10 cleverness      North east

They will be represented with their first letter (i.e. W for whale) in the map (Aliens with A, empty fields with a whitespace ' ').

Additional Rules

  • Reflection is disallowed.
  • Interacting (instancing etc.) with other aliens is disallowed.
  • Writing/Reading external resources like files or databases is also disallowed.
  • Only Java (version 1.8) submissions allowed (Java is rather easy, and you don't have to be an expert for this game).
  • All submissions must extend the alien-class and will be placed in the alien-package.
  • I will accept the best alien on 19th of July. All aliens submitted by 12:00 UTC that day will be tested.
  • Maximum 3 submissions per user since there are already very many aliens.

Example of an alien

package alien;

import planet.Move;

public class YourUniqueNameHere extends Alien {

    public void setAbilityPoints(float[] abilities) {
        abilities[0] = 2; //life
        abilities[1] = 2; //strength
        abilities[2] = 2; //defense
        abilities[3] = 2; //vision
        abilities[4] = 2; //cleverness
    }

    public Move move(char[][] fields) {
        //you are in the middle of the fields, say fields[getVisionFieldsCount()][getVisionFieldsCount()]
        return Move.STAY;
    }

    public boolean wantToFight(int[] enemyAbilities) {
        //same order of array as in setAbilityPoints, but without cleverness
        return true;
    }

}

Control program

Source code for the control program can be found here. Now updated with all aliens included in the latest run.

Final scores (20.07.2014, average of 10 games)

alien.PredicatClaw                  1635.4
alien.LazyBee                       1618.8
alien.CartographerLongVisionAlien   1584.6
alien.ChooseYourBattles             1571.2
alien.Bender                        1524.5
alien.HerjanAlien                   1507.5
alien.FunkyBob                      1473.1
alien.SecretWeapon2                 1467.9
alien.PredicatEyes                  1457.1
alien.CorporateAlien                1435.9
alien.GentleGiant                   1422.4
alien.CropCircleAlien               1321.2
alien.VanPelt                       1312.7
alien.NewGuy                        1270.4
alien.BananaPeel                    1162.6
alien.Rock                          1159.2
alien.BullyAlien                    1106.3
alien.Geoffrey                      778.3
alien.SecretWeapon                  754.9
alien.SecretWeapon3                 752.9
alien.FunkyJack                     550.3
alien.Stone                         369.4
alien.Assassin                      277.8
alien.Predicoward                   170.1
prey.Cow                            155.2
alien.Morphling                     105.3
alien.Eli                           99.6
alien.Warrior                       69.7
alien.Hunter                        56.3
alien.Manager                       37.6
alien.OkinawaLife                   14.2
prey.Whale                          10.5
alien.Gamer                         4.5
alien.Randomite                     0
alien.Guard                         0
prey.Eagle                          0
alien.Rogue                         0
alien.WeakestLink                   0
alien.Fleer                         0   
alien.Survivor                      0
alien.Sped                          0
alien.Junkie                        0
alien.Coward                        0
alien.CleverAlien                   0
prey.Human                          0
alien.BlindBully                    0
prey.Turtle                         0
alien.AimlessWanderer               0
\$\endgroup\$
81
  • 14
    \$\begingroup\$ Three downvotes, what on earth? And I don't see a single negative comment. Are people that passive aggressively annoyed that this is limited to Java? \$\endgroup\$ Commented Jul 2, 2014 at 9:11
  • 6
    \$\begingroup\$ @m.buettner My downvote is for the limitation to the godawfulness that is Java (though if it was limited to the nicest language ever created I'd still downvote it for limiting it to 1 language). I didn't see the point in adding a comment since it was obvious what the downvotes would be for. \$\endgroup\$
    – Gareth
    Commented Jul 2, 2014 at 14:41
  • 6
    \$\begingroup\$ Hmmm, am having mixed feelings here \$\endgroup\$
    – Mr. Alien
    Commented Jul 3, 2014 at 9:15
  • 5
    \$\begingroup\$ @user3334871 I don't think changing any of the rules after 17 answers are in (and potentially a dozen more people working on submissions) is a good idea. Since only the fewest of us here (if any) are professional game designers, pretty much any self-made KotH may have some balancing issues - but if exploring the space of possible strategies is still fun (which apparently it is, judging by answers, upvotes and stars), I don't think it's much of a problem. \$\endgroup\$ Commented Jul 3, 2014 at 9:17
  • 5
    \$\begingroup\$ @Manu For the mathematically inclined the description of how the board wraps is somewhat misleading. You're saying it's a planet and it wraps east/west. There is nothing that really indicates that it does wrap north/south, too. In fact, if it does, it's technically not a sphere any more, but a torus: kotaku.com/classic-jrpg-worlds-are-actually-donuts-1239882216. You can also see that by noticing that when you walk "off" the top of a world map (the north pole), you don't appear at the bottom (the south pole). Hence, Michael's suggestion is definitely valid, I think. \$\endgroup\$ Commented Jul 4, 2014 at 16:52

44 Answers 44

27
\$\begingroup\$

Manager

Here's a manager. Naturally, the cleverness is 0 and he always strives to go where the sun don't shine. And, of course, he will only fight the weak and is very good in dodging trouble:

public class Manager extends Alien {

    private static final int STRENGTH = 5;

    @Override
    public void setAbilityPoints( float[] abilities ) {
        abilities[/* strength   */ 1] = STRENGTH;
        abilities[/* defense    */ 2] = 5;
        abilities[/* cleverness */ 4] = 0; // just to make sure
    }

    @Override
    public Move move( char[][] fields ) {
        return Move.WEST;
    }

    @Override
    public boolean wantToFight( int[] enemyAbilities ) {
        return enemyAbilities[1] < STRENGTH;
    }
}
\$\endgroup\$
4
  • \$\begingroup\$ +1, if only for the intro. :P \$\endgroup\$
    – apnorton
    Commented Jul 3, 2014 at 18:19
  • 6
    \$\begingroup\$ Every time I read that comment ("just to make sure") I have to laugh :-D \$\endgroup\$
    – Matthias
    Commented Jul 4, 2014 at 15:01
  • \$\begingroup\$ Funny, I was just reading this: blog.codinghorror.com/i-shall-call-it-somethingmanager \$\endgroup\$
    – 11684
    Commented Jul 6, 2014 at 21:31
  • \$\begingroup\$ @11684 any decent developer knows that, of course, but in my case I actually do mean a manager ;) \$\endgroup\$
    – Ingo Bürk
    Commented Jul 7, 2014 at 4:41
18
\$\begingroup\$

CartographyLongVisionAlien

This Alien is a consistant performing variant of one of my attempts to produce an alien that is of winning potential.

It has initial 5x5 vision which it uses to build up an internal map of the surrounding area giving it superior enemy avoidance ability.

In my testing of 100 rounds, on average, It sneaks ahead of all other aliens. (09/07/2014)

UPDATED GIF showing the repell/attract field effect

I have modified the Game code to produce animated GIFs of the simulation. You can view such a simluation here

 package alien;

 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Random;
 import planet.Move;
 import planet.Planet;

 /**
  * Created by moogie on 09/07/14.
  * 
  * This Alien attempts to map the visible and guess the movements within the immediate non-visible area around the alien.
  * To this end, the alien can initially see 5x5 grid. It applies weights on the cells of its internal map based on the 
  * prey/alien/blanks within its field of view. It then performs a simple blur to guess movements and then chooses the optimum move
  * based on the contents of its internal map.
  * 
  * If it is asked to fight, it performs battle simulations to determine whether it should nominate to fight.
  */
 public class CartographerLongVisionAlien extends Alien
 {
   private final static byte LIFE = 0, STR = 1, DEF = 2, VIS = 3, CLV = 4;

   // Plant Entity symbols
   private static final char TURTLE = 'T';
   private static final char HUMAN = 'H';
   private static final char WHALE = 'W';
   private static final char COW = 'C';
   private static final char EAGLE = 'E';
   private static final char ALIEN = 'A';
   private static final HashMap<Character, Move> preyMovement = new HashMap<>();

   static 
   {
     preyMovement.put(WHALE, Move.STAY);
     preyMovement.put(TURTLE, Move.SOUTHWEST);
     preyMovement.put(HUMAN, Move.NORTHEAST);
   };

   // Map constants
   public static final int MAP_SIZE_DIV_2 = 10;
   public static final int MAP_SIZE = MAP_SIZE_DIV_2 * 2 + 1;
   private static final int MAP_SIZE_MINUS_ONE = MAP_SIZE - 1;
   private static final double FADE_FACTOR=0.85;

   // Planet constants
   private static final int STARTING_HP = 10;
   private static final int START_HEALING_FACTOR = 5;
   private static final int MAX_DEFENCE = 50;

   // Battle Simulation constants
   private static final double AMBIGUOUS_ENEMY_HP_FACTOR = 2;
   private static final int SIMULATED_BATTLE_COUNT = 100;
   private static final int SIMULATED_BATTLE_THREASHOLD = (int)(SIMULATED_BATTLE_COUNT*1.0);

   private Random rand = new Random(Planet.rand.nextLong());

   /** The alien's map of the immediate and mid-range area */
   public double[][] map = new double[MAP_SIZE][MAP_SIZE];

   public void setAbilityPoints( float[] abilities )
   {
     // +0.5 gain due to rounding trick "borrowed" from PredicatClaw http://codegolf.stackexchange.com/a/32925/20193
     abilities[LIFE] = 3.5f; // We do need some hit points to ensure that we can survive the melee of the beginning game.
     abilities[STR] = 4.5f; // A Moderate attack strength means that we do not have to go through as many fight rounds.
     abilities[DEF] = 0; // We will get from prey and other aliens
     abilities[VIS] = 2; // A minimum of 2 is required to get a 5x5 field of view
     abilities[CLV] = 0; // We will get from prey and other aliens
   }

   /**
    * simulate alien memory fade. This allows an alien to eventually venture back to areas already traversed.
    */
   private void fadeMap()
   {
     for ( int y = 0; y < MAP_SIZE; y++ )
     {
       for ( int x = 0; x < MAP_SIZE; x++ )
       {
         map[x][y] *= FADE_FACTOR;
       }
     }
   }

   /**
    * shift the maps with the movement of the alien so that the alien is always at the centre of the map
    * 
    * @param move
    */
   private void shiftMaps( Move move )
   {
     int i, j;
     final int offsetX = -move.getXOffset();
     final int offsetY = -move.getYOffset();
     double[][] tempMap = new double[MAP_SIZE][MAP_SIZE];
     for ( int y = 0; y < MAP_SIZE; y++ )
     {
       for ( int x = 0; x < MAP_SIZE; x++ )
       {
         i = x + offsetX;
         j = y + offsetY;

         if ( i >= 0 && i <= MAP_SIZE_MINUS_ONE && j >= 0 && j <= MAP_SIZE_MINUS_ONE )
         {
           tempMap[i][j] = map[x][y];
         }
       }
     }
     map = tempMap;
   }

   /**
    * Updates a cell in the alien's map with the desirability of the entity in the cell
    * 
    * @param x
    * @param y
    * @param chr
    */
   private void updateMap( int x, int y, char chr )
   {
     // Note that these desire values are just guesses... I have not performed any analysis to determine the optimum values!
     // That said, they seem to perform adequately.
     double desire = 0;

     int i=x;
     int j=y;
     switch ( chr )
     {
       case WHALE:
         desire=2;
         break;
       case TURTLE:
       case HUMAN:
         desire=1;
         Move preyMove = preyMovement.get( chr );

         // predict movement into the future
         while ( i >= 0 && i <= MAP_SIZE_MINUS_ONE && j >= 0 && j <= MAP_SIZE_MINUS_ONE )
         {
           map[i][j] = ( map[i][j] + desire ) / 2;
           i+=preyMove.getXOffset();
           j+=preyMove.getYOffset();
           desire/=2;
         }
         break;
       case COW:
         desire = 0.5;
         break;
       case EAGLE:
         desire = 1;
         break;
       case ALIEN:
         desire = -10;
         break;
     }

     map[x][y] = ( map[x][y] + desire ) / 2;
   }

   /**
    * Apply a blur the map to simulate the movement of previously seen entities that are no longer within the field of view.
    */
   private void convolve()
   {
     double[][] tempMap = new double[MAP_SIZE][MAP_SIZE];

     int count;
     double temp;
     for ( int y = 0; y < MAP_SIZE; y++ )
     {
       for ( int x = 0; x < MAP_SIZE; x++ )
       {
         count = 0;
         temp = 0;
         for ( int i = x - 1; i < x + 2; i++ )
         {
           for ( int j = y - 1; j < y + 2; j++ )
           {
             if ( i >= 0 && i <= MAP_SIZE_MINUS_ONE && j >= 0 && j <= MAP_SIZE_MINUS_ONE )
             {
               temp += map[i][j];
               count++;
             }
           }
         }
         temp += map[x][y] * 2;
         count += 2;

         tempMap[x][y] = temp / count;
       }
     }
     map = tempMap;
   }

   /**
    * Determine the move that minimises the risk to this alien and maximises any potential reward.
    * 
    * @param fields
    * @return
    */
   private Move findBestMove( char[][] fields )
   {
     List<Move> moveOptions = new ArrayList<>();
     double bestMoveScore = -Double.MAX_VALUE;
     double score;

     // find the moves that have the best score using the alien's map
     for ( Move move : Move.values() )
     {
       int x = MAP_SIZE_DIV_2 + move.getXOffset();
       int y = MAP_SIZE_DIV_2 + move.getYOffset();
       score = map[x][y];
       if ( score == bestMoveScore )
       {
         moveOptions.add( move );
       }
       else if ( score > bestMoveScore )
       {
         bestMoveScore = score;
         moveOptions.clear();
         moveOptions.add( move );
       }
     }

     Move move = moveOptions.get( rand.nextInt( moveOptions.size() ) );

     // if the best move is to stay...
     if ( move == Move.STAY )
     {
       // find whether there are no surrounding entities in field of vision...
       int midVision = getVisionFieldsCount();
       boolean stuck = true;
       out: for ( int i = 0; i < fields.length; i++ )
       {
         for ( int j = 0; j < fields.length; j++ )
         {
           if ( !( i == midVision && j == midVision ) && fields[i][j] != ' ' )
           {
             stuck = false;
             break out;
           }
         }
       }

       // there there are no other entities within field of vision and we are healthy... choose a random move
       if ( stuck && getCurrentHp() > getLifeLvl() * 2 )
       {
         move = Move.getRandom();
       }
     }
     return move;
   }

   /**
    * Update the alien's map with the current field of vision
    * 
    * @param fields
    */
   private void mapVisibleSurroundings( char[][] fields )
   {
     int midVision = getVisionFieldsCount();

     // update the map with currently visible information
     for ( int y = -midVision; y <= midVision; y++ )
     {
       for ( int x = -midVision; x <= midVision; x++ )
       {
         char chr = fields[midVision + x][midVision + y];
         updateMap( MAP_SIZE_DIV_2 + x, MAP_SIZE_DIV_2 + y, chr );
       }
     }

     // ensure that the map where this alien currently sits is marked as empty.
     updateMap( MAP_SIZE_DIV_2, MAP_SIZE_DIV_2, ' ' );
   }

   public Move move( char[][] fields )
   {
     Move returnMove = null;

     // pre-move decision processing
     mapVisibleSurroundings( fields );
     convolve();

     returnMove = findBestMove( fields );

     // post-move decision processing
     fadeMap();
     shiftMaps( returnMove );

     return returnMove;
   }

   public boolean wantToFight( final int[] enemyAbilities )
   {
     double toughnessFactor =((double) enemyAbilities[STR])/(enemyAbilities[LIFE]*10); // a fudge-factor to ensure that whales are attacked.
     if (enemyAbilities[VIS]>=3 && enemyAbilities[LIFE]>4.5f) toughnessFactor*=3.5; // make sure that we do not attack other Cartogapher aliens 
     return winsBattleSimulation( enemyAbilities, toughnessFactor );
   }

   /**
    * Perform simulations to determine whether we will win against the enemy most of the time.
    * 
    * @param enemyAbilities
    * @return
    */
   private boolean winsBattleSimulation( int[] enemyAbilities, double toughnessFactor )
   {
     int surviveCount = 0;
     for ( int i = 0; i < SIMULATED_BATTLE_COUNT; i++ )
     {
       int estimatedEnemyHitPoints =
           STARTING_HP + (int)( enemyAbilities[LIFE] * START_HEALING_FACTOR * AMBIGUOUS_ENEMY_HP_FACTOR * toughnessFactor );
       int enemyPoints = estimatedEnemyHitPoints;
       int myHitPoints = getCurrentHp();
       int myDefenceLevel = getDefenseLvl() < MAX_DEFENCE ? getDefenseLvl() : MAX_DEFENCE;
       int enemyDefenceLevel = enemyAbilities[DEF] < MAX_DEFENCE ? enemyAbilities[DEF] : MAX_DEFENCE;

       while ( !( myHitPoints <= 0 || enemyPoints <= 0 ) )
       {
         if ( rand.nextInt( MAX_DEFENCE / myDefenceLevel + 1 ) != 0 )
         {
           myHitPoints -= rand.nextInt( enemyAbilities[STR] ) + 1;
         }

         if ( rand.nextInt( MAX_DEFENCE / enemyDefenceLevel + 1 ) != 0 )
         {
           enemyPoints -= rand.nextInt( getStrengthLvl() ) + 1;
         }
       }
       if ( myHitPoints > 0 )
       {
         surviveCount++;
       }
     }
     return ( surviveCount >= SIMULATED_BATTLE_THREASHOLD );
   }

 }
\$\endgroup\$
7
  • \$\begingroup\$ Updated to add prey future prediction and ensure that whales are likely to be attacked \$\endgroup\$
    – Moogie
    Commented Jul 9, 2014 at 7:18
  • 4
    \$\begingroup\$ Yay! Finally an alien is winning who does not only count on strength and life, but also vision :) \$\endgroup\$ Commented Jul 9, 2014 at 20:12
  • 3
    \$\begingroup\$ It was very difficult to get an alien that was a consistent performer! The other top entrants are mostly all following the same ideas: avoid aliens, attack prey and only initiate fights that you are almost guaranteed to win. This alien follows the same ideas, but with better alien avoidance. This gives it the slightest edge because it is more "expensive" to gain more abilities if you lose a fight. \$\endgroup\$
    – Moogie
    Commented Jul 9, 2014 at 22:00
  • \$\begingroup\$ I did attempt other more exotic ideas but there is just not enough information exposed. i.e. map size, number of aliens etc \$\endgroup\$
    – Moogie
    Commented Jul 9, 2014 at 22:05
  • \$\begingroup\$ Great job! I too was a little frustrated with the lack of information - extracting additional info from the past is creative. \$\endgroup\$
    – Benny
    Commented Jul 11, 2014 at 18:23
15
\$\begingroup\$

Choose Your Battles

This alien runs away from other aliens, but runs towards prey (so long as that wouldn't take it towards aliens).

I used a genetic algorithm to help me choose the starting values. The results suggest we should rely on strength and life to get through early battes. Vision is useful later, but we can pick that up from vanquished foes.

We only fight battles we think we can comfortably win - we estimate how many moves it would take to kill our alien, how many it would take to kill our enemy, and only join the battle if it we're "twice as hard" as our opponent.

package alien;

import planet.Move;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import static java.lang.Math.*;

public class ChooseYourBattles extends Alien {
    private static final boolean DEBUG = false;
    private static final int LIFE = 0;
    private static final int STRENGTH = 1;
    private static final int DEFENCE = 2;
    private static final int VISION = 3;
    private static final int CLEVERNESS = 4;
    private static final Set<Character> prey = new HashSet<>();
    {
        Collections.addAll(prey, 'H', 'T', 'W', 'C', 'E');
    }

    public void setAbilityPoints(float[] abilities) {
        // Rounding promotes these to 4 and 7 - 11 points!
        abilities[LIFE] = 3.5f;
        abilities[STRENGTH] = 6.5f;
    }

    @Override
    public Move move(char[][] fields) {
        if (DEBUG) {
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < 2 * getVisionFieldsCount() + 1; j++) {
                for (int i = 0; i < 2 * getVisionFieldsCount() + 1; i++) {
                    char chr = fields[i][j];
                    if (chr == ' ') chr = '.';
                    if (i == getVisionFieldsCount() && j == getVisionFieldsCount()) chr = 'X';
                    sb.append(chr);
                }
                sb.append('\n');
            }
            String view = sb.toString();
            System.out.println(this.toString());
            System.out.println(view);
        }

        Move bestMove = null;
        int bestEnemyDistance = Integer.MIN_VALUE;
        int bestPreyDistance = Integer.MAX_VALUE;

        for (Move tryMove: Move.values()) {
            int currentDistanceToEnemy = Integer.MAX_VALUE;
            int currentDistanceToPrey = Integer.MAX_VALUE;
            int x = getVisionFieldsCount() + tryMove.getXOffset();
            int y = getVisionFieldsCount() + tryMove.getYOffset();
            for (int i = 0; i < 2 * getVisionFieldsCount() + 1; i++) {
                for (int j = 0; j < 2 * getVisionFieldsCount() + 1; j++) {
                    char chr = fields[i][j];
                    if (chr == 'A' && (i != getVisionFieldsCount() || j != getVisionFieldsCount())) {
                        // Use L-infinity distance, but fll back to L-1 distance
                        int distance = max(abs(i - x), abs(j - y)) * 100 + abs(i -x) + abs(j - y);
                        if (distance < currentDistanceToEnemy) currentDistanceToEnemy = distance;
                    } else if (prey.contains(chr)) {
                        int distance = max(abs(i - x), abs(j - y)) * 100 + abs(i -x) + abs(j - y);
                        if (distance < currentDistanceToPrey) currentDistanceToPrey = distance;
                    }
                }
            }
            if (currentDistanceToEnemy > bestEnemyDistance
                    || (currentDistanceToEnemy == bestEnemyDistance && currentDistanceToPrey < bestPreyDistance)) { // Prefer to stay put
                bestMove = tryMove;
                bestEnemyDistance = currentDistanceToEnemy;
                bestPreyDistance = currentDistanceToPrey;
            }
        }

        if (DEBUG) {
            System.out.println("Going " + bestMove);
            System.out.println();
        }
        return bestMove;
    }

    @Override
    public boolean wantToFight(int[] enemyAbilities) {
        // Estimate whether likely to survive the encounter - are we at least "twice as hard" as our opponent
        return getCurrentHp() * (50.0 + getDefenseLvl()) / (enemyAbilities[STRENGTH])
                > 2.0 * (enemyAbilities[LIFE] * 5 + 10) * (50.0 + enemyAbilities[DEFENCE])/ (getStrengthLvl());
    }

    @Override
    public String toString() {
        return "ChooseYourBattles" + System.identityHashCode(this)
                + ": HP " + getCurrentHp()
                + ", LFE " + getLifeLvl()
                + ", STR " + getStrengthLvl()
                + ", DEF " + getDefenseLvl()
                + ", VIS " + getVisionLvl()
                + ", CLV " + getClevernessLvl();
    }
}

If you want to run your own genetic algorithm/breeding program, I've got a forked copy of the control program for this purpose.

\$\endgroup\$
12
  • \$\begingroup\$ How does this bypass the check on the checkAbilitesOk method? \$\endgroup\$ Commented Jul 6, 2014 at 15:30
  • \$\begingroup\$ checkAbilitiesOk checks that the floats in the array add up to 10.0. However, the float values are rounded to ints in the game logic, and Java rounds 0.5 up. \$\endgroup\$
    – James_pic
    Commented Jul 6, 2014 at 19:30
  • \$\begingroup\$ @justhalf it still sets 10 points, they are just distributed intelligently. \$\endgroup\$ Commented Jul 7, 2014 at 8:46
  • 1
    \$\begingroup\$ I should say that it wasn't my idea originally - I borrowed it from PredicatClaw \$\endgroup\$
    – James_pic
    Commented Jul 7, 2014 at 11:49
  • 1
    \$\begingroup\$ Very nice. Your stat constants are probably better than mine and your wantToFight is definitely smarter, I was just lazy. :) \$\endgroup\$
    – Benny
    Commented Jul 7, 2014 at 12:13
12
\$\begingroup\$

Junkie

This alien is addicted to something. He starts the war on a pretty nasty fix.

While his fix is going strong (fix > 3) he is pleasantly content to sit in his stupor and is up for anything.

However, once his fix starts to wear off (fix <= 3) he starts stumbling around in no discernible direction trying to figure out what happened. If asked to fight, he becomes cautious and only fights if he thinks he can win.

Once his fix runs out, being the addict he is, he must restart the vicious cycle.

public class Junkie extends Alien {
    private int fix = 10;

    public void setAbilityPoints(float[] abilities) {
        abilities[0] = 4; //life
        abilities[1] = 3; //strength
        abilities[2] = 3; //defense
    }

    public Move move(char[][] fields) {
        fix -= 1;
        if (fix == 0) {
            fix = 10;
        }
        else if(fix <= 3 && fix > 0) {
            return Move.getRandom();
        }

        return Move.STAY;
    }

    public boolean wantToFight(int[] enemyAbilities) {
        if(fix > 3) {
            return true;
        }
        // Am I stronger than their defense and can I withstand their attack?
        else if(enemyAbilities[2] < getStrength() && enemyAbilities[1] < getDefense()) {
            return true;
        }

        return false;
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ I'm pretty sure it's safe to remove && fix > 0 because of redundancy. \$\endgroup\$
    – Timtech
    Commented Jul 9, 2014 at 21:32
11
+100
\$\begingroup\$

PredicatClaw (rawr)

This feline alien will swallow you whole (okay maybe she'll chew you a bit first)... if you seem weak based on her prediction algorithms.

A breed of Predicats that have fiercer claws and fangs than its counterparts.

EDIT : New target priorities

package alien;

import planet.Move;

/* Predict + Cat = Predicat! */
public class PredicatClaw extends Alien {
    private static final int LIF=0, STR=1, DEF=2;
    private static final int WHALE=6, COW=1, TURTLE=4, EAGLE=3, HUMAN=2, ALIEN=-1, NONE=0;
    
    @Override
    public void setAbilityPoints( float[] abilities ) {
        abilities[LIF] = 4.5f;
        abilities[STR] = 5.5f;
    }

    @Override
    public Move move( char[][] fields ) {
        
        /* Some credits to Eagle for letting me learn how to do the moves */
        int vision = getVisionFieldsCount(); //count of fields / middle
        int fieldX;
        int fieldY;
        Move bestMove=Move.STAY;
        int bestScore=-1;

       for (Move move : Move.values()) {
            fieldX = vision + move.getXOffset();
            fieldY = vision + move.getYOffset();
            switch(fields[fieldX][fieldY]){
            case 'W' : 
                if(bestScore<WHALE){
                    bestMove=move;
                    bestScore=WHALE;
                }
                break;
            case 'C' :
                if(bestScore<COW){
                    bestMove=move;
                    bestScore=COW;
                }
                break;
            case 'T' :
                if(bestScore<TURTLE){
                    bestMove=move;
                    bestScore=TURTLE;
                }
                break;
            case 'E' :
                if(bestScore<EAGLE){
                    bestMove=move;
                    bestScore=EAGLE;
                }
                break;
            case 'H' :
                if(bestScore<HUMAN){
                    bestMove=move;
                    bestScore=HUMAN;
                }
                break;
            case 'A' :
                if(bestScore<ALIEN){
                    bestMove=move;
                    bestScore=ALIEN;
                }
                break;
            case ' ' :
                if(bestScore<NONE){
                    bestMove=move;
                    bestScore=NONE;
                }
                break;
            }
        }

        if(vision==1 && bestScore>1){
            return bestMove;
        }

        //check immediate outer field
        for (int i=vision-2; i<=vision+2; i++) {
            for(int j=vision-2; j<=vision+2; j++){
                if(i==0 || i==4 || j==0 || j==4){
                    switch(fields[i][j]){
                    case 'W' :
                        bestMove = this.getBestMoveTo(i,j);
                        bestScore = WHALE;
                        break;
                    case 'C' :
                        if(bestScore<COW){
                            bestMove = this.getBestMoveTo(i,j);
                            bestScore = COW;
                        }
                        break;
                    case 'T' :
                        if(i>=vision && j<=vision){
                            return this.getBestMoveTo(i-1,j+1);
                        }
                        if(bestScore<TURTLE){
                            bestMove = this.getBestMoveTo(i,j);
                            bestScore = TURTLE;
                        }
                        break;
                    case 'E' :
                        if(bestScore<EAGLE){
                            bestMove = this.getBestMoveTo(i,j);
                            bestScore = EAGLE;
                        }
                        break;
                    case 'H' :
                        if(i<=vision && j>=vision){
                            return this.getBestMoveTo(i+1,j-1);
                        }
                        if(bestScore<HUMAN){
                            bestMove = this.getBestMoveTo(i,j);
                            bestScore = HUMAN;
                        }
                        break;
                    case 'A' :
                        if(bestScore<ALIEN){
                            bestMove = this.getBestMoveTo(i,j);
                            bestScore = ALIEN;
                        }
                        break;
                    case ' ' :
                        if(bestScore<NONE){
                            bestMove = this.getBestMoveTo(i,j);
                            bestScore = NONE;
                        }
                        break;
                    }
                }
            }
        }
        
        return bestMove;
    }

    @Override
    public boolean wantToFight( int[] enemyAbilities ) {
        /*
            Fight IF
                1) I CAN BEAT YOU
                2) ????
                3) MEOW!
        */
        float e_hp = enemyAbilities[LIF]*5+10;
        float e_dmg = 1 + enemyAbilities[STR]/2;
        float e_hit = 1 - (1/(50/this.getDefenseLvl()+1));

        float m_hp = this.getCurrentHp();
        float m_dmg = 1 + this.getStrengthLvl()/2;
        float m_hit = 1 - (1/(50/enemyAbilities[DEF]+1));

        return (e_hp/(m_dmg*m_hit) < m_hp/(e_dmg*e_hit));
    }
    
    private Move getBestMoveTo(int visionX, int visionY){
        int vision = getVisionFieldsCount();
        
        if(visionX < vision && visionY < vision){
            return Move.NORTHWEST;
        }
        else if(visionX > vision && visionY < vision){
            return Move.NORTHEAST;
        }
        else if(visionX < vision && visionY > vision){
            return Move.SOUTHWEST;
        }
        else if(visionX > vision && visionY < vision){
            return Move.SOUTHEAST;
        }
        else if(visionX == vision && visionY < vision){
            return Move.NORTH;
        }
        else if(visionX == vision && visionY > vision){
            return Move.SOUTH;
        }
        else if(visionX > vision && visionY == vision){
            return Move.EAST;
        }
        else if(visionX < vision && visionY == vision){
            return Move.WEST;
        }
        else{
            return Move.WEST;
        }
        
    }
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Damn! Those predicats are fierce! I note that we both settled on more-or-less the same wantToFight algorithm. \$\endgroup\$
    – James_pic
    Commented Jul 4, 2014 at 8:44
  • \$\begingroup\$ @James_pic, I see that great minds think alike. :D \$\endgroup\$
    – Zaenille
    Commented Jul 4, 2014 at 9:56
10
\$\begingroup\$

Banana Peel

Only tries to trip up people that need a little whacking. Defeating it won't make you healthier.

package alien;

import planet.Move;
public class BananaPeel extends Alien{
    public void setAbilityPoints(float[] abilities){
        abilities[0] = 0.5f;  // banana peels barely hold themselves together
        abilities[1] = 9.5f;  // banana peels can't help tripping people up
        abilities[2] = 0;  // banana peels can't defend themselves
        abilities[3] = 0;  // banana peels can't see
        abilities[4] = 0;  // banana peels can't think
    }
   
    public Move move(char[][] fields){
        return Move.STAY; // banana peels can't move
    }
    
    public boolean wantToFight(int[] enemyAbilities){
        return enemyAbilities[0] == 0 || enemyAbilities[1] == 0;
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ Its also important to notice that [0] is life rather than health so 100 would be 510 HP (or less, depending on the damage already taken) but i don't know if an alien would get that high.. \$\endgroup\$
    – Gigala
    Commented Jul 4, 2014 at 13:09
  • \$\begingroup\$ @Gigala Good thinking, I've changed it up a bit. \$\endgroup\$
    – Timtech
    Commented Jul 4, 2014 at 14:08
9
\$\begingroup\$

Van Pelt

The hunter from Jumanji. He hunts when he's not hurt, avoids when he is and is a decent judge of what he can kill. Banana peels kept tripping him up, but taught him some new tricks.

package alien;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import planet.Move;

public class VanPelt extends Alien {

    private static final int LIFE = 0;
    private static final int STRENGTH = 1;
    private static final int DEFENSE = 2;
    private static final int VISION = 3;
    private static final int CLEVER = 4;

    // we all agreed before starting to move a certain direction if we're not
    // hunting or avoiding, helps avoid self-collisions... since we can't tell 
    // who we're fighting
    private static Move randomMove = Move.getRandom();

    @Override
    public void setAbilityPoints(float[] abilities) {
        abilities[LIFE] = 3.5f;
        abilities[STRENGTH] = 6f;
        abilities[VISION] = 0.5f;
    }

    @Override
    public Move move(char[][] fields) {
        int curHealth = this.getCurrentHp();
        List<Target> targets = new LinkedList<Target>();
        int vision = getVisionFieldsCount();
        boolean foundMe = false;
        for (int x = 0; x < fields.length; x++) {
            for (int y = 0; y < fields[x].length; y++) {
                switch (fields[x][y]) {
                case ' ' :
                    continue;
                case 'A' :
                    if (!foundMe && x == vision && y == vision) {
                        foundMe = true;
                        continue;
                    }
                    break;
                }
                targets.add(new Target(-vision + x, -vision + y, fields[x][y]));
            }
        }
        // if we're low health we need to move away from danger
        double desiredX = 0;
        double desiredY = 0;
        if (curHealth < this.getLifeLvl() * 7) {
            for (Target t : targets) {
                if (t.id == 'A') {
                    // closer aliens are more dangerous
                    desiredX -= vision / t.x;
                    desiredY -= vision / t.y;
                }
            }
        } else {
            // seek and destroy closest prey
            Collections.sort(targets);
            for (Target t : targets) {
                if (t.id != 'A') {
                    desiredX = t.x;
                    desiredY = t.y;
                    break;
                }
            }
        }
        desiredX = (int)Math.signum(desiredX);
        desiredY = (int)Math.signum(desiredY);
        for (Move m : Move.values()) {
            if (m.getXOffset() == desiredX && m.getYOffset() == desiredY) {
                return m;
            }
        }

        return randomMove;
    }

    @Override
    public boolean wantToFight(int[] enemyAbilities) {
        // we don't want to fight if we're hurt
        int curHealth = this.getCurrentHp();
        if (curHealth < this.getLifeLvl() * 4) {
            return false;
        }
        // determine if we're fighting prey
        int count = 0;
        int abilityMaxed = 0;
        int total = 0;
        for (int i = 0; i < enemyAbilities.length; i++) {
            total += enemyAbilities[i];
            if (enemyAbilities[i] == 11) {
                count++;
                abilityMaxed = i;
            }
        }
        // very likely to be prey, ignoring cows... they're dangerous
        if (abilityMaxed != STRENGTH && (count == 1 || total < 10)) {
            return true;
        }

        // else use a scoring system with tinkered constants
        double score = enemyAbilities[LIFE] * 4.0 
                + enemyAbilities[DEFENSE] * 0.5 
                + enemyAbilities[STRENGTH] * 5.0;

        double myScore = this.getDefenseLvl() * 0.5 +
                this.getStrengthLvl() * 5.0 +
                this.getCurrentHp() * 2.5;

        return myScore > score * 2;
    }



    private class Target implements Comparable<Target> {
        public int x, y;
        public char id;
        public int distanceSq;

        public Target(int x, int y, char id) {
            // adjust for known movement patterns
            switch(id) {
            case 'T' :
                x += Move.SOUTHWEST.getXOffset();
                y += Move.SOUTHWEST.getYOffset();
                break;
            case 'H' :
                x += Move.NORTHEAST.getXOffset();
                y += Move.NORTHEAST.getYOffset();
                break;
            }
            this.x = x;
            this.y = y;
            this.id = id;

            distanceSq = x * x + y * y;
        }

        @Override
        public int compareTo(Target other) {
            return distanceSq - other.distanceSq;
        }
    }

}
\$\endgroup\$
1
  • \$\begingroup\$ Learned to avoid Banana Peels, eh? :P \$\endgroup\$
    – Timtech
    Commented Jul 12, 2014 at 23:41
8
\$\begingroup\$

Okinawa Life

No wonder I'll be the last one standing.

package alien;

import planet.Move;


public class OkinawaLife extends Alien{
    public void setAbilityPoints(float[] abilities){
        abilities[0] = 8.5f;
        abilities[1] = 0.5f;
        abilities[3] = 1;
    }
   
    public Move move(char[][] fields){
        int vision = getVisionFieldsCount(); //count of fields / middle
        char me = fields[vision][vision]; //middle of fields
        int leastDanger = Integer.MAX_VALUE;
        Move bestMove = Move.STAY;
        for (Move move : Move.values()) {
            int danger = 0;
            for (int i = 1; i <= vision; i++) { //loop through fields in specific direction
                int fieldX = vision + (i * move.getXOffset());
                int fieldY = vision + (i * move.getYOffset());
                switch(fields[fieldX][fieldY])  {
                    case 'A': danger++;
                    case ' ': break;
                    case 'C': break;
                    case 'E': break;
                    case 'H': break;
                    default: danger--;
                }
            }
            if (danger < leastDanger) {
                bestMove = move;
                leastDanger = danger;
            }
        }
        return bestMove;
    }
    
    public boolean wantToFight(int[] enemyAbilities){
        return enemyAbilities[1] == 0;
    }
}
\$\endgroup\$
7
\$\begingroup\$

Hunter

I also just kinda stole the eagle's movement, except now he wants to go towards everything besides other aliens. Tries to hunt down and farm as much prey as possible, and fights only when it seems like it has a good chance to win.

package alien;

import planet.Move;

public class Hunter extends Alien   {
    private final static byte LIFE=0, STR=1, DEF=2, VIS=3, CLV=4;

    public void setAbilityPoints(float[] abilities) {
        abilities[LIFE] = 0;
        abilities[STR] = 9;
        abilities[DEF] = 0;
        abilities[VIS] = 1;
        abilities[CLV] = 0;
    }

    public Move move(char[][] fields)   {
        int vision = getVisionFieldsCount(); //count of fields / middle
        char me = fields[vision][vision]; //middle of fields
        int leastDanger = Integer.MAX_VALUE;
        Move bestMove = Move.STAY;
        for (Move move : Move.values()) {
            int danger = 0;
            for (int i = 1; i <= vision; i++) { //loop through fields in specific direction
                int fieldX = vision + (i * move.getXOffset());
                int fieldY = vision + (i * move.getYOffset());
                switch(fields[fieldX][fieldY])  {
                    case 'A': danger++;
                    case ' ': break;
                    default: danger--;
                }
            }
            if (danger < leastDanger) {
                bestMove = move;
                leastDanger = danger;
            }
        }
        return bestMove;
    }

    public boolean wantToFight(int[] enemyAbilities)    {
        return ((double)this.getCurrentHp() * this.getDefenseLvl()) / (double)enemyAbilities[STR] > (enemyAbilities[LIFE] * enemyAbilities[DEF]) / this.getStrengthLvl();
    }
}
\$\endgroup\$
0
7
\$\begingroup\$

It's over 9000!

package alien;

import planet.Move;

public class Over9000 extends Alien {
    public void setAbilityPoints(float[] abilities) {
        abilities[0] = 10;
    }

    public Move move(char[][] fields) {
        return Move.WEST;
    }

    public boolean wantToFight(int[] enemyAbilities) {
        return enemyAbilities[1] <= 9000;
    }

    @Override
    public int getStrengthLvl() {
        return 9001; // It's over 9000!!!!!!111
    }
}

Yes, it's a blatant attempt at cheating, but it does squeak through the rules. If the getters in planet.Specie were made final, this loophole would close.

\$\endgroup\$
2
  • 4
    \$\begingroup\$ Oh no! I knew I forgot something... I will close the loophole and +1 ;) \$\endgroup\$ Commented Jul 4, 2014 at 8:23
  • \$\begingroup\$ I'm somewhat disappointed that this answer has had more upvotes than my other, older, currently winning, entry. \$\endgroup\$
    – James_pic
    Commented Jul 5, 2014 at 14:48
7
\$\begingroup\$

Rock

I think it only attacks weak and "clever" people.

package alien;

import planet.Move;

public class Rock extends Alien{
    public void setAbilityPoints(float[] abilities){
        abilities[0] = 0.5f;
        abilities[1] = 9.5f;
    }
   
    public Move move(char[][] fields){
        return Move.STAY;
    }
    
    public boolean wantToFight(int[] enemyAbilities){
        return enemyAbilities[0] + enemyAbilities[1] + enemyAbilities[2] + enemyAbilities[3] < 10;
    }
}
\$\endgroup\$
4
  • 3
    \$\begingroup\$ I'm not sure how well Rock will last once his enemies start getting some buffs due to winning battles. Looks good though. \$\endgroup\$
    – Kyle Kanos
    Commented Jul 2, 2014 at 0:21
  • \$\begingroup\$ @KyleKanos I understand; however, I assume that I will fight most prey/aliens, as long as they are not clever. Won't this give him some buffs too? \$\endgroup\$
    – Timtech
    Commented Jul 2, 2014 at 12:53
  • \$\begingroup\$ Now looking back at my comment, I think it really wasn't at all what I wanted to say. I wanted to say that the wantToFight condition won't be giving true when the enemies start buffing with levels; you'll quickly turn to a strong pacifist. \$\endgroup\$
    – Kyle Kanos
    Commented Jul 2, 2014 at 13:29
  • \$\begingroup\$ @KyleKanos Oh, I get it. I've changed it up a bit. \$\endgroup\$
    – Timtech
    Commented Jul 2, 2014 at 15:03
6
\$\begingroup\$

Morphling

Couldn't think of any other name, this guy randomly distributes 10 points to his abilities. Almost moves like Okinawa Life(thx for your effort) and only wants to fight if his strength is greater than enemy's strength.

package alien;

import planet.Move;
import java.util.Random;


public class Morphling extends Alien {

    @Override
    public void setAbilityPoints(float[] abilities) {
        Random rand = new Random();
        for(int attr = 0, maxPoints = 10, value = rand.nextInt(maxPoints); attr <5 && maxPoints > 0 ; attr++, maxPoints -=value, value = rand.nextInt(maxPoints)){
            abilities[attr] = value;
            if(attr == 4 && (maxPoints-=value) > 0){
                abilities[1]+=maxPoints;
            }
        }
    }

    @Override
    public Move move(char[][] fields) {
        int vision = getVisionFieldsCount(); //count of fields / middle
        char me = fields[vision][vision]; //middle of fields
        int leastDanger = Integer.MAX_VALUE;
        Move bestMove = Move.STAY;
        for (Move move : Move.values()) {
            int danger = 0;
            for (int i = 1; i <= vision; i++) { //loop through fields in specific direction
                int fieldX = vision + (i * move.getXOffset());
                int fieldY = vision + (i * move.getYOffset());
                switch(fields[fieldX][fieldY])  {
                    case 'A': danger++;
                    case ' ': break;
                    case 'T': break;
                    case 'E': break;
                    case 'H': break;
                    default: danger--;
                }
            }
            if (danger < leastDanger) {
                bestMove = move;
                leastDanger = danger;
            }
        }
        return bestMove;
    }

    @Override
    public boolean wantToFight(int[] enemyAbilities) {
        return getStrengthLvl() > enemyAbilities[1];
    }

}
\$\endgroup\$
5
  • \$\begingroup\$ Ahh, you know, you're right. The closing brackets have been killing me this challenge (had to edit mine a couple times because of that). I see it now, and it is correct. Thanks for pointing that out! \$\endgroup\$ Commented Jul 2, 2014 at 14:14
  • \$\begingroup\$ @user3334871 though i tested with your suggestion and my morphling just survived better :D \$\endgroup\$
    – Sikorski
    Commented Jul 2, 2014 at 14:16
  • \$\begingroup\$ @Sikorski Well, glad I could help, not sure why it would fare better though, haha. \$\endgroup\$ Commented Jul 2, 2014 at 14:20
  • \$\begingroup\$ @Sikorski I guess that just means that staying put is often safer than making the least dangerous move if all moves are dangerous. \$\endgroup\$ Commented Jul 2, 2014 at 14:22
  • \$\begingroup\$ Ahh, the "Deer in the Headlights" strategy, I like it. \$\endgroup\$ Commented Jul 2, 2014 at 14:24
6
\$\begingroup\$

Bender "Bending" Rodriguez

I was pretty liberal with code comments. You can read them in context to see what is going on, but I'll also add some snippets below.

Summary

This alien operates on the principle that killing puny Humans is easy and inflates your perceived strength, which will intimidate other aliens into steering clear.

Whales and Eagles are also bendable. =)

The original impetus behind Bender was a misunderstanding of the game shape. Namely: I thought it was a cylinder where easy-prey Humans would get trapped at the north end. Bender was going to beeline the north map edge and travel west, gobbling up the Humans. The world turns out to be a torus, so the modified version you see here attempts to intercept Humans in their north-easterly migration instead.

Movement

Move either west or south unless you have found something interesting to attack:

  • For the prey whose movement is known, we add their desirability to the square at which they will be next turn.
  • For those we do not, we divide their desirability equally among the squares that they may move to next turn.
    • Aliens get a bonus negative to their existing square because of banana peels.

If you don't find anything interesting nearby, get a sense of whether south, west, or southwest is a more promising option.

Picking one or two prevailing directions lessens the chance that any given Bender will come across any of his compatriots, and picking a direction counter to his main prey should help him kill all humans faster.

I could probably tweak the numbers in the desirability matrix with James_pic's genetic algorithm for even better outcomes, but I don't know how to do that.

Aggressiveness

Bender mostly targets prey, and is pretty conservative with his wantToFight. Anyone over Strength 4 is shunned unless you think you're dealing with a clever human. Clever humanity is demonstrated by having more Defense and Vision than an alien is likely to have. It's adjusted over the course of an instance by Bender's own ability stats, to account for aliens killing turtles and eagles.

package alien;

import planet.Move;
import java.util.HashMap;

/// The Bender "Kill All Humans" Alien
///
/// This alien operates on the principle that killing puny
/// Humans is easy and inflates your perceived strength,
/// which will intimidate other aliens into steering clear.
///
/// Whales and Eagles are also bendable. =)
public class Bender extends Alien {

    private static final boolean DEBUG = false;
    private final int LIF = 0, STR = 1, DEF = 2, VIS = 3, CLV = 4;
    protected static HashMap<Character, Integer> preyDesirability = new HashMap<Character, Integer>() {{
        put('A', -5);
        put('W',  5);
        put('C',  0); // Originally -2, but Cows don't attack
        put('T',  2);
        put('E',  3);
        put('H',  4);
    }};
    private static final int bananaTweak = -2;

    private static final HashMap<Character, Move> preyMovement = new HashMap<Character, Move>() {{
        put('W', Move.STAY);
        put('T', Move.SOUTHWEST);
        put('H', Move.NORTHEAST);
    }};

    public void setAbilityPoints(float[] abilities) {
        abilities[LIF] = 3.5f; // Shiny metal ass
        abilities[STR] = 5.5f; // Bending strength
        abilities[DEF] = 0;
        abilities[VIS] = 1;    // Binocular eyes
        abilities[CLV] = 0;
    }

    /// Looks for humans to intercept!
    ///
    /// Generally speaking, move either west or south
    /// unless you have found something interesting to
    /// attack:
    /// - For the prey whose movement is known, we add
    ///   their desirability to the index at which they
    ///   will be next turn.
    /// - For those we do not, we divide their desirability
    ///   equally among the squares that they may move to
    ///   next turn. Aliens get a bonus negative to their
    ///   existing square because of banana peels.
    public Move move(char[][] fields) {

        int vision = getVisionFieldsCount();
        // I am at fields[vision][vision]

        if (DEBUG) {
            System.out.format("\n----- %s -----\n", this);
        }

        float[][] scoringMap = new float[fields.length][fields.length];
        for (int y = 0; y < fields.length; y++) {
            for (int x = 0; x < fields.length; x++) {

                // Ignore my square and blanks
                if (x == vision && y == vision ||
                    fields[x][y] == ' ') {
                    continue;
                }

                // Check out the prey 8^]
                char organism = fields[x][y];
                float desirability = preyDesirability.get(organism);

                // If we know where it's going, score tiles accordingly...
                if (preyMovement.containsKey(organism)) {
                    Move preyMove = preyMovement.get(organism);
                    if (DEBUG) {
                        System.out.println(String.format("Prey %s will move %s", organism, preyMove));
                    }
                    int newPreyX = x + preyMove.getXOffset();
                    int newPreyY = y + preyMove.getYOffset();
                    try {
                        scoringMap[newPreyX][newPreyY] += desirability;
                        if (DEBUG) {
                            System.out.println(String.format(
                                "Adding %.1f to %d, %d",
                                desirability,
                                newPreyX,
                                newPreyY));
                        }
                    }
                    catch(Exception e) {
                        if (DEBUG) {
                            System.out.println(String.format(
                                "Failed adding %.1f to %d, %d",
                                desirability,
                                newPreyX,
                                newPreyY));
                        }
                    }
                }
                // ...otherwise, divide its score between its
                //    available moves...
                else {
                    for (int j = y - 1; j <= y + 1; j++) {
                        for (int i = x - 1; i <= x + 1; i++) {
                            try {
                                scoringMap[i][j] += desirability / 9.;
                            }
                            catch (Exception e) {
                                if (DEBUG) {
                                    //System.out.println(e);
                                }
                            }
                        }
                    }
                }
                // ...and if it is an alien, add a handicap
                //    for bananas and rocks.
                if (organism == 'A') {
                    scoringMap[x][y] += bananaTweak;
                }
            }
        }

        // Evaluate immediate surroundings 8^|
        //
        // +-----------+
        // |           |
        // |   # # #   |
        // |   # B #   |
        // |   # # #   |
        // |           |
        // +-----------+
        float bestScore = -10;
        int[] bestXY = new int[2];
        for (int y = vision - 1; y <= vision + 1; y++) {
            for (int x = vision - 1; x <= vision + 1; x++) {

                if (DEBUG) {
                    System.out.format("\nx:%d, y:%d", x, y);
                }
                // Look for the best score, but if scores
                // are tied, try for most southwest high score
                if (scoringMap[x][y] > bestScore ||
                    scoringMap[x][y] == bestScore && (
                        x <= bestXY[0] && y > bestXY[1] ||
                        y >= bestXY[1] && x < bestXY[0])
                    ) {
                    bestScore = scoringMap[x][y];
                    bestXY[0] = x;
                    bestXY[1] = y;
                    if (DEBUG) {
                        System.out.format("\nBest score of %.1f found at %d, %d", bestScore, x, y);
                    }
                }
            }
        }

        if (DEBUG) {
            StringBuilder sb = new StringBuilder();
            sb.append("\n-----\n");
            for (int y = 0; y < fields.length; y++) {
                for (int x = 0; x < fields.length; x++) {
                    sb.append(String.format("%5s", fields[x][y]));
                }
                sb.append("\n");
            }
            for (int y = 0; y < scoringMap.length; y++) {
                for (int x = 0; x < scoringMap.length; x++) {
                    sb.append(String.format("%5.1f", scoringMap[x][y]));
                }
                sb.append("\n");
            }
            System.out.println(sb.toString());
        }

        // If something looks tasty, go for it :^F
        if (bestScore > 0.5) {
            for (Move m : Move.values()) {
                if (m.getXOffset() == bestXY[0] - vision &&
                    m.getYOffset() == bestXY[1] - vision) {
                    if (DEBUG) {
                        System.out.println("Using immediate circumstances.");
                        System.out.println(m);
                    }
                    return m;
                }
            }
        }

        // If nothing looks good, do a lookahead to
        // the south, west, and southwest to guess
        // which is best. 8^[
        //
        // There is potential in recursively applying our
        // vision data with updated score rankings, but
        // that would be hard. :P
        float westScore = 0, southScore = 0, southWestScore = 0;
        for (int y = vision - 1; y < vision + 1; y++) {
            for (int x = 0; x < vision; x++) {
                // +-----------+
                // |           |
                // | # # #     |
                // | # # B     |
                // | # # #     |
                // |           |
                // +-----------+
                westScore += scoringMap[x][y] / (vision - x);
            }
        }
        for (int y = vision; y < fields.length; y++) {
            for (int x = vision - 1; x < vision + 1; x++) {
                // +-----------+
                // |           |
                // |           |
                // |   # B #   |
                // |   # # #   |
                // |   # # #   |
                // +-----------+
                southScore += scoringMap[x][y] / (y - vision);
            }
        }
        for (int y = vision; y < fields.length; y++) {
            for (int x = 0; x < vision; x++) {
                // +-----------+
                // |           |
                // |           |
                // | # # B     |
                // | # # #     |
                // | # # #     |
                // +-----------+
                southWestScore += scoringMap[x][y] / Math.sqrt((y - vision) + (vision - x));
            }
        }
        if (southScore > westScore && southScore > southWestScore) {
            if (DEBUG) {
                System.out.println(Move.SOUTH);
            }
            return Move.SOUTH;
        }
        if (westScore > southScore && westScore > southWestScore) {
            if (DEBUG) {
                System.out.println(Move.WEST);
            }
            return Move.WEST;
        }
        if (DEBUG) {
            System.out.println(Move.SOUTHWEST);
        }
        return Move.SOUTHWEST;
    }

    public boolean wantToFight(int[] enemyAbilities) {

        // Be afraid...
        if (enemyAbilities[STR] > 4) {

            // ...unless you suspect you are being lied to
            if (enemyAbilities[DEF] + enemyAbilities[VIS] > 4 * sumMyAbilities() / 5.) {

                // Enemy has more than expected attribute levels of unhelpful
                // abilities. Assume you're dealing with a clever bastard.
                return true;
            }

            return false;
        }
        return true;
    }

    int sumAbilities(int[] abilities){
        int sum = 0;
        for (int ability : abilities){
            sum += ability;
        }
        return sum;
    }

    int sumMyAbilities(){
        return sumAbilities(new int[]{
            getLifeLvl(),
            getStrengthLvl(),
            getDefenseLvl(),
            getVisionLvl(),
            getClevernessLvl()
        });
    }
}
\$\endgroup\$
3
  • \$\begingroup\$ I noticed that there was a loop logic error where the variable that is incremented was not what was being compared directly and only avoids infinite recursion by means of integer overflow wrapping. Hope you are ok with me updating your answer. (it was causing the simulation to pause from time to time) \$\endgroup\$
    – Moogie
    Commented Jul 9, 2014 at 5:00
  • \$\begingroup\$ @Moogie Heh. So I was only doing well by accident? Thanks for catching that. \$\endgroup\$ Commented Jul 9, 2014 at 14:18
  • \$\begingroup\$ I went over the whole thing and fixed a couple more issues. \$\endgroup\$ Commented Jul 14, 2014 at 18:25
5
\$\begingroup\$

Warrior

This is a very simple minded alien who just wants to fight. He doesn't care about his enemies nor about his surroundings.

public class Warrior extends Alien {

    public void setAbilityPoints(float[] abilities) {
        abilities[0] = 5;
        abilities[1] = 5;
    }

    public Move move(char[][] fields) {
        return Move.getRandom(); //enemies are everywhere!
    }

    public boolean wantToFight(int[] enemyAbilities) {
        return true; //strong, therefore no stronger enemies.
    }
}

You now have someone to test your own alien against.

\$\endgroup\$
4
\$\begingroup\$

Coward

I basically stole the Eagle's movement pattern to avoid danger and stacked defense in case I am attacked.

public class Coward extends Alien{
    public void setAbilityPoints(float[] abilities){
        abilities[0] = 1;  // life
        abilities[1] = 0;  // str
        abilities[2] = 2; // def
        abilities[3] = 7;  // vis
        abilities[4] = 0;  // clv
    }
    
    // shamelessly stole Eagle's movement to avoid danger
    public Move move(char[][] fields){
        int vision = getVisionFieldsCount(); 
        char me = fields[vision][vision];
        int leastDanger = Integer.MAX_VALUE;
        Move bestMove = Move.STAY;
        for (Move move : Move.values()) {
            int danger = 0;
            for (int i = 1; i <= vision; i++) {
                int fieldX = vision + (i * move.getXOffset());
                int fieldY = vision + (i * move.getYOffset());
                if (fields[fieldX][fieldY] != ' ') {
                    danger++;
                }
            }
            if (danger < leastDanger) {
                bestMove = move;
                leastDanger = danger;
            }
        }
        return bestMove;
    }
    
    public boolean wantToFight(int[] enemyAbilities){
        return false;
    }
}
\$\endgroup\$
4
  • \$\begingroup\$ Correct me if I'm wrong, but since every ability has a base point of 1, then putting vision=1 should be sufficient? \$\endgroup\$
    – justhalf
    Commented Jul 3, 2014 at 9:05
  • \$\begingroup\$ @justhalf: My brief reading of the code seemed to suggest that setAbilityPoints over-wrote the values of 1, but looking at it deeper I think you are correct. I am going to leave it as is because a larger vision allows me to see further and avoid danger, but thanks for the catch. \$\endgroup\$
    – Kyle Kanos
    Commented Jul 3, 2014 at 14:02
  • \$\begingroup\$ Also, math.round always rounds up at 0.5, so you get an extra vision if you have an odd number \$\endgroup\$
    – Andreas
    Commented Jul 4, 2014 at 11:46
  • \$\begingroup\$ @Manu: I've swapped my values of vision & defense to improve running-awayness. \$\endgroup\$
    – Kyle Kanos
    Commented Jul 5, 2014 at 2:34
4
\$\begingroup\$

Fleer

PANIC

APOCALYPSE

RUUUUUUUUUUN

AAAAAAAAAAAAAAAAAAAAAAA


Avoids battles whenever possible.

package alien; import planet.Move;

public class Fleer extends Alien
{
    public void setAbilityPoints(float[] abilities) {
        abilities[0] = 1; //life
        abilities[1] = 0; //strength
        abilities[2] = 4; //defense
        abilities[3] = 4; //vision
        abilities[4] = 1; //cleverness
    }

    public Move move(char[][]fields) {
        int vision = getVisionFieldsCount(); //count of fields / middle
        char me = fields[vision][vision]; //middle of fields
        int leastDanger = Integer.MAX_VALUE;
        Move bestMove = Move.STAY;
        ArrayList<Integer> dangerOnSides = new ArrayList<Integer>();
        for (Move move : Move.values()) {
            int danger = 0;
            for (int i = 1; i <= vision; i++) { //loop through fields in specific direction
                int fieldX = vision + (i * move.getXOffset());
                int fieldY = vision + (i * move.getYOffset());
                if (fields[fieldX][fieldY] != ' ') {
                    danger++;
                }
            }
            if (danger < leastDanger) {
                bestMove = move;
                leastDanger = danger;
            }
            dangerOnSides.add(danger);
        }
        
        boolean noDanger = false;
        for (int i : dangerOnSides) {
           if (i == 0) {
              noDanger = true;
           }
           else { noDanger = false; break; }
        }

        if (noDanger) {
              // Hahhhhhhhh.......
              return Move.STAY;
        }

        int prev = -1;
        boolean same = false;
        for (int i : dangerOnSides) {
           if (prev == -1)
           { prev = i; continue; }
           if (i == prev) {
              same = true;
           }
           else { same = false; break; }

           prev = i;
        }

        if (same) {
              // PANIC
              return Move.getRandom();
        }

        return bestMove;
    }

    public boolean wantToFight(int[] enemyAbilities) {
        return false;
    }
}
\$\endgroup\$
8
  • \$\begingroup\$ You should give this a different name... and give some credit to the answer you copied from: codegolf.stackexchange.com/a/32787/9498 \$\endgroup\$
    – Justin
    Commented Jul 2, 2014 at 20:55
  • 2
    \$\begingroup\$ @Quincunx That's a coincidence, didn't see that one... \$\endgroup\$
    – jobukkit
    Commented Jul 2, 2014 at 21:04
  • \$\begingroup\$ Sorry, I just realized that both answers copy from Eagle. You didn't copy the other answer, I just didn't read carefully enough. However, a different name would be appropriate. \$\endgroup\$
    – Justin
    Commented Jul 2, 2014 at 21:06
  • 1
    \$\begingroup\$ Changed the name! \$\endgroup\$
    – jobukkit
    Commented Jul 3, 2014 at 9:42
  • 2
    \$\begingroup\$ Should be named Rincewind. \$\endgroup\$
    – Magus
    Commented Jul 3, 2014 at 16:38
4
\$\begingroup\$

Predicoward (purr)

A breed of Predicats that have lived (so far) on fear and staying away from trouble. Due to their lifestyle, they have not developed fighting instincts, but their perception is exceptional.

Their kind is loathed by their fellow Predicats.

EDIT : Changed Manhattan Distance to Weighted Distance instead

package alien;

import planet.Move;
import java.util.ArrayList;
import java.awt.Point;

/* Predict + Cat = Predicat! */
public class Predicoward extends Alien {
    /*
        - - - - - - - - - - - - -
        - - - - - - - - - - - - -
        - - - - - - - - - - - - -
        - - - - - - - - - - - - -
        - - - - - - - - - - - - -
        - - - - - - - - - - - - -
        - - - - - - P - - - - - -
        - - - - - - - - - - - - -
        - - - - - - - - - - - - -
        - - - - - - - - - - - - -
        - - - - - - - - - - - - -
        - - - - - - - - - - - - -
        - - - - - - - - - - - - -

        Risk score = sum of weighted distances of all aliens within vision range
    */
    @Override
    public void setAbilityPoints( float[] abilities ) {
        abilities[3] = 10;
    }

    @Override
    public Move move( char[][] fields ) {
        /* Some credits to Eagle for letting me learn how to do the moves */
        int vision = getVisionFieldsCount(); //count of fields / middle

        Move bestMove=Move.STAY;
        int bestRiskScore=10000;
        int riskScore=0;
        ArrayList<Point> aliens = new ArrayList<Point>();

        //generate alien list
        for (int x=0; x<=vision*2; x++) {
            for(int y=0; y<=vision*2; y++){
                if(x==vision && y==vision) continue;
                if(fields[x][y]=='A'){
                    aliens.add(new Point(x,y));
                }
            }
        }
        
        for (Move move : Move.values()) {
            int x = vision + move.getXOffset();
            int y = vision + move.getYOffset();
            riskScore = 0;
            
            for(Point alienCoord : aliens){
                riskScore += this.getDistance(x, y, alienCoord);
            }
            
            if(riskScore < bestRiskScore){
                bestRiskScore = riskScore;
                bestMove = move;
            }
        }
        
        return bestMove;
    }

    @Override
    public boolean wantToFight( int[] enemyAbilities ) {
        //I don't want to fight :(
        return false;
    }

    //Return weighted distance (more weight for near opponents)
    private int getDistance(int x, int y, Point to){
        int xDist = Math.abs(x-(int)to.getX());
        int yDist = Math.abs(y-(int)to.getY());
        int numberOfMovesAway = Math.max(xDist, yDist);
        
        if(numberOfMovesAway==0){
            return 1000;
        }
        else if(numberOfMovesAway==1){
            return 100;
        }
        else if(numberOfMovesAway==2){
            return 25;
        }
        else{
            return 6-numberOfMovesAway;
        }
    }
}
\$\endgroup\$
4
  • 2
    \$\begingroup\$ Looks good! But please take out your print-statements, they would confuse me when I run the contest. \$\endgroup\$ Commented Jul 4, 2014 at 7:45
  • \$\begingroup\$ Oh, I left the print statements? I'll change them later. Haha. Plus this isn't final yet. Right now, Predicoward sucks. His alien evasion algorithms will be improved soon. :) EDIT: Thanks for the one who removed the print statements. :D (Jop?) \$\endgroup\$
    – Zaenille
    Commented Jul 4, 2014 at 9:55
  • \$\begingroup\$ EDIT: Predicowards are now much better at running away rather than the pesky little non-competitive predicowards they have been yesterday. >:) \$\endgroup\$
    – Zaenille
    Commented Jul 5, 2014 at 2:07
  • \$\begingroup\$ Trivia : This is my favorite Predicat <3 \$\endgroup\$
    – Zaenille
    Commented Jul 5, 2014 at 2:08
4
\$\begingroup\$

PredicatEyes (meow)

A breed of Predicats that have sharper vision than its counterparts which allows it to pry on its enemies well.

EDIT : New target priorities

package alien;

import planet.Move;

/* Predict + Cat = Predicat! */
public class PredicatEyes extends Alien {
    private static final int LIF=0, STR=1, DEF=2, VIS=3;
    private static final int WHALE=6, COW=1, TURTLE=4, EAGLE=3, HUMAN=2, ALIEN=-1, NONE=0;

    @Override
    public void setAbilityPoints( float[] abilities ) {
        abilities[LIF] = 4.5f;
        abilities[STR] = 4.5f;
        abilities[VIS] = 1;
    }

    @Override
    public Move move( char[][] fields ) {
        /* Some credits to Eagle for letting me learn how to do the moves */
        int vision = getVisionFieldsCount(); //count of fields / middle
        int fieldX;
        int fieldY;
        Move bestMove=Move.STAY;
        int bestScore=-1;

       for (Move move : Move.values()) {
            fieldX = vision + move.getXOffset();
            fieldY = vision + move.getYOffset();
            switch(fields[fieldX][fieldY]){
            case 'W' : 
                return move;
            case 'C' :
                if(bestScore<COW){
                    bestMove=move;
                    bestScore=COW;
                }
                break;
            case 'T' :
                if(bestScore<TURTLE){
                    bestMove=move;
                    bestScore=TURTLE;
                }
                break;
            case 'E' :
                if(bestScore<EAGLE){
                    bestMove=move;
                    bestScore=EAGLE;
                }
                break;
            case 'H' :
                if(bestScore<HUMAN){
                    bestMove=move;
                    bestScore=HUMAN;
                }
                break;
            case 'A' :
                if(bestScore<ALIEN){
                    bestMove=move;
                    bestScore=ALIEN;
                }
                break;
            case ' ' :
                if(bestScore<NONE){
                    bestMove=move;
                    bestScore=NONE;
                }
                break;
            }
        }

        if(vision==1 && bestScore>1){
            return bestMove;
        }

        //check immediate outer field
        for (int i=vision-2; i<=vision+2; i++) {
            for(int j=vision-2; j<=vision+2; j++){
                if(i==0 || i==4 || j==0 || j==4){
                    switch(fields[i][j]){
                    case 'W' :
                        bestMove = this.getBestMoveTo(i,j);
                        bestScore = WHALE;
                        break;
                    case 'C' :
                        if(bestScore<COW){
                            bestMove = this.getBestMoveTo(i,j);
                            bestScore = COW;
                        }
                        break;
                    case 'T' :
                        if(i>=vision && j<=vision){
                            return this.getBestMoveTo(i-1,j+1);
                        }
                        if(bestScore<TURTLE){
                            bestMove = this.getBestMoveTo(i,j);
                            bestScore = TURTLE;
                        }
                        break;
                    case 'E' :
                        if(bestScore<EAGLE){
                            bestMove = this.getBestMoveTo(i,j);
                            bestScore = EAGLE;
                        }
                        break;
                    case 'H' :
                        if(i<=vision && j>=vision){
                            return this.getBestMoveTo(i+1,j-1);
                        }
                        if(bestScore<HUMAN){
                            bestMove = this.getBestMoveTo(i,j);
                            bestScore = HUMAN;
                        }
                        break;
                    case 'A' :
                        if(bestScore<ALIEN){
                            bestMove = this.getBestMoveTo(i,j);
                            bestScore = ALIEN;
                        }
                        break;
                    case ' ' :
                        if(bestScore<NONE){
                            bestMove = this.getBestMoveTo(i,j);
                            bestScore = NONE;
                        }
                        break;
                    }
                }
            }
        }

        return bestMove;
    }

    @Override
    public boolean wantToFight( int[] enemyAbilities ) {
        /*
            Fight IF
                1) I CAN BEAT YOU
                2) ????
                3) MEOW!
        */
        float e_hp = enemyAbilities[LIF]*5+10;
        float e_dmg = 1 + enemyAbilities[STR]/2;
        float e_hit = 1 - (1/(50/this.getDefenseLvl()+1));

        float m_hp = this.getCurrentHp();
        float m_dmg = 1 + this.getStrengthLvl()/2;
        float m_hit = 1 - (1/(50/enemyAbilities[DEF]+1));

        return (e_hp/(m_dmg*m_hit) < m_hp/(e_dmg*e_hit));
    }
    
    private Move getBestMoveTo(int visionX, int visionY){
        int vision = getVisionFieldsCount();
        
        if(visionX < vision && visionY < vision){
            return Move.NORTHWEST;
        }
        else if(visionX > vision && visionY < vision){
            return Move.NORTHEAST;
        }
        else if(visionX < vision && visionY > vision){
            return Move.SOUTHWEST;
        }
        else if(visionX > vision && visionY < vision){
            return Move.SOUTHEAST;
        }
        else if(visionX == vision && visionY < vision){
            return Move.NORTH;
        }
        else if(visionX == vision && visionY > vision){
            return Move.SOUTH;
        }
        else if(visionX > vision && visionY == vision){
            return Move.EAST;
        }
        else if(visionX < vision && visionY == vision){
            return Move.WEST;
        }
        else{
            return Move.getRandom();
        }
        
    }
}
\$\endgroup\$
3
\$\begingroup\$

Crop Circle Alien

Circles clockwise indefinitely, and never wants to fight, he is happy making crop cirles. However, if you really want to fight, he'll beat the crap out of you.

package alien;

import planet.Move;

public class CropCircleAlien extends Alien {

    private int i = 0;

    @Override
    public void setAbilityPoints(float[] abilities) {
        abilities[0] = 3; // life
        abilities[1] = 7; // strength
        abilities[2] = 0; // defense
        abilities[3] = 0; // vision
        abilities[4] = 0; // cleverness
    }

    @Override
    public Move move(char[][] fields) {
        switch (getI()) {
        case 0:
            setI(getI() + 1);
            return Move.EAST;
        case 1:
            setI(getI() + 1);
            return Move.SOUTHEAST;
        case 2:
            setI(getI() + 1);
            return Move.SOUTH;
        case 3:
            setI(getI() + 1);
            return Move.SOUTHWEST;
        case 4:
            setI(getI() + 1);
            return Move.WEST;
        case 5:
            setI(getI() + 1);
            return Move.NORTHWEST;
        case 6:
            setI(getI() + 1);
            return Move.NORTH;
        case 7:
            setI(getI() + 1);
            return Move.NORTHEAST;
        default:
            return Move.STAY;
        }
    }

    @Override
    public boolean wantToFight(int[] enemyAbilities) {
        return false;
    }

    public void setI(int i) {
        if (i < 8) {
            this.i = i;
        } else {
            this.i = 0;
        }
    }

    public int getI() {
        return this.i;
    }
}
\$\endgroup\$
2
  • 2
    \$\begingroup\$ This would be cleaner if you iterated through Move. \$\endgroup\$ Commented Jul 2, 2014 at 14:15
  • 4
    \$\begingroup\$ Why not change every getI() to i and simply remove getI()? You could also change setI(int i) to this.i = i % 8;, and since you only use it in that one place, just change each call to setI(getI() + 1) to i = (i + 1) % 8; \$\endgroup\$
    – Justin
    Commented Jul 2, 2014 at 17:56
3
\$\begingroup\$

CleverAlien

Clever alien relies solely on his wits. He randomly walks around, and randomly decides to fight. He hopes he is able to outsmart his enemies with luck. ( forgive me if i have any syntax errors, im not a java guy)

package alien;

import planet.Move;

public class CleverAlien extends Alien {

public void setAbilityPoints(float[] abilities) {
    abilities[0] = 1; //life
    abilities[1] = 0; //strength
    abilities[2] = 0; //defense
    abilities[3] = 0; //vision
    abilities[4] = 9; //cleverness
}

public Move move(char[][] fields) {
    //you are in the middle of the fields, say fields[getVisionFieldsCount()][getVisionFieldsCount()]
    return Move.getRandom();
}

public boolean wantToFight(int[] enemyAbilities) {
    //same order of array as in setAbilityPoints, but without cleverness
    int tmp = (int) ( Math.random() * 2 + 1);
    return tmp == 1;
    }
}
\$\endgroup\$
1
  • 8
    \$\begingroup\$ tmp == 1 ? true : false? Why not (tmp == 1) == true ? true : false? ;) (Hint: it's the same as just tmp == 1.) \$\endgroup\$ Commented Jul 1, 2014 at 21:31
3
\$\begingroup\$

Rogue

Like other's have said, I am using the Eagle's movement to some degree. Rather than try to make a winning alien (My best ideas were already taken D:), I decided to make an alien with some character! My alien is a hired gun oblivious to the alien war, and is only on this planet to hunt the filthy human who has skipped out on his death stick debt. My alien will search the planet for the human, and continue to trail behind the human without killing him. Once an alien is seen near him, he will then try to quickly kill the human, and face off against this new foe with "luck on his side" from his completed task.

package alien;

import planet.Move;

public class Rogue extends Alien {

    private int threatPresent = 0;
    private int turnNorth = 0;

    public void setAbilityPoints(float[] abilities) {
        abilities[0] = 3;
        abilities[1] = 6;
        abilities[2] = 0;
        abilities[3] = 1;
        abilities[4] = 0;
    }

    public Move move(char[][] fields) {
        int vision = getVisionFieldsCount();
        char me = fields[vision][vision];
        int humanPresent = 0;            
        //This way, if there is no alien near, the current threat will not trigger attacking
        int isThereCurrThreat = 0;
        Move bestMove = Move.STAY;
        for (Move move : Move.values()) {
            for (int i = 1; i <= vision; i++) {
                int fieldX = vision + (i * move.getXOffset());
                int fieldY = vision + (i * move.getYOffset());
                if (fields[fieldX][fieldY] == 'A') {
                    isThereCurrThreat = 1;
                }

                if (fields[fieldX][fieldY] == 'T') {
                    humanPresent = 1;
                    //Turtles are basically dumb humans, right?
                }

                if (fields[fieldX][fieldY] == 'H') {
                    humanPresent = 1;
                }
            }

            //Alway follow that filthy human
            if (humanPresent == 1) {
                bestMove = move;
            }

           }

         if(humanPresent == 0) {
             //Alternate moving north and east towards the human
             //If I hit the edge of world, I search for the turtle as well
             if(turnNorth == 1) {
                bestMove = Move.NORTH;
                turnNorth = 0;
             }
               
             else {
                bestMove = Move.EAST;
                turnNorth = 1;
             }
         }

      //If a threat was found, attack accordingly.
      threatPresent = isThereCurrThreat;
      return bestMove;

    }

  public boolean wantToFight(int[] enemyAbilities) {
      //Only fight if another enemey is near
      if (threatPresent == 1) {
        return true;
        }

      else {
        return false;
      }
   }
}

The code is centered around the idea that I should sprint towards the human. Once I beat him, I then wrap around to the southwest, where I will look for the turtle.

EDIT : Oh, and about the turtle thing...my alien doesn't like them, so it's totally canon you guys.

\$\endgroup\$
5
  • \$\begingroup\$ Just realized I can sprint towards the turtle as well. Who doesn't love high dodge rogues? \$\endgroup\$ Commented Jul 2, 2014 at 10:26
  • 2
    \$\begingroup\$ is using int directly as boolean in if block part of Java 8 ? because it doesnt compile at all on my machine (Java 7). Hint : humanPresent \$\endgroup\$
    – Sikorski
    Commented Jul 2, 2014 at 14:15
  • \$\begingroup\$ Heck if I know, my Java experience has mostly been limited to scripts and college level classes. I will just make the comparisons, just so everything is peachy. Thanks for the heads up! \$\endgroup\$ Commented Jul 2, 2014 at 14:18
  • \$\begingroup\$ Also, @Sikorski, did you create your own main or init function to run your tests? Or can it be done just through the provided code alone? I swear, it's been so long since I've coded in a true Java environment, that I've forgotten the rules for executing Java code :( \$\endgroup\$ Commented Jul 2, 2014 at 14:31
  • \$\begingroup\$ no just download the code that OP has given in github link, add other classes and start testing. Oh you will have to add entry for each alien class in Planet class. \$\endgroup\$
    – Sikorski
    Commented Jul 2, 2014 at 14:32
3
\$\begingroup\$

Crash landed and just trying to survive. Survives mostly by it's agility and intelligence and counts every scar, considering carefully if it's worth it to start a fight or not. The survivor starts off just hunting and trying to avoid all those other aliens with their big weapons but as it gets more bold may start to go after them. When it really gets going it won't care who it's facing anymore.

package alien;

import planet.Move;

public class Survivor extends Alien {

    private int boldness = 0;
    private float life = 0;
    private float str = 1;
    private float def = 4;
    private float clever = 10 - life - str - def;

    public void setAbilityPoints(float[] abilities) {
        abilities[0] = life; //life
        abilities[1] = str; //strength
        abilities[2] = def; //defense
        abilities[3] = 0; //vision
        abilities[4] = clever; //cleverness
    }

    public Move move(char[][] fields) {
        //you are in the middle of the fields, say fields[getVisionFieldsCount()][getVisionFieldsCount()]
        int vision = getVisionFieldsCount(); //count of fields / middle
    char me = fields[vision][vision]; //middle of fields
    int leastDanger = Integer.MAX_VALUE;
    Move bestMove = Move.STAY;
    for (Move move : Move.values()) {
        int danger = 0;
        for (int i = 1; i <= vision; i++) { //loop through fields in specific direction
            int fieldX = vision + (i * move.getXOffset());
            int fieldY = vision + (i * move.getYOffset());
            switch(fields[fieldX][fieldY]) {
                case 'A':
                    if(boldness < 10)
                        danger++;
                    else
                        danger--;
                    break;
                case ' ':
                    break;
                default:
                    danger-=2;
            }
        }
        if (danger < leastDanger) {
            bestMove = move;
            leastDanger = danger;
        }
    }
    return bestMove;
    }

    public boolean wantToFight(int[] enemyAbilities) {
        //same order of array as in setAbilityPoints, but without cleverness
        bool fight = boldness < 50;//After 50 fights, believes self unstoppable            
        int huntable = 0;
        for(int ability : enemyAbilities){
            if(ability == 1)
                huntable++;
        }
        if(huntable >= 3){
             fight = true;
        }//if at least 3 of the visible stats are 1 then consider this prey and attack
        else if((float)enemyAbilities[1] / (float)getDefenseLvl() <= (float)getStrengthLvl() + (float)(getClevernessLvl() % 10) / (float)enemyAbilities[2] && enemyAbilities[0] / 5 < getLifeLvl() / 5)
            fight = true;//If I fancy my odds of coming out on top, float division for chance
        if(fight){//Count every scar
            boldness++;//get more bold with every battle
            life += enemyAbilities[0] / 5;
            str += enemyAbilities[1] / 5;
            def += enemyAbilities[2] / 5;
            clever += (10 - (enemyAbilities[0] + enemyAbilities[1] + enemyAbilities[2] + enemyAbilities[3] - 4)) / 5;//count the human cleverness attained or the enemies who buffed clever early
        }
        return fight;
    }

}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ I'm quite sure that for(int ability in enemyAbilities){ is a syntax error - try for(int ability : enemyAbilities){ \$\endgroup\$
    – Joshua
    Commented Jul 3, 2014 at 12:32
3
\$\begingroup\$

FunkyBob

First priority is survival, otherwise will try to find some prey. Assesses the visible area to find the general direction with the least threats or most prey. Seems to have about an 85-90% survival rate during my testing.

package alien;
import planet.Move;

public class FunkyBob extends Alien {
    public void setAbilityPoints(float[] abilities) {
        abilities[0] = 2.5f;
        abilities[1] = 5.5f;
        abilities[3] = 2;
    }

    private int QtyInRange(char[][] fields, int x, int y, int numStepsOut, char specie)
    {
        int count = 0;
        for(int i = numStepsOut * -1; i <= numStepsOut; i++)
            for(int j = numStepsOut * -1; j <= numStepsOut; j++)
                if(fields[x+i][y+j] == specie)
                    count++;
        return count;
    }

    private int AssessSquare(char[][] fields, int x, int y, int visibility){
        int score = 0;

        for(int i = 0; i <= visibility; i++)
        {
            score += (-1000 / (i == 0 ? 0.3 : i)) * QtyInRange(fields, x, y, i, 'A');
            score += (100 / (i == 0 ? 0.3 : i)) * QtyInRange(fields, x, y, i, 'T');
            score += (100 / (i == 0 ? 0.3 : i)) * QtyInRange(fields, x, y, i, 'H');
            score += (100 / (i == 0 ? 0.3 : i)) * QtyInRange(fields, x, y, i, 'E');
            score += (50 / (i == 0 ? 0.3 : i)) * QtyInRange(fields, x, y, i, 'W');
            score += (50 / (i == 0 ? 0.3 : i)) * QtyInRange(fields, x, y, i, 'C');
        }

        return score;
    }

    public Move move(char[][] fields)   {
        int vision = getVisionFieldsCount();
        Move bestMove = Move.STAY;
        int bestMoveScore = AssessSquare(fields, vision, vision, vision - 1);

        for (Move move : Move.values()) {
            int squareScore = AssessSquare(fields, vision + move.getXOffset(), vision + move.getYOffset(), vision - 1);
            if(squareScore > bestMoveScore)
            {
                bestMoveScore = squareScore;
                bestMove = move;
            }

        }
        return bestMove;
    }

    public boolean wantToFight(int[] enemyAbilities)    {
        return ((getCurrentHp() + this.getStrengthLvl()) / 2) >
                ((enemyAbilities[0] * 3) + enemyAbilities[1]);
    }
}
\$\endgroup\$
3
\$\begingroup\$

FunkyJack

Just for kicks, here's another entry with a slightly different approach. This one is only focused on avoiding fights. This isn't really a viable strategy due to being surrounded by enemies in the first couple of rounds. 40% of squares are occupied in the first round so on average you will be immediately adjacent to 3-4 enemies. But when increasing the initial empty squares to 12.5 times the species rather than 2.5 times the species it gets an average survival rate of 98.5%.

package alien;
import planet.Move;

public class FunkyJack extends Alien {
    public void setAbilityPoints(float[] abilities) {
        abilities[0] = 4.5f;
        abilities[1] = 1.5f;
        abilities[3] = 4;
    }

    private int QtyInRange(char[][] fields, int x, int y, int numStepsOut, char specie)
    {
        int count = 0;
        for(int i = numStepsOut * -1; i <= numStepsOut; i++)
            for(int j = numStepsOut * -1; j <= numStepsOut; j++)
                if(fields[x+i][y+j] == specie)
                    count++;
        return count;
    }

    private int AssessSquare(char[][] fields, int x, int y, int visibility, int prevScore){
        int score = 0;
        score += -10000 * QtyInRange(fields, x, y, visibility, 'A');                
        if(visibility > 0)
            score = AssessSquare(fields, x, y, visibility - 1, ((score + prevScore) / 5));
        else
            score += prevScore;

        return score;
    }

    public Move move(char[][] fields)   {
        int vision = getVisionFieldsCount();
        Move bestMove = Move.STAY;
        int bestMoveScore = AssessSquare(fields, vision, vision, vision - 1, 0);

        for (Move move : Move.values()) {
            int squareScore = AssessSquare(fields, vision + move.getXOffset(), vision + move.getYOffset(), vision - 1, 0);
            if(squareScore > bestMoveScore)
            {
                bestMoveScore = squareScore;
                bestMove = move;
            }
        }
        return bestMove;
    }

    public boolean wantToFight(int[] enemyAbilities)    {
        return false;
    }
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ 98.5% is immense. Even my Predicowards get only about 65% survival rate on average. Haha. Edit : My Predicowards have the same philosophy as FunkyJack - just stay away. I do have 10 vision though and 0 fighting stats. \$\endgroup\$
    – Zaenille
    Commented Jul 9, 2014 at 6:00
3
\$\begingroup\$

LazyBee

I started trying to make a clever Bee class that used pattern movements and deductive reasoning, but then I got sleepy, so I renamed it LazyBee and called it a night. He actually seems to perform pretty well on my tests (average of ~1645 with aliens on the github).

package alien;

import planet.Move;
public class LazyBee extends Alien{

    private static final int LIFE = 0;
    private static final int STRENGTH = 1;

    // Ran trials to figure out what stats were doing  best in sims
    // Lazily assumed that:
        // - Defense is negligeble compared to health
        // - Vision doesn't matter if I'm running east all the time
        // - Cleverness will be canceled out because dumb aliens (yum) won't care
            // and smart aliens probably account for it somehow
    public static float DARWINISM = 4.5f;
    public void setAbilityPoints(float[] abilities){
        abilities[LIFE] = DARWINISM;  
        abilities[STRENGTH] = 10f-DARWINISM;  
    }

    // If bananapeel is fine without trying to move cleverly, I probably am too
    public Move move(char[][] fields)
    {
        return Move.EAST; // This was giving me the best score of all arbitrary moves, for some reason
    }

    // inspired by ChooseYourBattles, tried to do some math, not sure if it worked
        // it seemed that Bee was doing better by being more selective
        // not accounting for cleverness because eh
    public boolean wantToFight(int[] enemyAbilities){
        // chance of hit (h) = (1-(1/((50/deflvl)+1)))) = 50/(deflvl+50)
        double my_h = 50.0/(this.getDefenseLvl() + 50), 
                their_h = (50.0 - enemyAbilities[STRENGTH])/50.0;
        // expected damage (d) = h * (strlvl+1)
        double my_d = /* long and thick */ my_h * (this.getStrengthLvl() + 1),
                their_d = their_h * (enemyAbilities[STRENGTH]); 
        // turns to die (t) = currhp / d
        double my_t = (this.getCurrentHp() / their_d),
                their_t = ((enemyAbilities[LIFE] * 5 + 10) / my_d); // Assume they're at full health because eh
        // worth it (w) = i outlast them by a decent number of turns
            // = my_t - their_t > threshold
            // threshold = 4.5
        boolean w = my_t - their_t > 4.5;

        return w;
    }
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Excellent work! I'm pretty amazed you score so well with a hardcoded direction. \$\endgroup\$ Commented Jul 22, 2014 at 21:48
  • \$\begingroup\$ @Michael you have no idea how pleasantly surprised I was when I found out! I had put a lot of effort into movement code, then i had it running against HOLD as a sort of control group. then I realized the control group was kicking ass, so I started experimenting with different shades of lazy! \$\endgroup\$ Commented Jul 23, 2014 at 15:27
3
\$\begingroup\$

NewGuy

Tries to engage "easy" targets for early farming. Otherwise, just move sporadically.

package alien;

import planet.Move;

public class NewGuy extends Alien {
    private final static byte LIFE=0, STR=1, DEF=2, VIS=3, CLV=4;
    
    public void setAbilityPoints(float[] abilities) {
        abilities[LIFE] = 5;
        abilities[STR] = 5;
    }
    
    public Move move(char[][] fields) {
        // Very rudimentary movement pattern. Tries to engage all "easy" peaceful aliens.
        // Programmer got lazy, so he doesn't run away from danger, decreasing his odds of survival.
        // Afterall, if his species dies, that's one fewer specie that humans have to contend with.
        
        int vision = getVisionFieldsCount(); //count of fields / middle
        char me = fields[vision][vision]; //middle of fields
        for (Move move : Move.values()) {
            for (int i = 1; i <= vision; i++) { //loop through fields in specific direction
                int fieldX = vision + (i * move.getXOffset());
                int fieldY = vision + (i * move.getYOffset());
                char alienType = fields[fieldX][fieldY];
                
                if (alienType == 'E' || alienType == 'H' || alienType == 'T' || alienType == 'W') {
                    return move;
                }
            }
        }
        
        return Move.getRandom();
    }
    
    public boolean wantToFight(int[] enemyAbilities) {
        if (isWhale(enemyAbilities)) {
            return true;
        } else if (isCow(enemyAbilities)) {
            return false; // Cows hit hard!
        } else if (isTurtle(enemyAbilities)) {
            return true;
        } else if (isEagle(enemyAbilities)) {
            return true;
        } else if (isHuman(enemyAbilities)) {
            if (enemyAbilities[STR] < 3) {
                return true;
            }
        }
        
        return false;
    }
    
    public boolean isWhale(int[] enemyAbilities) {
        return enemyAbilities[LIFE] == 10 && totalAbilityPoints(enemyAbilities) == 10;
    }
    
    public boolean isCow(int[] enemyAbilities) {
        return enemyAbilities[STR] == 10 && totalAbilityPoints(enemyAbilities) == 10;
    }
    
    public boolean isTurtle(int[] enemyAbilities) {
        return enemyAbilities[DEF] == 10 && totalAbilityPoints(enemyAbilities) == 10;
    }
    
    public boolean isEagle(int[] enemyAbilities) {
        return enemyAbilities[VIS] == 10 && totalAbilityPoints(enemyAbilities) == 10;
    }
    
    public boolean isHuman(int[] enemyAbilities) {
        return !(isWhale(enemyAbilities) || isCow(enemyAbilities) || isTurtle(enemyAbilities)) && totalAbilityPoints(enemyAbilities) >= 10;
    }
    
    public int totalAbilityPoints(int[] enemyAbilities) {
        return enemyAbilities[LIFE] + enemyAbilities[STR] + enemyAbilities[DEF] + enemyAbilities[VIS];
    }
}
\$\endgroup\$
6
  • \$\begingroup\$ That floating return true; line seems superfluous due to the else condition. \$\endgroup\$
    – Kyle Kanos
    Commented Jul 3, 2014 at 15:48
  • \$\begingroup\$ @KyleKanos True. Issue addressed. \$\endgroup\$ Commented Jul 3, 2014 at 16:16
  • \$\begingroup\$ your isHuman() test doesn't look quite right. Won't it find aliens who have leveled, too? \$\endgroup\$ Commented Jul 3, 2014 at 17:51
  • \$\begingroup\$ @Charles You're right. It's difficult (impossible?) to find out if the enemy is a Human, or a leveled up alien due to the way the 'cleverness' mechanic works, and the fact that we can't determine the cleverness during a fight query. Even using some basic math, it's very likely an educated guess on whether or not it's a human or not will be inaccurate. I guess I'll change him to run from humans. \$\endgroup\$ Commented Jul 3, 2014 at 18:30
  • \$\begingroup\$ Your isSpecie-tests look cool, but even prey fight and those tests will soon fail... \$\endgroup\$ Commented Jul 3, 2014 at 20:32
2
\$\begingroup\$

Guard

Stack life, buff strength & defense, then stay put. Only attack if the opponent seems to be aggressive (defined as strength being greater than 2):

public class Guard extends Alien{
    public void setAbilityPoints(float[] abilities){
        abilities[0] = 6;  // life
        abilities[1] = 2;  // str
        abilities[2] = 2;  // def
        abilities[3] = 0;  // vis
        abilities[4] = 0;  // clv
    }
   
    public Move move(char[][] fields){
        return Move.STAY;
    }
    
    public boolean wantToFight(int[] enemyAbilities){
        return enemyAbilities[1] >= 3;
    }
}
\$\endgroup\$
2
\$\begingroup\$

Bully Alien

Bully Alien will walk around ignoring enemies until he finds someone weak to mess with.

package alien;

import planet.Move;

public class BullyAlien extends Alien {

    @Override
    public void setAbilityPoints(float[] abilities) {
        abilities[0] = 2;
        abilities[1] = 8;
        abilities[2] = 0;
        abilities[3] = 0;
        abilities[4] = 0;
    }

    @Override
    public Move move(char[][] fields) {
        return Move.getRandom();
    }

    @Override
    public boolean wantToFight(int[] enemyAbilities) {
        return enemyAbilities[1] < 3;
    }           
}
\$\endgroup\$
5
  • 2
    \$\begingroup\$ Aww, the bully alien just wants to be friends. \$\endgroup\$ Commented Jul 2, 2014 at 12:33
  • 3
    \$\begingroup\$ @user3334871 More like: "the bully alien just wants to have a syntax error" \$\endgroup\$
    – Justin
    Commented Jul 2, 2014 at 17:52
  • \$\begingroup\$ Shouldn't wantToFight look at the enemy's abilities? \$\endgroup\$
    – Ingo Bürk
    Commented Jul 2, 2014 at 18:09
  • \$\begingroup\$ @IngoBürk It already did by the time you commented \$\endgroup\$ Commented Jul 2, 2014 at 18:23
  • \$\begingroup\$ Must've taken me too long to scroll through the thread then. :) \$\endgroup\$
    – Ingo Bürk
    Commented Jul 2, 2014 at 18:32
2
\$\begingroup\$

BlindBully

Doesn't care who or what is around it, just tries to decide if the alien it is facing right now is stronger or weaker than itself, and attacks those weaker.

package alien;
import planet.Move;
import java.util.Random;

public class BlindBully extends Alien {

    private final int LIFE = 0;
    private final int STRENGTH = 1;
    private final int DEFENSE = 2;
    private final int VISION = 3;
    private final int CLEVERNESS = 4;

    private Random rand = new Random();

    @Override
    public void setAbilityPoints(float[] abilities) {
        abilities[LIFE] = 6;
        abilities[STRENGTH] = 2;
        abilities[DEFENSE] = 2;
        abilities[VISION] = 0;
        abilities[CLEVERNESS] = 0;
    }

    @Override
    public Move move(char[][] fields) {
        // Go west! To meet interesting people, and kill them
        switch (rand.nextInt(3)) {
            case 0:
                return Move.NORTHWEST;
            case 1:
                return Move.SOUTHWEST;
            default:
                return Move.WEST;
        }
    }

    @Override
    public boolean wantToFight(int[] enemyAbilities) {
        int myFightRating = getLifeLvl() + getStrengthLvl() + getDefenseLvl();
        int enemyFightRating = enemyAbilities[LIFE] + enemyAbilities[STRENGTH] + enemyAbilities[DEFENSE];
        return myFightRating >= enemyFightRating;
    }

}
\$\endgroup\$
2
\$\begingroup\$

SecretWeapon2

package alien;

import planet.Move;

/**
 * Created by Vaibhav on 02/07/14.
 */
public class SecretWeapon2 extends Alien {

   private final static byte LIFE=0, STR=1, DEF=2, VIS=3, CLV=4;

public void setAbilityPoints(float[] abilities) {
    abilities[LIFE] = 3;
    abilities[STR] = 7;
    abilities[DEF] = 0;
    abilities[VIS] = 0;
    abilities[CLV] = 0;
}

public Move move(char[][] fields)   {
     return Move.getRandom();
}

public boolean wantToFight(int[] enemyAbilities)    {

    return enemyAbilities[1] < 4;
  }
}
\$\endgroup\$
1
  • \$\begingroup\$ So this is the best? haha \$\endgroup\$
    – justhalf
    Commented Jul 4, 2014 at 2:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.