首页 > 解决方案 > 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();
  }

}

标签: javaloopswhile-loop

解决方案


我无法完全解决您的问题,但我会给您一些指示。

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;
}

总之,在尝试使整个应用程序工作之前,您可能应该从小步骤开始。


推荐阅读