我有一个2d数组,并且我将所有单元格设置为枚举类型State.SAFE。现在我想把其中的5个单元格,随机放到state。hit中。输入:
Random objrandom = new Random();
State[][] playField = new State[5][5];
int w;
for (w = 0; w < 5; w++) { // set all states to SAFE first
int h = 0;
playField[w][h] = State.SAFE;
for (h = 0; h < 5; h++) {
playField[w][h] = State.SAFE;
}
}
for (int i = 0; i < 5; i++) { // try and set 5 states, randomly, to HIT
playField[objrandom.nextInt(5)][objrandom.nextInt(5)] = State.HIT;
}
问题是每次我运行它时,所有的细胞要么仍然处于安全状态,要么命中状态是非随机分布的,即每列的第一行或有超过5个命中状态。
如果你需要5个单元格设置为HIT,你不能使用这样的随机,因为你可能会得到相同的数字不止一次。我是这样做的:
public static void main(String[] args) {
State[][] playField = new State[5][5];
setStateToSafe(playField);
List<Integer> hits = getRandomIndices(5);
applyHitStateToIndices(hits, playField);
System.out.println(Arrays.deepToString(playField));
}
private static void setStateToSafe(State[][] playField) {
for (int w = 0; w < playField.length; w++) {
Arrays.fill(playField[w], State.SAFE);
}
}
private static List<Integer> getRandomIndices(int n) {
List<Integer> hits = new ArrayList<>();
for (int i = 0; i < n * n; i++) hits.add(i);
Collections.shuffle(hits);
return hits.subList(0, n);
}
private static void applyHitStateToIndices(List<Integer> hits, State[][] playField) {
for (int i = 0; i < hits.size(); i++) {
int hitIndex = hits.get(i);
int row = hitIndex / playField.length;
int column = hitIndex % playField.length;
playField[row][column] = State.HIT;
}
}
您的解决方案有一个问题,因为行playField[objrandom.nextInt(5)][objrandom.nextInt(5)]=...
可能导致同一个单元格被引用两次。我不能确定这是否是你的问题的原因,但至少可能是部分原因。
如果你想解决这个问题,你必须根据已经更改的单元格的历史检查每个随机数,并在重复点击的情况下请求不同的随机数。
我的建议是一个完全不同的方法。而不是请求要更改值的单元格的行和列的索引,随机应该表示值将更改的概率。
换句话说:
- 遍历数组中的所有单元格,生成0到1之间的随机值(使用
nextDouble()
) - 如果该值低于该单元格发生变化的概率(25个单元格中有5个单元格意味着5/25 = 0.2概率= 20%),则设置为
State.HIT
,否则设置为State.SAFE
代码应该看起来像这样:
Random objrandom = new Random();
State[][] playField = new State[5][5];
for (int w = 0; w < 5; w++) {
for (int h = 0; h < 5; h++) {
playField[w][h] = (objrandom.nextDouble() < 0.2d) ? State.HIT : State.SAFE;
}
}
如果这个小开销不会造成太多麻烦,那么您可以这样做:
创建一个类来表示字段上的一个点。
final class Point {
public final int x;
public final int y;
public Point(final int x, final int y) {
this.x = x;
this.y = y;
}
}
用所有可能的点填一个列表,然后洗牌。
List<Point> points = new ArrayList<>();
for (int x = 0; x < 5; x++) {
for (int y = 0; y < 5; y++) {
points.add(new Point(x, y));
}
}
Collections.shuffle(points);
现在第一个N
(在你的情况下是5)点将被随机化,并且100%不相同。
for (int i = 0; i < 5; i++) {
Point p = points.get(i);
playField[p.x][p.y] = State.HIT;
}