Right now I have a static ArrayList in my Object class, but both of the threads are accessing/changing data to that one list. I need an ArrayList that is shared between all instances of Object, but not between instances of Object that are in different threads. What's the best way to go about this? Here's the gist of what's going on:
public class Game extends Thread {
private Actions actions;
private Player whitePlayer;
private Player blackPlayer;
private String gameID;
private boolean gameOver;
private int movesTaken;
private Command currentCommand;
private Player winner;
public ArrayList<Settlement> SettlementList = new ArrayList<Settlement>();
public ArrayList<Hex> SettledHexes = new ArrayList<Hex>();
public Game(String gameID){
whitePlayer = new Player(PlayerSide.WHITE);
blackPlayer = new Player(PlayerSide.BLACK);
actions = new Actions(true);
actions.setCurrentPlayer(whitePlayer);
this.gameID = gameID;
gameOver = false;
movesTaken = 0;
}
public void run(){
while(!gameOver){
if(commandIsInQueue()){
Message currentMessage = GameData.getIncomingMessages().poll();
if (currentMessage.getPlayerID().equals(whitePlayer.getPlayerID())) {
actions.setCurrentPlayer(whitePlayer);
}
else if(currentMessage.getPlayerID().equals(blackPlayer.getPlayerID())){
actions.setCurrentPlayer(blackPlayer);
}
else{
endGame();
}
System.out.println("Move made by: " + actions.getCurrentPlayer().getPlayerID() + " " + "in game: " + gameID);
setCurrentCommand(currentMessage.getCommand());
executeCommand();
checkEndGameConditions();
mergeAllSettlement();
movesTaken++;
}
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void executeCommand(){
int x, y, z, orientation;
TerrainType hexATerrain, hexBTerrain, terrainTypeExpansion;
switch(currentCommand.getCommandType()){
case ROTATE_TILE : rotate();
break;
case PLACE_TILE :
x = currentCommand.getX();
y = currentCommand.getY();
z = currentCommand.getZ();
orientation = currentCommand.getOrientation();
hexATerrain = currentCommand.getHexATerrain();
hexBTerrain = currentCommand.getHexBTerrain();
try{
placeTile(x, y, z, orientation, hexATerrain, hexBTerrain);
}catch (InvalidMoveException e){
endGame();
}
break;
case FOUND_SETTLEMENT :
x = currentCommand.getX();
y = currentCommand.getY();
z = currentCommand.getZ();
try {
foundSettlement(x, y, z);
} catch (InvalidMoveException e) {
endGame();
}
break;
case PLACE_TOTORO :
x = currentCommand.getX();
y = currentCommand.getY();
z = currentCommand.getZ();
try {
placeTotoro(x, y, z);
} catch (InvalidMoveException e) {
endGame();
}
break;
case PLACE_TIGER :
x = currentCommand.getX();
y = currentCommand.getY();
z = currentCommand.getZ();
try {
placeTiger(x, y, z);
} catch (InvalidMoveException e) {
endGame();
}
break;
case EXPAND_SETTLEMENT :
x = currentCommand.getX();
y = currentCommand.getY();
z = currentCommand.getZ();
terrainTypeExpansion = currentCommand.getTerrainTypeExpansion();
try {
expandSettlement(x, y, z, terrainTypeExpansion);
} catch (InvalidMoveException e) {
endGame();
}
break;
}
}
private void checkEndGameConditions(){
if(whitePlayer.hasNoPiecesLeft()){
winner = whitePlayer;
endGame();
}
else if(blackPlayer.hasNoPiecesLeft()){
winner = blackPlayer;
endGame();
}
else if(whitePlayer.hasOnlyOneTypeOfPieceLeft()){
winner = whitePlayer;
endGame();
}
else if(blackPlayer.hasOnlyOneTypeOfPieceLeft()){
winner = blackPlayer;
endGame();
}
else if(actions.getBoard().getNumberOfTilesOnBoard() > 48){
calculateWinnerByScore();
endGame();
}
}
private boolean commandIsInQueue(){
try {
if (GameData.getIncomingMessages().peek().getGameID().equals(null)) {
return false;
} else if (GameData.getIncomingMessages().peek().getGameID().equals(gameID)) {
return true;
} else {
return false;
}
}
catch (Exception e) {System.out.println("Error in commandIsInQueue() method..");}
return false;
}
public void setCurrentCommand(Command command){
currentCommand = command;
movesTaken++;
}
public void endGame(){
System.out.println("end of: " + gameID);
gameOver = true;
//SEND END GAME MESSAGE
}
protected void forfeit(Player player){
if(player.getPlayerSide() == PlayerSide.BLACK){
winner = whitePlayer;
}
else{
winner = blackPlayer;
}
//SEND FORFEIT MESSAGE
}
public void calculateWinnerByScore(){
if(whitePlayer.getScore() > blackPlayer.getScore()){
winner = whitePlayer;
}
else if(blackPlayer.getScore() > whitePlayer.getScore()){
winner = blackPlayer;
}
else{
if(whitePlayer.getTotoroAvailable() > blackPlayer.getTotoroAvailable()){
winner = blackPlayer;
}
else if(blackPlayer.getTotoroAvailable() > whitePlayer.getTotoroAvailable()){
winner = whitePlayer;
}
else if(whitePlayer.getTigerAvailable() > blackPlayer.getTigerAvailable()){
winner = blackPlayer;
}
else if(whitePlayer.getTigerAvailable() < blackPlayer.getTigerAvailable()){
winner = whitePlayer;
}
}
}
public static Location convertCoordinates(int x, int y, int z){
return new Location(x + 100, z + 100);
}
public void rotate(){
actions.invertTile();
actions.rotateTile();
actions.rotateTile();
if(actions.getCurrentTile().getOrientation() == 6) actions.getCurrentTile().setOrientation(1);
else{
int temp = actions.getCurrentTile().getOrientation() + 1;
actions.getCurrentTile().setOrientation(temp);
}
}
public void placeTile(int x, int y, int z, int orientation, TerrainType terrainTypeA, TerrainType terrainTypeB) throws InvalidMoveException {
Location coord = null;
switch(orientation) {
case 1:
actions.setCurrentTile(new Tile(new Hex(TerrainType.VOLCANO), new Hex(terrainTypeA), new Hex(terrainTypeB)));
actions.invertTile();
actions.getCurrentTile().setOrientation(1);
coord = convertCoordinates(x, y, z);
break;
case 2:
actions.setCurrentTile(new Tile(new Hex(terrainTypeA), new Hex(terrainTypeB), new Hex(TerrainType.VOLCANO)));
actions.getCurrentTile().setOrientation(2);
coord = convertCoordinates(x + 1, y, z - 1);
break;
case 3:
actions.setCurrentTile(new Tile(new Hex(terrainTypeB), new Hex(TerrainType.VOLCANO), new Hex(terrainTypeA)));
actions.invertTile();
actions.getCurrentTile().setOrientation(3);
coord = convertCoordinates(x, y, z + 1);
break;
case 4:
actions.setCurrentTile(new Tile(new Hex(TerrainType.VOLCANO), new Hex(terrainTypeA), new Hex(terrainTypeB)));
actions.getCurrentTile().setOrientation(4);
coord = convertCoordinates(x, y, z);
break;
case 5:
actions.setCurrentTile(new Tile(new Hex(terrainTypeA), new Hex(terrainTypeB), new Hex(TerrainType.VOLCANO)));
actions.invertTile();
actions.getCurrentTile().setOrientation(5);
coord = convertCoordinates(x - 1, y, z + 1);
break;
case 6:
actions.setCurrentTile(new Tile(new Hex(terrainTypeB), new Hex(TerrainType.VOLCANO), new Hex(terrainTypeA)));
actions.getCurrentTile().setOrientation(6);
coord = convertCoordinates(x, y, z - 1);
break;
default:
throw new InvalidMoveException("Invalid Orientation", 20);
}
actions.placeTile(coord);
}
public void foundSettlement(int x, int y, int z) throws InvalidMoveException {
Location coord = convertCoordinates(x, y, z);
actions.foundSettlement(coord);
}
public void placeTotoro(int x, int y, int z) throws InvalidMoveException {
Location coord = convertCoordinates(x, y, z);
actions.placeTotoro(coord);
}
public void placeTiger(int x, int y, int z) throws InvalidMoveException {
Location coord = convertCoordinates(x, y, z);
actions.placeTiger(coord);
}
public void expandSettlement(int x, int y, int z, TerrainType terrainType) throws InvalidMoveException {
Location coord = convertCoordinates(x, y, z);
actions.expandSettlement(coord, terrainType);
}
public void cyclePlayerTurn(){
if(actions.getCurrentPlayer() == whitePlayer){
actions.setCurrentPlayer(blackPlayer);
}
else{
actions.setCurrentPlayer(whitePlayer);
}
}
// deletes the current list of settlements and then re-merges each and adds them to a new list
public void mergeAllSettlement()
{
// error if no settlements are on the board
if(SettlementList.isEmpty()) return; //error?
// create a list of Hex to be filled with Settled Hexes
SettledHexes = new ArrayList<Hex>();
for(int i=0; i<SettlementList.size(); i++)
{
for (int j=0; j<SettlementList.get(i).getSize(); j++)
{
SettledHexes.add(SettlementList.get(i).getHexInSettlementList().get(j));
}
}
// Create a new SettlementList, deletes the old one
SettlementList = new ArrayList<Settlement>();
// Create a array of bool to check if that hex has been merged already
boolean[] isChecked = new boolean[SettledHexes.size()];
for (int i=0; i<SettledHexes.size(); i++)
{
if(isChecked[i] == false)
{
isChecked[i] = true;
SettledHexes.get(i).setParentSettlement(new Settlement());
SettledHexes.get(i).getParentSettlement().addSettlement(SettledHexes.get(i));
merger(SettledHexes, isChecked, i);
}
}
}
public void merger( ArrayList<Hex> SettledHexes, boolean[] isChecked, int current_position)
{
for (int j = 0; j < SettledHexes.size(); j++) {
if (isChecked[j]) continue;
Hex start_point = SettledHexes.get(current_position);
Hex possible_adj = SettledHexes.get(j);
Location location_start = start_point.getLocationOfHex();
Location location_possAdj = possible_adj.getLocationOfHex();
if ((location_possAdj.getX() == location_start.getX() && location_possAdj.getY() == (location_start.getY() - 1))
|| (location_possAdj.getX() == (location_start.getX() + 1) && location_possAdj.getY() == (location_start.getY() - 1))
|| (location_possAdj.getX() == (location_start.getX() + 1) && location_possAdj.getY() == location_start.getY())
|| (location_possAdj.getX() == location_start.getX() && location_possAdj.getY() == (location_start.getY() + 1))
|| (location_possAdj.getX() == (location_start.getX() - 1) && location_possAdj.getY() == (location_start.getY() + 1))
|| (location_possAdj.getX() == (location_start.getX() - 1) && location_possAdj.getY() == location_start.getY()))
{
if(start_point.getOwner() == possible_adj.getOwner())
{
isChecked[j] = true;
SettlementList.get(SettlementList.size() - 1).addSettlement(SettledHexes.get(j));
merger(SettledHexes, isChecked, j);
}
}
}
return;
}
public Actions getActions(){
return actions;
}
public Player getWhitePlayer(){
return whitePlayer;
}
public Player getBlackPlayer(){
return blackPlayer;
}
public void setGameID(String gid){
gameID = gid;
}
public String getGameID(){
return gameID;
}
public Command getCurrentCommand(){
return currentCommand;
}
public boolean isGameOver(){
return gameOver;
}
public Player getWinner(){
return winner;
}
public ArrayList<Settlement> getSettlementList(){
return SettlementList;
}
public ArrayList<Hex> getSettledHexes(){
return SettledHexes;
}
}
public class Settlement {
private ArrayList<Hex> HexInSettlementList;
private int size;
private boolean hasTotoro;
private boolean hasTiger;
private Game parentGame;
public Settlement(){
if(Thread.currentThread().getName() == null){
parentGame = new Game(" ");
}
else if(Thread.currentThread().getName() == GameData.getGameOne().getGameID() ){
parentGame = GameData.getGameOne();
}
else if(Thread.currentThread().getName() == GameData.getGameTwo().getGameID()){
parentGame = GameData.getGameTwo();
}
else {
parentGame = new Game(" ");
}
parentGame.getSettlementList().add(this);
HexInSettlementList = new ArrayList<Hex>();
size = 0;
hasTotoro = false;
hasTiger = false;
}
public void addSettlement(Hex hex){
hex.setParentSettlement(this);
this.HexInSettlementList.add(hex);
if(hex.hasTotoro()) this.hasTotoro = true;
if(hex.hasTiger()) this.hasTiger = true;
this.size++;
}
public static void removeSettlement(Hex hex){
if(hex.isSettled())
{
hex.getParentSettlement().size--;
hex.getParentSettlement().getHexInSettlementList().remove(hex);
}
else return; //error?
}
// These set functions are used for testing purposes
public int setSize(int size){ return this.size = size; }
public boolean setHasTotoro(boolean hasTotoro) { return this.hasTotoro = hasTotoro; }
public boolean setHasTiger(boolean hasTiger) { return this.hasTiger = hasTiger; }
public int getSize(){ return size; }
public boolean getHasTotoro() { return hasTotoro; }
public boolean getHasTiger() { return hasTiger; }
public ArrayList<Hex> getHexInSettlementList() { return HexInSettlementList; }
}