0

I am creating a concentration game.

I have an buffered image array where I load in a 25 image sprite sheet.

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

0 index being the card back. and 1 - 24 being the values for the face of the cards to check against if the cards match.

What I am tying to do is this I will have 4 difficulties Easy, Normal, Hard, and Extreme. Each difficulty will have a certain amount of cards it will need to draw and then double the ones it chosen. for example the default level will be NORMAL which is 12 matches so it need to randomly choose 12 unique cards from the Buffered Image array and then double each value so it will only have 2 of each cards and then shuffle the results.

This is what I got so far but it always seems to have duplicates about 99% of the time.

//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

the 3 amounts I will be needing to generate is Easy 6, Normal 12, and Hard 18 extreme will use all of the images except index 0 which is the back of the cards.

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

わかりました、私はあなたにもっと良いものをあげると言ったので、そうします。まず、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 に答える
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

あなたの質問から私が理解していることから、答えは次のようになり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 に答える