/*******************************************************************************
* Copyright (c) 2015 - 2017
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*******************************************************************************/
package jsettlers.algorithms.borders;
import jsettlers.common.movable.EDirection;
import jsettlers.common.position.ShortPoint2D;
import java.util.concurrent.LinkedBlockingQueue;
/**
* This thread calculates the positions that represent the border between the areas occupied by different players.
*
* @author Andreas Eberle
*
*/
public class BordersThread implements Runnable {
private final IBordersThreadGrid grid;
private final LinkedBlockingQueue<ShortPoint2D> positionsQueue = new LinkedBlockingQueue<ShortPoint2D>();
private final Thread bordersThread;
private boolean canceled = false;
/**
* This constructor creates a new instance of {@link BordersThread} and automatically launches a thread for it called "bordersThread".
*
* @param grid
* the grid on that the {@link BordersThread} will be operating
*/
public BordersThread(IBordersThreadGrid grid) {
this.grid = grid;
this.bordersThread = new Thread(this);
this.bordersThread.setName("BordersThread");
this.bordersThread.setDaemon(true);
}
@Override
public void run() {
while (!canceled) {
ShortPoint2D position = null;
while (position == null && !canceled) {
try {
position = positionsQueue.take();
} catch (InterruptedException e) {
}
}
if (!canceled) {
calculateForPosition(position);
}
}
}
private void calculateForPosition(ShortPoint2D position) {
short x = position.x;
short y = position.y;
byte player = grid.getPlayerIdAt(x, y);
boolean isBorder = false;
if (grid.getBlockedPartition(x, y) > 0) { // the position is not a blocked landscape
for (EDirection currDir : EDirection.VALUES) {
int currNeighborX = currDir.getNextTileX(x);
int currNeighborY = currDir.getNextTileY(y);
if (!grid.isInBounds(currNeighborX, currNeighborY)) {
continue;
}
if (grid.getBlockedPartition(currNeighborX, currNeighborY) <= 0) {
continue; // this neighbor is in the sea => it can never be set.
}
byte neighborPlayer = grid.getPlayerIdAt(currNeighborX, currNeighborY);
boolean neighborIsBorder = false;
if (neighborPlayer != player) {
isBorder = true;
}
if (neighborPlayer >= 0) { // this position is occupied by a player
for (EDirection currNeighborDir : EDirection.VALUES) {
int nextX = currNeighborDir.getNextTileX(currNeighborX);
int nextY = currNeighborDir.getNextTileY(currNeighborY);
if (grid.isInBounds(nextX, nextY) && grid.getPlayerIdAt(nextX, nextY) != neighborPlayer
&& grid.getBlockedPartition(nextX, nextY) > 0) {
neighborIsBorder = true;
break;
}
}
} // else the position is not occupied -> don't display a border here
grid.setBorderAt(currNeighborX, currNeighborY, neighborIsBorder);
}
}
grid.setBorderAt(x, y, isBorder && player >= 0);
}
public void checkPosition(ShortPoint2D position) {
this.positionsQueue.offer(position);
}
public void checkArea(int x, int y, short width, short height) {
int endX = x + width;
int endY = y + height;
for (; y < endY; y += 2) {
for (int currX = x; currX < endX; currX += 2) {
this.positionsQueue.offer(new ShortPoint2D(currX, y));
}
}
}
public void cancel() {
this.canceled = true;
bordersThread.interrupt();
}
public void start() {
bordersThread.start();
}
}