如何创建一个只能选择1次的数字生成器?

时间:2013-11-07 03:33:17

标签: java random

我正在制作专注游戏。

我有一个缓冲的图像数组,我加载了25张图像精灵表。

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

0指数是回卡。如果卡匹配,则1 - 24是要检查的卡面值。

我要做的就是这将使我有4个困难Easy,Normal,Hard和Extreme。每个难度都会有一定数量的牌需要抽取,然后加倍选择的牌。例如,默认级别为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;
                    }

A sample run of my program

我需要生成的3个数量是Easy 6,Normal 12和Hard 18 extreme将使用除了索引0之外的所有图像。

4 个答案:

答案 0 :(得分: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;
}

编辑:经过测试和更正。现在它有效。 :)

答案 1 :(得分: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;

}
}

答案 2 :(得分:0)

这就是我处理它的方式。您可以将BufferedImage对象移动到List,但我会考虑为您正在使用的“卡​​片”创建一个对象...

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
}

答案 3 :(得分:0)

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

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

    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++);
        }
    }
    

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