0

我正在创造一个专注的游戏。

我有一个缓冲图像数组,我在其中加载了 25 个图像精灵表。

public static BufferedImage[] card = new BufferedImage[25];

0 索引是卡片背面。1 - 24 是卡片正面的值,用于检查卡片是否匹配。

我要做的是,我将有 4 个难度,简单、普通、困难和极端。每个难度都会有一定数量的卡片需要绘制,然后将其选择的卡片加倍。例如,默认级别将是 NORMAL,即 12 个匹配项,因此它需要从 Buffered Image 数组中随机选择 12 个唯一卡,然后将每个值加倍,这样每张卡只有 2 个,然后对结果进行洗牌。

这是我到目前为止所得到的,但它似乎总是有大约 99% 的时间重复。

//generate cards
                    Random r = new Random();

                    int j = 0;


                    int[] rowOne = new int[12];
                    int[] rowTwo = new int[12];
                    boolean[] rowOneBool = new boolean[12];

                    for(int i = 0; i < rowOneBool.length; i++)
                        rowOneBool[i] = false;


                    for(int i = 0; i < rowOne.length; i++){
                        int typeId = r.nextInt(12)+1;
                        while(rowOneBool[typeId]){
                            typeId = r.nextInt(12)+1;
                            if(rowOneBool[typeId] == false);
                        }

                        rowOne[i] = typeId;
                        j=0;
                    }

我的程序的示例运行

我需要生成的 3 个数量是 Easy 6、Normal 12 和 Hard 18extreme 将使用除索引 0(即卡片背面)之外的所有图像。

4

4 回答 4

1

这或多或少是随机数的性质。有时它们是重复的。如果您希望它们更加独特,您可以轻松地将其考虑在内。如果它不是唯一的,只需丢弃该数字并再次生成。

这是一种生成具有指定重复允许的唯一随机数的简单方法:

public static void main(String[] args) {
    int[] randoms = uniqueRandoms(new int[16], 1, 25, 3);
    for (int r : randoms) System.out.println(r);
}

public static int[] uniqueRandoms(int[] randoms, int lo, int hi, int allowance) {
    // should do some error checking up here

    int range = hi - lo, duplicates = 0;
    Random gen = new Random();

    for (int i = 0, k; i < randoms.length; i++) {
        randoms[i] = gen.nextInt(range) + lo;

        for (k = 0; k < i; k++) {
            if (randoms[i] == randoms[k]) {
                if (duplicates < allowance) {
                    duplicates++;
                } else {
                    i--;
                }
                break;
            }
        }
    }

    return randoms;
}

编辑:测试和纠正。现在它起作用了。:)

于 2013-11-07T04:09:36.463 回答
0

根据我从您的问题中了解到的情况,答案应该是这样的:有 2 个类,一个叫Randp,另一个叫Main. 运行Main并编辑代码以满足您的需要。

package randp;


public class Main {

    public static void main(String[] args) {
        Randp randp = new Randp(10);
        for (int i = 0; i < 10; i++) {
            System.out.print(randp.nextInt());
        }
    } 

}


package randp;

public class Randp {

private int numsLeft;
private int MAX_VALUE;
int[] chooser;

public Randp(int startCounter) {
    MAX_VALUE = startCounter; //set the amount we go up to
    numsLeft = startCounter;
    chooser = new int[MAX_VALUE];
    for (int i = 1; i <= chooser.length; i++) {
        chooser[i-1] = i; //fill the array up

    }
}

public int nextInt() {
    if(numsLeft == 0){
        return 0; //nothing left in the array
    }
    int a = chooser[(int)(Math.random() * MAX_VALUE)]; //picking a random index
    if(a == 0) {
        return this.nextInt(); //we hit an index that's been used already, pick another one!
    }
    chooser[a-1] = 0; //don't want to use it again
    numsLeft--; //keep track of the numbers
    return a;

}
}
于 2013-11-07T03:45:23.250 回答
0

这就是我将如何处理它。您会将 BufferedImage 对象移动到列表中,尽管我会考虑为您正在使用的“卡​​片”创建一个对象......

int removalAmount = 3; //Remove 3 cards at random... Use a switch to change this based upon difficulty or whatever...
List<BufferedImage> list = new ArrayList<BufferedImage>();
list.addAll(Arrays.asList(card)); // Add the cards to the list, from your array.
Collections.shuffle(list);

for (int i = 0; i < removalAmount; i++) {
    list.remove(list.size() - 1);
}

list.addAll(list);
Collections.shuffle(list);

for (BufferedImage specificCard : list) {
    //Do something
}
于 2013-11-07T03:58:48.877 回答
0

好吧,我说过我会给你更好的,我会的。首先,让我们改进 Jeeter 的解决方案。

  1. 它有一个错误。因为它依赖 0 作为“使用”指标,所以它实际上不会在最后产生索引 0,这不是随机的。
  2. 它用索引填充数组,然后使用 0 作为有效的布尔值,这是多余的。如果索引处的值不是 0,我们已经知道它是什么,它与我们用来获取它的索引相同。它只是隐藏了算法的真实本质,并使其变得不必要的复杂。
  3. 它在不需要时使用递归。当然,您可以争辩说这提高了代码的清晰度,但是您可能会遇到StackOverflowException太多递归调用的风险。

因此,我提出了算法的改进版本:

class Randp {
    private int MAX_VALUE;
    private int numsLeft;
    private boolean[] used;

    public Randp(int startCounter) {
        MAX_VALUE = startCounter; 
        numsLeft = startCounter;

        // All false by default. 
        used = new boolean[MAX_VALUE]; 
    }

    public int nextInt() {
        if (numsLeft <= 0)
            return 0;
        numsLeft--;

        int index;
        do
        {
            index = (int)(Math.random() * MAX_VALUE);
        } while (used[index]);

        return index;
    }
}

我相信这更容易理解,但现在很明显算法不是很好。找到未使用的索引可能需要很长时间,尤其是当我们想要很多值而只剩下几个值时。我们需要从根本上改变我们处理这个问题的方式。最好从头开始随机生成值:

class Randp {
    private ArrayList<Integer> chooser = new ArrayList<Integer>();
    private int count = 0;

    public Randp(int startCounter) {
        for (int i = 0; i < startCounter; i++)
            chooser.add(i);
        Collections.shuffle(chooser);
    }

    public int nextInt() {
        if (count >= chooser.size())
            return 0;
        return chooser.get(count++);
    }
}

这是最有效和最简单的,因为我们利用了现有的类和方法。

于 2013-11-08T19:26:40.260 回答