Java while循环,循环次数超过预期

时间:2018-07-15 09:13:50

标签: java loops while-loop

我只是在业余时间制作一个简单的扫雷游戏。为了放置地雷,我运行while循环,直到地雷总数==所选级别所需的地雷数量。

但是,我总是得到比预期更多的地雷!我唯一的想法是while循环在多个线程上运行,但是我试图阻止它,但是它仍然会产生比我想要的更多的地雷。我对线程也不是很满意,因为我没有尝试使用它们特别是之前。

我正在使用Processing来简化窗口和绘图的创建。

我尝试了不同的事情。将同步添加到函数负载中,简单的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();
  }

}

1 个答案:

答案 0 :(得分:0)

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

围绕while语句的一般逻辑是可以的。当true将添加所需的地雷数量时,您的退出条件应为addMine()

 while(this.grid.mineCount() < mines) {
    this.grid.addMine();
  }

但是请注意,如果addMine()mineCount()的实现不正确,将无法按预期工作。您没有显示可以解释该问题的Cell代码。

  

放置地雷,我运行while循环,直到   地雷==所选级别所需的地雷数量。

使用while语句进行早期已知的多次迭代是不相关的。
通常,您使用它是因为您不知道必须执行的迭代次数。
如果您知道以下数字,则使用loop似乎更合适:

for (int i=0; i< mines; i++) {
    this.grid.addMine();
} 

作为旁注,selected.setValue(9);在这里似乎没用:

if(selected.getValue() == 9) {
  selected.setValue(9);
  return true;
}

最后,在使整个应用程序正常工作之前,您可能应该从一些小步骤开始。