获取距离其他列表中的点最远的列表中的点

时间:2015-10-19 10:46:23

标签: java

我有一个玩家列表和一个生成点列表。每个玩家都有一个角色对象,每个角色都有一个位置。一个角色有许多生命,当他被杀时,只要他还有生命,他就会在最远离其他玩家的生物点重生。为此,我创建了以下代码:

for (Player spawnPlayer : players) {
   if (spawnPlayer.getCharacter().getCanSpawn()) {
      System.out.println("works");
      List<Integer> distanceArrayList = new ArrayList();
      for (Point point : map.getSpawnPoints()) {
         int distance = 0;
         for (Player player : players) {
             if (player != spawnPlayer && player.getCharacter().getLives() > 0 && !player.getCharacter().getCanSpawn()) {
                distance += Math.sqrt(Math.pow(point.x - player.getCharacter().getPosition().x, 2)
                                    + Math.pow(point.y - player.getCharacter().getPosition().y, 2));
             }
         }
         distanceArrayList.add(distance);
      }
      Point spawnPoint = map.getSpawnPoints().get(distanceArrayList.indexOf(Collections.max(distanceArrayList)));
                spawnPlayer.getCharacter().spawn(spawnPoint);

   }
}

生成点是硬编码的,分别为0,0,200,0,0,500和200,500。然而,玩家并不总是去最远的生成点(在测试期间只有两个玩家,一个没有移动)并且有时根本不改变位置,即使这个方法被调用。

修改

所以我们此时使用的代码如下:

public void SpawnPlayers()
{
    for (Player spawnPlayer : players)
    {
        if (spawnPlayer.getCharacter().getCanSpawn())
        {
            int maxDistance = 0;
            Point spawnPoint = null;
            for (Point point : map.getSpawnPoints())
            {
                int sumDistancesFromOthers = 0;
                for (Player player : players)
                {
                    if (player != spawnPlayer && player.getCharacter().getLives() > 0 && !player.getCharacter().getCanSpawn())
                    {
                        sumDistancesFromOthers += Math.sqrt(Math.pow(point.x - player.getCharacter().getPosition().x, 2)
                                + Math.pow(point.y - player.getCharacter().getPosition().y, 2));
                    }
                }
                if (maxDistance < sumDistancesFromOthers || spawnPoint == null)
                {
                    maxDistance = sumDistancesFromOthers;
                    spawnPoint = point;
                }
            }
            spawnPlayer.getCharacter().spawn(spawnPoint);
        }
    }
}

然而,球员有时仍会在错误的位置上产卵,有时根本不会在新的位置产卵,并且在比赛开始时,所有球员都会在同一位置产卵。每次游戏更新时都会调用SpawnPlayers()方法,并在玩家死亡时正确更新布尔值canSpawn。

产卵方法:

public void spawn(Point spawnPoint)
{
    setPosition(spawnPoint);
    canSpawn = false;
    for (Weapon weapon : weapons)
    {
        weapon.restartShotsRemaining();
    }
    new Timer().schedule(new TimerTask() {
        @Override
        public void run()
        {
            canBeHit = true;
        }
    }, 1500);
}

5 个答案:

答案 0 :(得分:2)

正如评论中所提到的,要充实实际问题是有点困难的。寻求调试帮助的问题通常被视为偏离主题。

根据目前提供的信息,很难清楚地得出“状态空间”#34;此计算中涉及的对象的数量。例如,getCanSpawn()getLives()>0之间的关系。目前尚不清楚何时将canSpawn标记设置为truefalse,以及lives计数何时减少。问题中的代码似乎也没有考虑到其他玩家已经占用的位置不应该用作生成位置。

因此,一般建议将算法分解为更小的部分,这样更容易测试和调试。例如,查看原始代码:

public void SpawnPlayers()
{
    for (Player spawnPlayer : players)
    {
        if (spawnPlayer.getCharacter().getCanSpawn())
        {
            ...
        }
    }
}

最里面的部分有助于将其提取到类似

的方法中
private void spawnPlayer(Player playerToSpawn)
{
    System.out.println("Spawning "+playerToSpawn);
    ...
}

这使得它更易于理解(并在控制台上看到)某个玩家即将被生成时,以及之后该玩家会发生什么(如{{1}所示语句)。

现在,有两件事与计算新玩家的生成位置有关:

  • 仍可用于产卵的位置
  • 其他玩家所拥有的位置(因而没有更长时间可用于产卵)

这些可以计算为两组...

System.out

这些集的内容取决于Set<Point> availableSpawnPoints = ...; Set<Point> positionsOfOtherPlayers = ...; getCanSpawn()值,可能需要根据您的需求和这些方法的相互作用进行调整。

然而,在计算了这些集之后,您要求的整个算法(根据问题标题)归结为单个方法 - 即接收两组点的方法,并从第一个计算点设置为&#34;最远的&#34;从第二组中的分数。

对于什么&#34;最远的&#34;有不同的可能解释。手段。你计算了一些距离,这对我来说有点奇怪。想象一下,你有两个&#34;固定&#34;积分(现有玩家的位置),以及一组候选人&#34;点(玩家可能产生的地方),如下图所示:

Spawning

现在,想象一下......

  • A与其他的距离为3.8和0.3,总和为4.1
  • B与其他的距离为2.0和2.0,导致总和为4.0

然后,根据您的方法,将选择A点作为产卵位置。 (当您简单地计算&#34;候选者&#34;指向任何固定点的最大距离时)同样适用于此示例。但是直观地(并且根据描述),您可能希望计算与任何其他点具有最大最小距离的点。或者更自然地:尽可能远离任何其他点的点。

因此可以使用某种方法(如

)来计算生成点
getLives()

您可以传递private Point computePointWithLargestMinimumDistance( Iterable<? extends Point> points, Set<? extends Point> others) { ... } availableSpawnPoints

(顺便说一下:方法签名是最通用的形式。你也可以使用更具体的参数类型,比如positionsOfOtherPlayers,但这里根本不需要 - 所以为什么不一般地这样做。 ..)

这是在这里实现的,在合理可能的范围内草绘你提到的类:

HashSet<Point>

MCVE的输出符合要求:

import java.awt.Point;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;


public class PlayerSpawning
{
    public static void main(String[] args)
    {
        PlayerSpawning p = new PlayerSpawning();
        p.spawnPlayers();
    }

    private List<Player> players;
    private PlayerMap map;

    PlayerSpawning()
    {
        map = new PlayerMap();
        players = new ArrayList<Player>();

        Player player0 = new Player("player0");
        player0.getCharacter().setPosition(new Point(0,0));
        player0.getCharacter().setCanSpawn(false);
        players.add(player0);

        Player player1 = new Player("player1");
        player1.getCharacter().setCanSpawn(true);
        players.add(player1);
    }

    public void spawnPlayers()
    {
        for (Player player : players)
        {
            if (player.getCharacter().getCanSpawn())
            {
                spawnPlayer(player);
            }
        }
    }

    private void spawnPlayer(Player playerToSpawn)
    {
        System.out.println("Spawning "+playerToSpawn);

        Set<Point> availableSpawnPoints = 
            new LinkedHashSet<Point>(map.getSpawnPoints());
        Set<Point> positionsOfOtherPlayers = 
            new LinkedHashSet<Point>();
        for (Player player : players)
        {
            if (player.getCharacter().getLives() <= 0)
            {
                continue;
            }
            if (player.getCharacter().getCanSpawn())
            {
                continue;
            }
            Point position = player.getCharacter().getPosition();

            System.out.println(
                "Have to consider that "+player+" is at "+position+
                " - this position is no longer available for spawing!");
            positionsOfOtherPlayers.add(position);
            availableSpawnPoints.remove(position);
        }

        Point spawnPoint = computePointWithLargestMinimumDistance(
            availableSpawnPoints, positionsOfOtherPlayers);

        System.out.println("Spawning "+playerToSpawn+" at "+spawnPoint);
        playerToSpawn.getCharacter().spawn(spawnPoint);
    }


    private Point computePointWithLargestMinimumDistance(
        Iterable<? extends Point> points, Set<? extends Point> others)
    {
        System.out.println("Compute point from    "+points);
        System.out.println("that is furthest from "+others);

        double largestMinDistance = Double.NEGATIVE_INFINITY;
        Point result = null;
        for (Point point : points)
        {
            double minDistance = 
                computeMinimumDistance(point, others);
            if (minDistance > largestMinDistance)
            {
                largestMinDistance = minDistance;
                result = point;
            }
        }
        System.out.println(
            "The point that has the largest minimum " +
            "distance "+largestMinDistance+" to any other point is "+result);
        return result;
    }


    private double computeMinimumDistance(
        Point point, Iterable<? extends Point> others)
    {
        double minDistanceSquared = Double.POSITIVE_INFINITY;
        for (Point other : others)
        {
            minDistanceSquared = 
                Math.min(minDistanceSquared, point.distanceSq(other));
        }
        return Math.sqrt(minDistanceSquared);
    }

}


class Player
{
    private String name;
    private Character character = new Character();

    public Player(String name)
    {
        this.name = name;
    }

    public Character getCharacter()
    {
        return character;
    }

    @Override
    public String toString()
    {
        return name;
    }

}
class Character
{
    private Point position = new Point();
    private boolean canSpawn = false;

    public boolean getCanSpawn()
    {
        return canSpawn;
    }

    public void setCanSpawn(boolean canSpawn)
    {
        this.canSpawn = canSpawn;
    }

    public int getLives()
    {
        return 1;
    }

    public Point getPosition()
    {
        return position;
    }

    public void setPosition(Point p)
    {
        position.setLocation(p);
    }

    public void spawn(Point spawnPoint)
    {
        setPosition(spawnPoint);
        canSpawn = false;
    }


}

class PlayerMap
{

    public List<Point> getSpawnPoints()
    {
        return Arrays.asList(
            new Point(0,0),
            new Point(200,0),
            new Point(0, 500),
            new Point(200,500));
    }

}

答案 1 :(得分:0)

我建议你使用局部变量来记住当前的最大值和相应的位置。您将通过避免搜索列表来获得性能。这将更改代码如下:

for (Player spawnPlayer : players) {
  if (spawnPlayer.getCharacter().getCanSpawn()) {
    System.out.println("works");
    int maxDistance = 0;
    Point spawnPoint = null;
    for (Point point : map.getSpawnPoints()) {
      int sumDistancesFromOthers = 0;
      for (Player player : players) {
        if (player != spawnPlayer && player.getCharacter().getLives() > 0 && !player.getCharacter().getCanSpawn()) {
          sumDistancesFromOthers += Math.sqrt(Math.pow(point.x - player.getCharacter().getPosition().x, 2)
              + Math.pow(point.y - player.getCharacter().getPosition().y, 2));
        }
      }
      if (maxDistance < sumDistancesFromOthers || spawnPoint == null) {
        maxDistance = sumDistancesFromOthers;
        spawnPoint = point;
      }
    }
    spawnPlayer.getCharacter().spawn(spawnPoint);
  }
}

我添加了测试spawnPoint == null,以确保退出循环后spawnPoint不会null

希望这会有所帮助......

杰夫

------------ UPDATE ------------

我更正了上面的片段,将其与其他玩家的距离总和作为最大化距离的定义。

答案 2 :(得分:0)

建议的代码更改:

for (Player spawnPlayer : players) {
   if (spawnPlayer.getCharacter().getCanSpawn()) {
      System.out.println("works");          
      int maxDistance = 0;
      Point currentSpawnPoint = null;
      for (Point point : map.getSpawnPoints()) {
         int distance = 0;             
         for (Player player : players) {
             if (player != spawnPlayer && player.getCharacter().getLives() > 0 && !player.getCharacter().getCanSpawn()) {
                distance += Math.sqrt(Math.pow(point.x - player.getCharacter().getPosition().x, 2)
                                    + Math.pow(point.y - player.getCharacter().getPosition().y, 2));
             }
         }
         if(distance>maxDistance){
             maxDistance = distance;
             currentSpawnPoint = Point;
         }
      }
    spawnPlayer.getCharacter().spawn(spawnPoint);

   }
}

推理:记住距离是没有必要的,依赖列表索引不是清理代码的方法(它们可能会改变)。

答案 3 :(得分:0)

如果以下假设属实,我认为您的代码段中没有问题:

  1. Character.getCanSpawn()隐含Character.getLives() > 0
  2. Character.spawn(spawnPoint)确保Character.getCanSpawn() == false(发布条件)
  3. 你最初仍然可以获得接近最佳的产卵:假设你为第一个角色随机选择一个产卵位置,第二个只能在w.r.t中最佳放置。首先。但是,第一个角色现在可能会有一个更优化的位置。

答案 4 :(得分:0)

我有点懒得“调试”你的代码,这就是我在下面创建代码片段的原因。

反正

  • 我建议你把代码分成小块。例如,我会移动代码来计算Point类的两点之间的距离。

  • 此外,您的代码如下,

    if (maxDistance < sumDistancesFromOthers || spawnPoint == null) {
        maxDistance = sumDistancesFromOthers;
        spawnPoint = point;
    }
    

    有点奇怪:如果 <{em> maxDistance < sumDistancesFromOthers spawnPoint == null,则选择当前的spawnpoint。我的意思是:如果maxDistance < sumDistancesFromOthers spawnPoint == null ......

以下代码假定至少有一名玩家还活着。然后,当产生所有死亡的玩家时,将每个生成点与活着的玩家的每个位置进行比较。如果玩家已经死亡并需要重生,我已将位置设置为null 此代码还假设多个玩家可以处于同一个生成点。但只有在所有spawnpoints 被占用时才会发生这种情况。

<强>播放器

public class Player {

    private Position position;

    public Player(Position initialPosition) {
        this.position = initialPosition;
    }

    /**
     * Returns a copy of the player's position.
     * @return The player's position.
     */
    public Position getPosition() {
        return new Position(this.position);
    }

    /**
     */
    public SpawnPoint spawn(List<SpawnPoint> spawnPoints, List<Player> players) {
        double highestDistance = 0.0d;
        SpawnPoint bestSpawnPoint = null;
        for (SpawnPoint sp : spawnPoints) {
            double distance = 0.0d;
            for (Player p : players) {
                if (p.isAlive()) {
                    distance += sp.getPosition().getDistance(p.getPosition());
                }
            }
            if (distance > highestDistance) {
                highestDistance = distance;
                bestSpawnPoint = sp;
            }
        }
        if (bestSpawnPoint == null) {
            // Do something if there is no best spawnpoint, that is,
            // when all spawnpoints are occupied and thus the furthest
            // spawnpoint is at a distance of 0.0.
        }
        return bestSpawnPoint;
    }

    public boolean isAlive() {
        return (this.position != null);
    }
}

<强>位置

public class Position {

    private int x;
    private int y;

    public Position(Position position) {
        if (position != null) {
            this.x = position.x;
            this.y = position.y;
        }
    }

    public Position(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return this.x;
    }

    public int getY() {
        return this.y;
    }

    /**
     * Calculates the distance between this position and the given position.
     * @param anotherPosition The position to compare the current position with.
     * @return The distance as a double.
     */
    public double getDistance(Position anotherPosition) {
        double xDistance = Math.abs(Math.pow(this.x - anotherPosition.x, 2));
        double yDistance = Math.abs(Math.pow(this.y - anotherPosition.y, 2));
        return Math.sqrt(xDistance + yDistance);
    }
}

<强> SpawnPoint

public class SpawnPoint {

    private Position position;

    public SpawnPoint(Position position) {
        this.position = position;
    }

    public SpawnPoint(int x, int y) {
        this(new Position(x, y));
    }

    public Position getPosition() {
        return new Position(this.position);
    }
}

主要:

public static void main(String[] args) {

    // Create some spawnpoints...
    List<SpawnPoint> spawnPoints = new ArrayList<SpawnPoint>() {{
        add(new SpawnPoint(0, 0));
        add(new SpawnPoint(2, 0));
        add(new SpawnPoint(0, 5));
        add(new SpawnPoint(2, 5));
    }};

    // Create some players
    Player playerA = new Player(new Position(0, 0));
    Player playerB = new Player(new Position(4, 1));
    Player playerC = new Player((Position) null);
    // A null position means that the player is dead.

    // Add the players to the list of players...
    List<Player> players = new ArrayList<Player>() {{
        add(playerA);
        add(playerB);
        add(playerC);
    }};

    // Spawn playerC (which is currently dead and need to be respawned)
    // and return the best spawn point as defined by the OP
    SpawnPoint sp = playerC.spawn(spawnPoints, players);

    // Print the position
    System.out.println(sp.getPosition());

}

我保持简单,并且有效。

然后你可以自己检查玩家是否还活着等等。

注意:正如Marco13已经说过的那样,确定生成点和任何玩家之间的最大最小值更合乎逻辑。或者你可以制作一个试图兼顾两者的算法。