一种半随机排序算法(Java)

时间:2011-09-07 22:55:29

标签: java algorithm sorting collections

我正在制作一个基于回合制的RPG游戏,我的方法按照所有“Actor”对象的顺序对所有“Actor”对象进行排序,这些对象完全随机排序。但是,我希望改进这种方法,以便每个演员都拥有的“敏捷”数据能够提高他们的成绩。我已经查看了Collections类和Arrays中的几个方法,但似乎没有找到任何符合我想要的方法。

现在,我正在考虑获得1到100之间的随机int,并且敏捷得分可以提高几率。我为整数和一个HashMap尝试了单独的ArrayLists ......但是没有继续使用它们。

我现在的方法是:

// getFriendlies(), getHostiles(), and attack_order are all ArrayLists

public void calculateAttackOrder() {
        attack_order.addAll(getFriendlies());
        attack_order.addAll(getHostiles());
        Collections.shuffle(attack_order);
}

我很感激帮助!

5 个答案:

答案 0 :(得分:6)

使用Collections.sort()并提供一个比较器,它使用随机数和敏捷性的组合来计算排名。

这是一个可行的实现。请注意,Player是最简单的可用接口:

public interface HasAgility {
    /** @return value between 0 and 1 */
    double getAgility();
}

public class Player implements HasAgility {
    double agility;
    double getAgility( return agility; );
   // rest of class
}

public class MoveComparator implements Comparator<HasAgility> {
    /** Need to calculate the agility once, and keep using that same value, for each player */
    private Map<HasAgility, Double> playerAgilities = new HashMap<HasAgility, Double>();

    private Double getRandomAgility(HasAgility player) {
        Double randomAgility = playerAgilities.get(player);
        if (randomAgility == null) {
            randomAgility = Math.random() * player.getAgility();
            playerAgilities.put(player, randomAgility);
        }
        return randomAgility;
    }

    public int compare(HasAgility o1, HasAgility o2) {
        return getRandomAgility(o1).compareTo(getRandomAgility(o2));
    }
}

public static void main(String args[]) {
    List<Player> players= new ArrayList<Player>();
    Collections.sort(players, new MoveComparator());
}

需要注意的重要一点是,一旦计算出来,玩家的随机敏捷分数必须再次重复用于以后的所有比较。此Comparator类仅设计为使用一次(映射在其使用开始时必须为空)。

答案 1 :(得分:6)

关于灵活性如何影响攻击顺序的要求,你的问题没有详细说明,但我认为你的意思是这两个中的一个:

  1. 如果一个单位的敏捷度高于另一个单位,则始终先攻击。
  2. 如果一个单位的敏捷度高于另一个单位,则通常先攻击。
  3. 如果其中第一个是真的(具有更高敏捷性的单位总是首先攻击),那么你正在寻找的是一种置换数组的方法,受限于具有较高敏捷性的单位总是在较低单位之前结束敏捷,但其他一切随机完成。一种方法如下:

    1. 如果您有N个单位,请随机将数字1 ... N分配给单位。不要两次分配相同的号码。
    2. 按单位升序排列如下:
      • 敏捷度高于其他单位的任何单位都是第一位。
      • 在两个被绑定的地方中,以较高的随机数为准。
    3. 你可以证明这种方法将安排单位,以便所有具有某种敏捷性的单位相对于彼此随机置换,但总是在低敏捷单位之前。这需要时间O(n log n),可以使用Collections.sortCollections.shuffle和适当的Comparator来完成。

      另一方面,如果您希望排序是随机的,但敏感度受影响,您可能需要考虑使用某种可由某些参数控制的随机分布。例如,您可以为每个单位分配一个优先级,该正态分布的平均值是敏捷性,其标准偏差是一个相当大的数字(例如,20)。这意味着具有更高敏捷性的单位更有可能在灵活性较低的单位之前移动,尽管存在大量随机性。这种方法的优点是通过调整基础分布及其参数(正态分布情况下的均值和方差),您可以微调灵敏度测量的因素。

      作为一种非常简单的方法的示例,您可以将单位速度建模为

        

      priority = e (敏捷/ 100)+随机(1,2)

      在这里,您拥有的灵活性越高,您的优先级就越高。增加随机性的数量会改变敏捷性的重要程度。当然,这可能有点偏斜,因为敏捷性的每个边际增加都有更多意义,因此您可能希望用logistic function之类的东西替换指数。

      希望这有帮助!

答案 2 :(得分:2)

如果你无法触及Actor内部,你需要一种方法来为每个actor关联一个'roll'以进行完整的排序(可能包括许多要比较的调用),但是下一种排序会忘记它。 / p>

在这种情况下,我会这样做:

public class ActorComparable {
  Actor actor;
  int roll;

  public ActorComparable(Actor actor) {
    this.actor = actor;
    roll = Math.Random(100) + actor.getAgility();
  }

  public getActor() {
    return actor;
  }

  public getRoll() {
    return roll;
  }

  public int compareTo(Actor that) {
    return this.getRoll() - that.getRoll();
  }
}

现在,当你想要对Actors的ArrayList进行排序时,构建一个ActorComparables的ArrayList,对它们进行排序,并从ActorComparables中构建一个结果列表。

答案 3 :(得分:1)

class Actor implements Comparable {

    private int agility;
    private int randomAgility;

    private int getInitiative() {
        //You can change this method as you see fit
        return randomAgility + this.agility;
    }

    public void generateRandomAgility() {
        this.randomAgility = (Math.random() * 100);
    }

    public int compareTo(Object o) {
        Actor other = (Actor)other;
        return this.getInitiative() - other.getInitiative();
    }
}

然后你可以打电话

for (Actor a : attack_order) {
    a.generateRandomAgility();
}
Collections.sort(attack_order);

答案 4 :(得分:1)

使用TreeSet(a SortedSet实现的完整示例,保证元素始终排序,在这种情况下使用Comparator):

class Actor {
    private int agility;
    private double weight = Math.random(); 

    public Actor(int agility) {
        this.agility = agility;
    }
    public double getComputedAgility() {
        return agility * weight;
    }
}

public class TestRandomActors {
    public static void main(String[] args) {
        Collection<Actor> collection = new TreeSet<Actor>(
                new Comparator<Actor>() {
                    @Override
                    public int compare(Actor a1, Actor a2) {
                        return 
                            a1.getComputedAgility() > a2.getComputedAgility() ? -1 : 1;
                    }
                }
            );

        collection.add(new Actor(30));
        collection.add(new Actor(31));
        collection.add(new Actor(60));

        for (Actor actor : collection)
            System.out.println("Actor with agility = " + actor.getComputedAgility());
    }
}