为扫雷游戏创建随机地雷
create random mines for a minesweeper game
JButton[][] buttons = new JButton[20][20];
public void mines(){
ArrayList<Integer> x = new ArrayList<>();
ArrayList<Integer> y = new ArrayList<>();
for(int a=0;a<20;a++){
x.add(a);
y.add(a);
}
for(int i=0;i<30;i++){
int random_x = x.get(new Random().nextInt(x.size()));
int random_y = y.get(new Random().nextInt(y.size()));
x.remove(random_x);
y.remove(random_y);
buttons[random_x][random_y].setText("X");
}
}
我想为扫雷游戏创建随机地雷..谁能告诉我我做错了什么?如果我 运行 该程序不会显示 30 个随机地雷
这里是:
for (int i = 0; i < 30; i++) {
int random_x = x.get(new Random().nextInt(x.size()));
int random_y = y.get(new Random().nextInt(y.size()));
x.remove(random_x);
y.remove(random_y);
....
将在某些时候生成 IndexOutOfBoundsException...
您的列表有 20 个元素,您要从中删除 30 次元素...
您的随机坐标可能大于您的网格大小。如果 x 的大小是 20,而你的 random_x 也是 20,那么你将得到一个 IndexOutOfBoundsException
.
改为:
int random_x = x.get(new Random().nextInt(x.size() - 1));
int random_y = y.get(new Random().nextInt(y.size() - 1));
如果大小为 20,它会给你一个 0 到 19 之间的随机数。
此外,因为您的列表是 Integer
类型,x.remove(random_x)
调用将其解释为列表中的索引,而不是对象本身。
要解决此问题,请在调用 remove()
时使用 Integer
,而不是 int
。如:
x.remove(Integer.valueOf(random_x));
编辑:
要进一步 improve/fix 随机生成器,将其更改为:
int random_x = x.get(new Random().nextInt(x.size() == 1 ? 1 : x.size() - 1));
使用以下代码段进行测试时:
Test t = new Test();
t.mines();
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 20; j++)
{
if ("X".equals(t.buttons[i][j].getText())) {
System.out.println("x:" + i + ", y:" + j);
}
}
}
给出输出:
x:0、y:18
x:1、y:5
x:2、y:1
x:3、y:3
x:4, y:9
x:5, y:15
x:6, y:14
x:7, y:10
x:8、y:8
x:9, y:11
x:10, y:16
x:11,y:17
x:12,y:0
x:13,y:7
x:14,y:4
x:15,y:12
x:16,y:2
x:17,y:6
x:18,y:13
x:19, y:19
试试这个方法:
public static void mines(JButton[][] buttons)
{
Random rand = new Random();
int mineCount = 0;
while (mineCount < 30)
{
int randomInteger = (int) (rand.nextDouble() * buttons.length);
int randomInteger2 = (int) (rand.nextDouble() * buttons[0].length);
if (buttons[randomInteger][randomInteger2].getText().equals("X"))
continue;
else
{
buttons[randomInteger][randomInteger2].setText("X");
mineCount++;
}
}
}
.nextDouble()
方法 returns 小于 1.0 的 Double 值。但我们需要一个介于 0 和 19 之间的随机整数(即 buttons.length
-1)。
所以我们将这个随机双精度值乘以按钮列表的大小,即 20,并将其转换为 int。所以我们可以得到 0 到 19 之间的值。
buttons.length
和 buttons[0].length
之间的区别是,第一个你得到第一维的长度(如你所知,它是一个二维数组),第二个给出的长度第二个维度。所以你动态获取数字并与随机数相乘,以避免 ArrayIndexOutOfBounds
异常。
您可以将此方法用于任何大小的二维按钮数组,它会起作用。但是警告,如果你使用的数组少于 30 个按钮,while 循环将永远持续下去,因为你不能得到 30 个地雷:)
改进此方法的一种方法是参数化 mineCount,因此您可以像 public static void mines(JButton[][] buttons, int mineCount)
那样更改方法,这样您就可以在方法调用时设置我的计数。
您选择了一种不同寻常的模型来保存地雷所在位置的信息。虽然您可能会通过一些明智的调试来解决眼前的问题,但我预计这会给您带来更多问题。
我建议将您的模型更改为更直接的模型,例如:
class Cell {
private final JButton button = new JButton();
private boolean mine = false;
private boolean hidden = true;
public Cell() {
button.setText(" ");
}
public void setMine() {
assert hidden;
mine = true;
}
public boolean hasMine() {
return mine;
}
public void reveal() {
hidden = false;
button.setText(mine ? "X" : "-");
}
public boolean isHidden() {
return hidden;
}
}
class Field {
public static final int SIZE = 20;
private final Cell[][] cells = new Cell[SIZE][SIZE];
public Field(int minesToAdd) {
for (int x = 0; x < SIZE; ++) {
for (int y = 0; y < SIZE; y++) {
cells[x][y] = new Cell();
}
}
Random random = new Random();
while (minesToAdd > 0) {
Cell cell = cells[random.nextInt(SIZE)][random.nextInt(SIZE)];
if (!cell.hasMine()) {
cell.setMine();
minesToAdd--;
}
}
}
public JPanel getButtonPanel() {
....
}
}
我相信这样会让你的意图更加明确。这有一些问题,例如模型和演示文稿 (JButton) 之间的紧密 link,但这完全可以通过各种设计模式解决。
你可以试试这个:
int x = 20;
int y = 20;
JButton[][] buttons = new JButton[x][y];
public void mines(){
int mines = 30;
Random rand = new Random()
while(mines>0){
int random_x = rand.nextInt(x);
int random_y = rand.nextInt(y);
if(buttons[random_x][random_y]!=null){
buttons[random_x][random_y] = new Button();
buttons[random_x][random_y].setText("X")
mines--;
}
}
}
JButton[][] buttons = new JButton[20][20];
public void mines(){
ArrayList<Integer> x = new ArrayList<>();
ArrayList<Integer> y = new ArrayList<>();
for(int a=0;a<20;a++){
x.add(a);
y.add(a);
}
for(int i=0;i<30;i++){
int random_x = x.get(new Random().nextInt(x.size()));
int random_y = y.get(new Random().nextInt(y.size()));
x.remove(random_x);
y.remove(random_y);
buttons[random_x][random_y].setText("X");
}
}
我想为扫雷游戏创建随机地雷..谁能告诉我我做错了什么?如果我 运行 该程序不会显示 30 个随机地雷
这里是:
for (int i = 0; i < 30; i++) {
int random_x = x.get(new Random().nextInt(x.size()));
int random_y = y.get(new Random().nextInt(y.size()));
x.remove(random_x);
y.remove(random_y);
....
将在某些时候生成 IndexOutOfBoundsException...
您的列表有 20 个元素,您要从中删除 30 次元素...
您的随机坐标可能大于您的网格大小。如果 x 的大小是 20,而你的 random_x 也是 20,那么你将得到一个 IndexOutOfBoundsException
.
改为:
int random_x = x.get(new Random().nextInt(x.size() - 1));
int random_y = y.get(new Random().nextInt(y.size() - 1));
如果大小为 20,它会给你一个 0 到 19 之间的随机数。
此外,因为您的列表是 Integer
类型,x.remove(random_x)
调用将其解释为列表中的索引,而不是对象本身。
要解决此问题,请在调用 remove()
时使用 Integer
,而不是 int
。如:
x.remove(Integer.valueOf(random_x));
编辑: 要进一步 improve/fix 随机生成器,将其更改为:
int random_x = x.get(new Random().nextInt(x.size() == 1 ? 1 : x.size() - 1));
使用以下代码段进行测试时:
Test t = new Test();
t.mines();
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 20; j++)
{
if ("X".equals(t.buttons[i][j].getText())) {
System.out.println("x:" + i + ", y:" + j);
}
}
}
给出输出: x:0、y:18 x:1、y:5 x:2、y:1 x:3、y:3 x:4, y:9 x:5, y:15 x:6, y:14 x:7, y:10 x:8、y:8 x:9, y:11 x:10, y:16 x:11,y:17 x:12,y:0 x:13,y:7 x:14,y:4 x:15,y:12 x:16,y:2 x:17,y:6 x:18,y:13 x:19, y:19
试试这个方法:
public static void mines(JButton[][] buttons)
{
Random rand = new Random();
int mineCount = 0;
while (mineCount < 30)
{
int randomInteger = (int) (rand.nextDouble() * buttons.length);
int randomInteger2 = (int) (rand.nextDouble() * buttons[0].length);
if (buttons[randomInteger][randomInteger2].getText().equals("X"))
continue;
else
{
buttons[randomInteger][randomInteger2].setText("X");
mineCount++;
}
}
}
.nextDouble()
方法 returns 小于 1.0 的 Double 值。但我们需要一个介于 0 和 19 之间的随机整数(即 buttons.length
-1)。
所以我们将这个随机双精度值乘以按钮列表的大小,即 20,并将其转换为 int。所以我们可以得到 0 到 19 之间的值。
buttons.length
和 buttons[0].length
之间的区别是,第一个你得到第一维的长度(如你所知,它是一个二维数组),第二个给出的长度第二个维度。所以你动态获取数字并与随机数相乘,以避免 ArrayIndexOutOfBounds
异常。
您可以将此方法用于任何大小的二维按钮数组,它会起作用。但是警告,如果你使用的数组少于 30 个按钮,while 循环将永远持续下去,因为你不能得到 30 个地雷:)
改进此方法的一种方法是参数化 mineCount,因此您可以像 public static void mines(JButton[][] buttons, int mineCount)
那样更改方法,这样您就可以在方法调用时设置我的计数。
您选择了一种不同寻常的模型来保存地雷所在位置的信息。虽然您可能会通过一些明智的调试来解决眼前的问题,但我预计这会给您带来更多问题。
我建议将您的模型更改为更直接的模型,例如:
class Cell {
private final JButton button = new JButton();
private boolean mine = false;
private boolean hidden = true;
public Cell() {
button.setText(" ");
}
public void setMine() {
assert hidden;
mine = true;
}
public boolean hasMine() {
return mine;
}
public void reveal() {
hidden = false;
button.setText(mine ? "X" : "-");
}
public boolean isHidden() {
return hidden;
}
}
class Field {
public static final int SIZE = 20;
private final Cell[][] cells = new Cell[SIZE][SIZE];
public Field(int minesToAdd) {
for (int x = 0; x < SIZE; ++) {
for (int y = 0; y < SIZE; y++) {
cells[x][y] = new Cell();
}
}
Random random = new Random();
while (minesToAdd > 0) {
Cell cell = cells[random.nextInt(SIZE)][random.nextInt(SIZE)];
if (!cell.hasMine()) {
cell.setMine();
minesToAdd--;
}
}
}
public JPanel getButtonPanel() {
....
}
}
我相信这样会让你的意图更加明确。这有一些问题,例如模型和演示文稿 (JButton) 之间的紧密 link,但这完全可以通过各种设计模式解决。
你可以试试这个:
int x = 20;
int y = 20;
JButton[][] buttons = new JButton[x][y];
public void mines(){
int mines = 30;
Random rand = new Random()
while(mines>0){
int random_x = rand.nextInt(x);
int random_y = rand.nextInt(y);
if(buttons[random_x][random_y]!=null){
buttons[random_x][random_y] = new Button();
buttons[random_x][random_y].setText("X")
mines--;
}
}
}