java - Java while 循环,循环次数超出预期
问题描述
我只是在业余时间制作一个简单的扫雷游戏。为了放置地雷,我运行 while 循环,直到地雷总数 == 所选级别所需的地雷数。
然而,我总是得到比预期更多的地雷!我唯一的想法是while循环在多个线程上运行,但我试图阻止它,它仍然创建了比我想要的更多的地雷,我对线程也不是很好,因为我没有尝试使用它们特别是之前。
我正在使用处理使创建窗口和绘图更容易。
我尝试过不同的东西。将同步添加到函数负载中,简单的 int count = 0; 然后每次放置地雷时增加计数会使情况变得更糟?!?!
private synchronized void placeMines() {
ExecutorService es = Executors.newSingleThreadExecutor();
class placeThread implements Runnable {
Grid grid;
public placeThread(Grid grid) { this.grid = grid; }
public void run() {
final int mines = mode.mines;
//int mCount = 0;
while(this.grid.mineCount() < mines) {
this.grid.addMine();
}
println(grid.mineCount());
}
}
es.execute(new placeThread(this));
}
public synchronized boolean addMine() {
int randX = (int) Math.floor(Math.random() * this.cols);
int randY = (int) Math.floor(Math.random() * this.rows);
Cell selected = getCell(randX, randY);
if(selected.getValue() == 9) {
selected.setValue(9);
return true;
}
return false;
}
public synchronized int mineCount() {
int mCount = 0;
for(ArrayList<Cell> row : this.cells) {
for(Cell c : row) {
if(c.isMine()) mCount++;
}
}
编辑我已更改代码以使用 for 循环并修改了添加地雷的方式
private synchronized void placeMines() {
ExecutorService es = Executors.newSingleThreadExecutor();
class placeThread implements Runnable {
Grid grid;
public placeThread(Grid grid) { this.grid = grid; }
public void run() {
final int mines = mode.mines;
ArrayList<Cell> cList = new ArrayList<Cell>();
for(ArrayList<Cell> row : this.grid.cells) {
cList.addAll(row);
}
for(int j = 0; j < mines; j++) {
int randCell = (int) Math.floor(Math.random() * cList.size());
Cell selected = cList.get(randCell);
if(this.grid.addMine(selected)) { cList.remove(selected); } else { j--; }
}
println(this.grid.mineCount());
}
}
es.execute(new placeThread(this));
}
public synchronized boolean addMine(Cell c) {
if(c.getValue() != 9) {
c.setValue(9);
return true;
}
return false;
}
Cell 类(我制作了自己的事件处理系统,因为为什么不:p):
public class Cell extends Interactable {
// value 0 -> 8 is the number of mines around the cell if cell is not a mine.
// value = 9 when the cell is a mine
int xPos, yPos, value, mark;
//gridX and gridY are the coordinates of the cell relative to the grid.
int gridX, gridY;
boolean hidden = true;
boolean flag = false;
boolean wrong = false;
Grid parent;
//Drawing settings
private int border;// = 4; //Border will be set in constructor as a percentage of the cellSize
private int shade = 150;
private int shown = 175;
private int highlight = 200;
public Cell(Grid parent,int gridX, int gridY) {
this.parent = parent;
this.gridX = gridX;
this.gridY = gridY;
this.createHitbox();
this.updatePos();
// Just for when I was testing, this is changed later
this.value = (int) Math.floor(Math.random() * 10);
this.parent.eHandler.register(this, EventList.MouseOver);
this.parent.eHandler.register(this, EventList.MouseLeave);
this.parent.eHandler.register(this, EventList.MouseClicked);
this.parent.eHandler.register(this, EventList.MouseRightClicked);
}
public void die() {
this.parent.eHandler.deregister(this, EventList.MouseOver);
this.parent.eHandler.deregister(this, EventList.MouseLeave);
this.parent.eHandler.deregister(this, EventList.MouseClicked);
this.parent.eHandler.deregister(this, EventList.MouseRightClicked);
}
public void createHitbox() {
this.hitBox = new HitBox(this.xPos, this.yPos, parent.cellSize, parent.cellSize);
}
public synchronized int getValue() {
return this.value;
}
public synchronized void setValue(final int v) {
this.value = v;
}
public void updatePos() {
this.xPos = (parent.cellSize * gridX) + parent.xOffset;
this.yPos = (parent.cellSize * gridY) + parent.yOffset;
this.hitBox.x = this.xPos;
this.hitBox.y = this.yPos;
this.hitBox.w = parent.cellSize;
this.hitBox.h = parent.cellSize;
this.border = parent.cellSize / 10;
}
public synchronized boolean isMine() { return this.value == 9; }
public void draw() {
if(hidden) {
stroke(this.highlight);
strokeWeight(this.border);
fill(this.shade);
rect(this.xPos + this.border / 2, this.yPos + this.border / 2, this.parent.cellSize - this.border, this.parent.cellSize - this.border);
if(this.flag) drawFlag();
} else {
noStroke();
fill(this.shown);
rect(this.xPos, this.yPos, this.parent.cellSize, this.parent.cellSize);
drawValue();
}
}
private void drawValue() {
switch(this.value) {
case 0:
return;
case 1:
fill(10);
break;
case 2:
fill(0, 0, 200);
break;
case 3:
fill(0, 200, 0);
break;
case 4:
fill(200, 0, 0);
break;
case 5:
fill(200, 200, 0);
break;
case 6:
fill(200, 100, 0);
break;
case 7:
fill(100, 0, 200);
break;
case 8:
fill(200, 0, 200);
break;
case 9:
drawMine();
return;
default:
return;
}
textSize(this.parent.cellSize);
textAlign(CENTER, CENTER);
text(this.value, this.xPos + this.parent.cellSize / 2, this.yPos + this.parent.cellSize / 2);
return;
}
private void drawMine() {
stroke(0);
strokeWeight(this.parent.cellSize / 2);
point(this.xPos + this.parent.cellSize / 2, this.yPos + this.parent.cellSize / 2);
}
private void drawFlag() {
stroke(255, 0, 0);
if(wrong) stroke(0, 0, 255);
strokeWeight(this.parent.cellSize / 2);
point(this.xPos + this.parent.cellSize / 2, this.yPos + this.parent.cellSize / 2);
}
public int countMines() {
if(this.isMine()) return 0;
ArrayList<Cell> ns = parent.getNeighbours(this);
int count = 0;
for(Cell c : ns) {
if(c.isMine()) count++;
}
return count;
}
public boolean allMinesFound() {
if(this.isMine()) return false;
ArrayList<Cell> ns = parent.getNeighbours(this);
int mines = 0;
int flags = 0;
for(Cell c : ns) {
if(c.isMine()) mines++;
if(c.flag) flags++;
}
return mines == flags;
}
public void clearChain() {
this.hidden = false;
if(!this.allMinesFound()) return;
for(Cell c : parent.getNeighbours(this)) {
if(c.flag) continue;
boolean wasHidden = c.hidden;
c.reveal(false);
if(c.isMine()) return;
if(c.value == 0 && wasHidden) c.clearChain();
}
}
public void reveal(boolean cce) {
this.hidden = false;
if(this.value == 9) {
//GAMEOVER! MINE!
this.GameOver();
return;
}
if (this.value == 0 && cce == true) {
clearChain();
}
}
@Override
public void onMouseOverEvent() {
this.shade += 20;
this.highlight += 20;
}
@Override
public void onMouseClickedEvent() {
if(!this.hitBox.test(mouseX, mouseY) || !hidden) return;
if(this.flag) return;
this.reveal(true);
}
@Override
public void onMouseRightClickedEvent() {
if(!this.hitBox.test(mouseX, mouseY)) return;
//Mark Loop
if(!hidden) {
clearChain();
return;
}
this.flag = !this.flag;
int fCount = 0;
for(ArrayList<Cell> row : grid.cells) {
for(Cell c : row) {
if(c.flag) fCount++;
}
}
this.parent.parent.flagCount = fCount;
if(this.parent.parent.flagCount >= this.parent.parent.mines) {
this.parent.verifyFlags();
}
}
@Override
public void onMouseLeaveEvent() {
this.shade -= 20;
this.highlight -= 20;
}
private void GameOver() {
this.parent.parent.GameOver();
}
}
解决方案
我无法完全解决您的问题,但我会给您一些指示。
该while
语句的一般逻辑是可以的。您有一个退出条件,应该是true
何时addMine()
添加所需地雷的数量:
while(this.grid.mineCount() < mines) {
this.grid.addMine();
}
但请注意,如果addMine()
和mineCount()
实施不正确,它将无法按您的预期工作。您没有显示Cell
可以解释问题的代码。
为了放置地雷,我运行 while 循环,直到地雷总数 == 所选级别所需的地雷数。
对早期已知的多次迭代使用while
语句是不相关的。
通常你会使用它,因为你不知道你必须做的迭代次数。如果您知道此数字,则
使用 a似乎更合适:loop
for (int i=0; i< mines; i++) {
this.grid.addMine();
}
作为旁注, selected.setValue(9);
这里似乎没用:
if(selected.getValue() == 9) {
selected.setValue(9);
return true;
}
总之,在尝试使整个应用程序工作之前,您可能应该从小步骤开始。
推荐阅读
- php - 如何在 PHP 中更改数组的键?
- spring-boot - 嵌入式服务器(微服务)是否等同于应用服务器(JbossEAP)?
- python - 对于给定的 Pandas df,按列对 df 进行排序(首先是最高的 SUMMED 值),然后在每个唯一值中按另一列排序
- gradle - 在使用 Gradle 5.4 的 multibuild 项目中,java 8 的 sourceSompatiblity 没有生效
- symfony - 如何在数据库中添加 JSON 字段?
- java - 应用程序无法加载 application.yml 文件
- regex - 使用 NIFI 中的替换文本从数据中提取文本时出错
- hibernate - SpringBoot 2.1.5.RELEASE & MySQL 8.0.15 中未生成 GenerationType.IDENTITY
- javascript - 在 React Router 中,我如何删除/更改我之前发送的 history.push 中的参数?
- javascript - 如何首先向上滚动 url 地址栏(在移动浏览器上)