algorithm - Locating point on a closed path to maximize sum of distances to a sample of weighted points (Game AI) -


i'm doing ai simple puzzled game , need solve following problem efficiently (less 1 sec range specified since need many iterations in game).

a sample of n (1 100,000) monsters strength 1 10,000 distributed on sides of square (0 200,000,000) @ 1 unit interval starting upper left corner. move hero point x on square maximize sum of weighted distances monsters. weighted distance each monster calculated monsterstrength*shortestdistancetox (by going clockwise or anticlockwise). x must on 1 unit interval mark , monsters , hero move on sides of square only

i have tried several approaches none fast or accurate enough.

the possibly complementary of problem (minimizing sum of distances set of points @ furthest distance each corresponding monsters in original set) seems related finding geometric median, facility location problem, weber problem etc.

linear programming possible might slow , overkilled.

does have idea approach?


here illustration on square of sides of length 3:

 1-------2(m/3)-------3------4(m/1) |                              | 12(m/2)                        5 |                              | 11(m/1)                        6 |                              | 10--------9---------8(x)-------7  

if put monster of strength 3 @ 2, 1 strenth 1 @ 4, 1 strength 2 @ 12 , 1 strength 1 @ 11 , hero(x) @ 8. sum of weighted distane is: 3*6 + 1*4 + 1*3 + 2*4 = 33, maximum in case

i try point out strategy can follow achieve required 1 second response time. of course, must implemented ensure fits requirement.

the solution relies on following fact:

basically, given sum of weighted distance wp position p, each monster contribute sum of weighted distances of p neighbor adding or subtracting 1 time strength wp. strength added if neighbor nearer monster p or subtracted if farther.

with fact in mind, solution resides in compute sum of weighted distance initial position on initial step, , compute sum of weighted distance other positions based on value computed neighbor.

besides compute value initial position, must define on initial step:

  • a direction (eg. clockwise) on traverse positions compute sum of weighted distances
  • the sum of strenght (sadd) of monsters farther (to add) when traversing on defined direction;
  • the sum of strenght (ssub) of monsters nearer (to subtract) when traversing on defined direction;

then, starting on neighbor of initial position, traverse position on defined direction, , each one, update sadd , ssub (when traverse circular path, monster getting nearer starts farther , vice versa) , add (sadd - ssub) value computed previous neighbor.

thus, can compute sum of weighted distances positions without having iterate on monsters each position.

i implemented initial version of solution in java.

the following class represents monster:

class monster {     private long strenght;     private int position;     // omitting getters , setters...         } 

and following class represents square side positions:

class squaresidepositions {     private list<monster>[] positionwithmosters;     private list<monster> monstersonsquaresides = new arraylist<monster>();      @suppresswarnings("unchecked")     public squaresidepositions(int numberofpositions) {         positionwithmosters = new linkedlist[numberofpositions];     }      public void add(int position, monster monster) {         if (positionwithmosters[position] == null) {             positionwithmosters[position] = new linkedlist<monster>();         }          positionwithmosters[position].add(monster);         monster.setposition(position);         monstersonsquaresides.add(monster);     }      public int size() {         return positionwithmosters.length;     }      public boolean hasmonsters(int position) {         return positionwithmosters[position] != null;     }      public long getsumofstrenghtsofmonstersontheposition(int i) {         long sum = 0;          (monster monster : positionwithmosters[i]) {             sum += monster.getstrenght();         }          return sum;     }      public list<monster> getmonstersonsquaresides() {         return monstersonsquaresides;     } } 

and finally, optimization performed in following method:

public static int findbest(squaresidepositions positions) {     long tini = system.currenttimemillis();     long sumofgettingnearer = 0;     long sumofgettingfarther = 0;     int currentbestposition;     long bestsumofweight = 0;     long currentsumofweight;     final int numberofpositions = positions.size();     int halfnumberofpositions = numberofpositions/2;     long strenghtsonpreviousposition = 0;     long strenghtsoncurrentposition = 0;     long strenghtsonpositionstartinggetnearer = 0;     int positionstartgetnearer;      // initial step. monsters initial position (0) skipped because @ distance 0      (monster monster : positions.getmonstersonsquaresides()) {         // getting nearer         if (monster.getposition() < halfnumberofpositions) {             bestsumofweight += monster.getstrenght()*monster.getposition();             sumofgettingnearer += monster.getstrenght();         } else {         // getting farther             bestsumofweight += monster.getstrenght()*(numberofpositions - monster.getposition());             sumofgettingfarther += monster.getstrenght();         }     }      currentbestposition = 0;     currentsumofweight = bestsumofweight;      // computing sum of weighted distances other positions     (int = 1; < numberofpositions; ++i) {         strenghtsonpreviousposition = 0;         strenghtsonpositionstartinggetnearer = 0;         strenghtsoncurrentposition = 0;         positionstartgetnearer = (halfnumberofpositions + - 1);          if (positionstartgetnearer >= numberofpositions) {             positionstartgetnearer -= numberofpositions;         }          // monsters on previous position start affect current , next positions, starting farther         if (positions.hasmonsters(i-1)) {             strenghtsonpreviousposition = positions.getsumofstrenghtsofmonstersontheposition(i-1);               sumofgettingfarther += strenghtsonpreviousposition;         }          // monsters on current position not affect current position , stop nearer         if (positions.hasmonsters(i)) {             strenghtsoncurrentposition = positions.getsumofstrenghtsofmonstersontheposition(i);             currentsumofweight -= strenghtsoncurrentposition;             sumofgettingnearer -= strenghtsoncurrentposition;         }          // monsters on position next half circuit start nearer         if (positions.hasmonsters(positionstartgetnearer)) {             strenghtsonpositionstartinggetnearer = positions.getsumofstrenghtsofmonstersontheposition(positionstartgetnearer);             sumofgettingnearer += strenghtsonpositionstartinggetnearer;             sumofgettingfarther -= strenghtsonpositionstartinggetnearer;         }          currentsumofweight += sumofgettingfarther - sumofgettingnearer;          // if current better previous best solution         if (currentsumofweight > bestsumofweight) {             bestsumofweight = currentsumofweight;             currentbestposition = i;         }     }      final long executiontime = system.currenttimemillis() - tini;      system.out.println("execution time: " + executiontime + " ms");     system.out.printf("best position: %d sum of weighted distances: %d\n", currentbestposition, bestsumofweight);      return currentbestposition; } 

to setup input used example, can use:

squaresidepositions positions = new squaresidepositions(12);  positions.add(1, new monster(3)); positions.add(3, new monster(1)); positions.add(10, new monster(1)); positions.add(11, new monster(2)); 

on preliminary test, method took 771 ms execute, 100,000 monsters , 200,000,000 possible positions, on intel core i5-2400 running windows 7.

i employed following code generate input:

// used numberofmosters == 100000 , numberofpositions == 200000000 public  static squaresidepositions initializemonstersonpositions(int numberofmonsters, int numberofpositions) {     random rand = new random();     squaresidepositions positions = new squaresidepositions(numberofpositions);      (int = 0; < numberofmonsters; ++i) {         monster monster = new monster(rand.nextint(10000)+1);          positions.add(rand.nextint(numberofpositions), monster);     }      return positions; } 

i hope helps you!


Comments

Popular posts from this blog

image - ClassNotFoundException when add a prebuilt apk into system.img in android -

I need to import mysql 5.1 to 5.5? -

Java, Hibernate, MySQL - store UTC date-time -