我有以下for循环,它应该生成两个随机整数并调用grid.place(x,y)。我试图弄清楚如果grid.place(x,y)返回false,如何生成不同的对。如果提供的x和y之前没有提供,则place方法返回true。谢谢。
for (int i = 0; i < 10; i++) {
mx = randomGenerator.nextInt(10);
my = randomGenerator.nextInt(10);
grid.place(mx,my);
}
答案 0 :(得分:2)
这是do-while
循环的完美情况:
for (int i = 0; i < 10; i++) {
do{
mx = randomGenerator.nextInt(10);
my = randomGenerator.nextInt(10);
}while(!grid.place(mx,my));
}
另一种解决方案是使用Collections.shuffle()
方法。像这样:
List<Integer> xPos = IntStream.rangeClosed(0,10).boxed().collect(Collectors.toList());
List<Integer> yPos = IntStream.rangeClosed(0,10).boxed().collect(Collectors.toList());
Collections.shuffle(xPos);
Collections.shuffle(yPos);
for(int i=0;i<10;i++)
grid.place(xPos.get(i), yPos.get(i));
这将为您提供所有协调,并且不会以比do-while
循环
答案 1 :(得分:1)
为避免重复,您可以使用List例如:
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);//fill your list
}
Random randomGenerator = new Random();
int mx = randomGenerator.nextInt(10);//generate the first value
int x = mx;//to not lost this value we store it in another variable
list.remove(mx);//remove the first value from your list, to avoid duplicate
int my = randomGenerator.nextInt(9);//generate the second value
int y = my;
grid.place(x, y);//now, you are sure that you have two different values
答案 2 :(得分:1)
这是一种更像OO的方法:
“网格”很可能不是无限的。这意味着您可以创建网格中所有可能位置的列表:
class Position{
private final int x;
private final int y;
public Position(int x, int y){
this.x=x;
this.y=y;
}
public getX(){return x;}
public getY(){return y;}
}
List<Position> availablePositions = new ArrayList<>();
for(int i =0; i<MAX_X;i++)
for(int j =0; j<MAX_Y;j++)
availablePositions.add(new Position(i,j));
然后您可以从该列表中检索随机索引:
for (int i =0;i<10;i++){
Position randomPosition =
availablePositions.remove(
new Random().nextInt(availablePositions.size()));
grid.place(
randomPosition.getX(),
randomPosition.getY());
}
这样你永远不会得到重复,但程序当前执行的位置会丢失。
或者你可以随便洗牌并获取前10个元素:
Collections.shuffle(availablePositions);
for (int i =0;i<10;i++)
grid.place(
availablePositions.get(i).getX(),
availablePositions.get(i).getY());
这也确保了循环中的不同位置,但是您将所有位置保留在列表中供以后使用...
这个解决方案的最大问题是它以O(MAX_X * MAX_Y)内存为代价具有确定性时间。其他解决方案具有O(1)时间(对于小的i值),尽管不是确定性的,并且具有O(1)存储器。 - gobernador
在现代计算机上,内存不是限制资源(甚至在手机上也没有......)。使用Java编程时,除非已经证明您遇到问题,否则不应优化内存和/或性能。如果你真的有内存问题那么Java很可能是该任务的错误工具。
可是:
当我们在解决方案中接受更多OO时,我们不需要单独的
Position
个对象使内存失真。我们宁愿使用状态的 Cell 对象,我们可以在网格中更改而不是不可变String
个对象。除了启用此选择机制之外,使用自定义类作为网格中的元素还有一些其他优点,因此我们应该看看它。
Cell.java
class Cell{
private String content = " "; // empty
public void placeHere(String newContent){
content = newContent;
}
}
Grid.java
// ...
Cell [] [] gameField = new Cell [MAX_X] [MAX_Y];
for(int i = 0; i
然后我们可以在单独的列表中收集这些现有单元格:
列出allCells = new ArrayList&lt;&gt;(); for(Cell [] row:gameField) allCells.addAll(Arrays.asList(行));
选择随机单元格来改变状态:
Collections.shuffle(allCells);
for(int i =0; i<10; i++)
allCells.get(i).placeHere("*");
实际上我们甚至不需要知道改变的细胞坐标。这就是OOP的意义:尽可能减少代码中的技术知识来解决您的任务。
等等,还有更多:
如何使用纯String
数组重置游戏?是的,你遍历完整的数组。但我得到的最佳性能优化提示是:
做某事的最快方法就是不去做。
那么我们怎样才能避免对整个数组进行迭代?
通过我的方法,我们可以在单独的列表中收集修改后的单元格:
List<Cell> modifiedCells = new ArrList<>();
Collections.shuffle(allCells);
for(int i =0; i<10; i++){
Cell currentCell = allCells.get(i);
currentCell.placeHere("*");
modifiedCells.add(currentCell);
}
然后,您必须重置该额外列表中的 10 单元格对象,而不是数组中的MAX_X*MAX_Y
字符串。
答案 3 :(得分:0)
最长和最强力的方法是检查网格中是否已经访问过坐标。
你必须从十岁开始,然后逐渐减少到零。
int size = 10;
for (int count = size; count > 0;) {
mx = randomGenerator.nextInt(size);
my = randomGenerator.nextInt(size);
if (!grid.exists(mx, my)) {
grid.place(mx, my);
count--;
}
}
public class Grid {
private boolean[][] self;
public Grid(int size) {
this.self = new boolean[size][size];
}
public int getSize() {
return this.self.length;
}
public boolean exists(int row, int col) {
return this.self[row][col];
}
public void place(int row, int col) {
this.self[row][col] = true;
}
@Override
public String toString() {
StringBuffer buff = new StringBuffer();
for (int row = 0; row < this.self.length; row++) {
if (row > 0) {
buff.append(System.lineSeparator());
}
for (int col = 0; col < this.self[0].length; col++) {
if (col > 0) {
buff.append('\t');
}
buff.append(this.self[row][col] ? '1' : '0');
}
}
return buff.toString();
}
}
public class GridDriver {
public static void main(String[] args) {
int size = 10;
Grid grid = new Grid(size);
for (int count = size; count > 0;) {
int mx = (int) (Math.random() * size);
int my = (int) (Math.random() * size);
if (!grid.exists(mx, my)) {
grid.place(mx, my);
count--;
}
}
System.out.println(grid);
}
}
0 0 0 1 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 1 1 0
0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 1
解决此问题的最佳方法是创建某种类型的内存映射并生成排列并随机迭代这些值。
答案 4 :(得分:0)
你只需要检查你传递的哪一对未被传递过。 使用HashSet可以实现它:
HashSet<String> set = new HashSet<>();
int i = 0;
while(i<10) {
mx = randomGenerator.nextInt(10);
my = randomGenerator.nextInt(10);
String rand = mx + "" + my;
if(!set.add(rand)){
grid.place(mx,my);
i++;
}
}
因此,设置将确保您传递的任何一对,之前未传递。
答案 5 :(得分:0)
你可以做到
for(int i = 0; i < 10; i++){
while(true){
mx = randomGenerator.nextInt(10);
my = randomGenerator.nextInt(10);
if(grid.place(mx,my)) break;
}
}
此循环结束,直到grid#place
返回true
,并继续生成随机值。
答案 6 :(得分:0)
如果您需要继续尝试生成数字直到它被放置,并填充网格10x10,基本上您要做的就是检查已经放置的数字。
Set<Integer> placedNumbers = new HashSet<>();
while(set.size() != 100) {
mx = randomGenerator.nextInt(10);
my = randomGenerator.nextInt(10);
if(!placedNumbers.contains(mx+my) && grid.place(mx,my)) {
placedNumbers.add(mx+my);
}
}