package gameParts;
import gameParts.Tile.TileType;
import java.io.Serializable;
import java.util.*;
import rmi.server.IGameServer.GameState;
public class Board implements Serializable, Cloneable {
private static final long serialVersionUID = 9092555974770706967L;
private List<Tile> mTiles = new ArrayList<Tile>(BoardUtils.sTilesAmount);
private int mThiefIndex;
private Map<Integer, Settlement> mSettlements = new HashMap<Integer, Settlement>();
private Map<String, Road> mRoads = new HashMap<String, Road>();
private Map<Integer, City> mCities = new HashMap<Integer, City>();
/**
* default ctor calls constructor that shuffles
*/
public Board()
{
this(true);
}
/**
* Ctor, creates a new board with random tile placements
*/
public Board(boolean isShuffle) {
// add new tiles by the proper amount and predefined order
TileType[] firstTiles = {TileType.MOUNTAIN,
TileType.FIELD, TileType.FOREST, TileType.MOUNTAIN,
TileType.FIELD, TileType.MEADOW, TileType.FIELD,
TileType.MEADOW, TileType.FOREST, TileType.HILL,
TileType.DESERT, TileType.HILL, TileType.MEADOW,
TileType.MEADOW, TileType.FOREST, TileType.HILL,
TileType.MOUNTAIN, TileType.FOREST, TileType.FIELD};
for (TileType t : firstTiles)
{
mTiles.add(new Tile(t));
}
if (isShuffle)
{
// shuffle the tiles in the board to be placed randomly
shuffledBoard();
}
else {
int i = 0;
for (Tile t : mTiles)
{
t.setTileLetter((char)(i+'A'));
++i;
}
}
int i = 0;
// adding predefined dice numbers to the tiles
int[] diceNumbers = { 5, 2, 6, 3, 8, 10, 9, 12, 11, 4, 8, 10, 9, 4, 5, 6, 3, 11 };
for (Tile t : mTiles) {
if (t.getType() != Tile.TileType.DESERT) {
t.setDiceNum(diceNumbers[i]);
++i;
}
}
// set up the robber in the desert tile
moveRobber(getDesertTile());
}
@Override
public Object clone() throws CloneNotSupportedException {
Board clone = new Board();
// set thief
clone.mThiefIndex = mThiefIndex;
// add tiles
// they are randomly set when the board is created, so first clear the randomly generated ones
clone.mTiles.clear();
Iterator<Tile> tilesIter = mTiles.iterator();
while (tilesIter.hasNext()) {
clone.mTiles.add((Tile) tilesIter.next().clone());
}
// add settlements
Iterator<Integer> mySettlementsIter = mSettlements.keySet().iterator();
while (mySettlementsIter.hasNext()) {
Integer settlement = mySettlementsIter.next();
clone.mSettlements.put(settlement.intValue(), (Settlement) mSettlements.get(settlement).clone());
}
// add cities
Iterator<Integer> myCitiesIter = mCities.keySet().iterator();
while (myCitiesIter.hasNext()) {
Integer city = myCitiesIter.next();
clone.mCities.put(city.intValue(), (City) mCities.get(city).clone());
}
// add roads
Iterator<String> myRoadsIter = mRoads.keySet().iterator();
while (myRoadsIter.hasNext()) {
String road = myRoadsIter.next();
clone.mRoads.put(road + "", (Road) mRoads.get(road).clone());
}
return clone;
}
@Override
public boolean equals(Object obj) {
Board board = null;
try {
board = (Board) obj;
} catch (Exception e) {
return false;
}
if (
(board == null) ||
(mTiles.size() != board.mTiles.size()) ||
(mSettlements.size() != board.mSettlements.size()) ||
(mRoads.size() != board.mRoads.size()) ||
(mCities.size() != board.mCities.size())
) {
return false;
}
// check tiles
Iterator<Tile> myTilesIter = mTiles.iterator();
Iterator<Tile> compareTilesIter = board.mTiles.iterator();
while (myTilesIter.hasNext()) {
Tile my = myTilesIter.next();
Tile compare = compareTilesIter.next();
if (! my.equals(compare)) {
return false;
}
}
// check settlements
Iterator<Integer> mySettlementsIter = mSettlements.keySet().iterator();
Iterator<Integer> compareSettlementsIter = board.mSettlements.keySet().iterator();
while (mySettlementsIter.hasNext()) {
Integer my = mySettlementsIter.next();
Integer compare = compareSettlementsIter.next();
if (! mSettlements.get(my).equals(board.mSettlements.get(compare))) {
return false;
}
}
// check cities
Iterator<Integer> myCitiesIter = mCities.keySet().iterator();
Iterator<Integer> compareCitiesIter = board.mCities.keySet().iterator();
while (myCitiesIter.hasNext()) {
Integer my = myCitiesIter.next();
Integer compare = compareCitiesIter.next();
if (! mCities.get(my).equals(board.mCities.get(compare))) {
return false;
}
}
// check roads
Iterator<String> myRoadsIter = mRoads.keySet().iterator();
Iterator<String> compareRoadsIter = board.mRoads.keySet().iterator();
while (myRoadsIter.hasNext()) {
String my = myRoadsIter.next();
String compare = compareRoadsIter.next();
if (! mRoads.get(my).equals(board.mRoads.get(compare))) {
return false;
}
}
return true;
}
/**
* @return the mTiles
*/
public List<Tile> getTiles() {
return mTiles;
}
/**
* sets the tiles on the board randomly
*/
public void shuffledBoard() {
Collections.shuffle(mTiles);
// add tile letter to each tile
int i = 0;
for (Tile t : mTiles)
{
t.setTileLetter((char)(i+'A'));
++i;
}
}
/**
* @return the char representation of the robber's location
*/
public char getRobberLocation() {
return (char) (mThiefIndex + 65);
}
/**
* sets the robber location to the given tile
* @param tile - the char representation of the tile
* we want the robber to move to
*/
public void moveRobber(char tile) {
Character c = Character.toLowerCase(tile);
int index = Character.getNumericValue(c)
- Character.getNumericValue('a');
this.mThiefIndex = index;
}
/**
* @return the char representation of the tile in which the
* desert is placed
*/
public char getDesertTile() {
int desertIndex = 0;
int i = 0;
for (Tile t : mTiles) {
if (t.getType() == Tile.TileType.DESERT) {
desertIndex = i;
break;
}
++i;
}
return (char) (desertIndex + 65);
}
/**
* checks whether the robber can be moved to the given location
* @param i - the enumeration of the tile to be checked
* @return true iff the robber isn't already in the given location.
*/
public boolean canMoveThief(int i) {
if (i == getRobberLocation()) {
return false;
}
return true;
}
/**
* adds a settlement belonging to the given player
* on the given corner
* @param player
* @param tile
* @param corner
* @precondition - canAddSettlement(player, corner, GameState)
*/
public void addSettlement(int player, Integer corner) {
mSettlements.put(corner, new Settlement(player, corner));
}
/**
* gets a settlement in the given corner
* @param corner
* @return the settlement if exists or null if the corner has
* no settlement.
*/
public Settlement getSettlement(Integer corner) {
return mSettlements.get(corner);
}
/**
* add road for given player between the to given corners
* @param player
* @param tile
* @param corner1
* @param corner2
* @precondition - canAddRoad(player, corner1, corner2)
*/
public void addRoad(int player, Integer corner1, Integer corner2) {
String location = corner1 + ":" + corner2;
mRoads.put(location, new Road(player, corner1, corner2));
}
/**
* get road that exists between two given corners
* @param tile
* @param corner1
* @param corner2
* @return the road if exists or null if the location is empty
*/
public Road getRoad(Integer corner1, Integer corner2) {
Road result = mRoads.get(corner1 + ":" + corner2);
if (result == null) {
result = mRoads.get(corner2 + ":" + corner1);
}
return result;
}
/**
* add city in given location for the given player
* @param player
* @param corner
* @precondition - canAddCity(player, corner)
*/
public void addCity(int player, Integer corner) {
mCities.put(corner, new City(player, corner));
mSettlements.remove(corner);
}
/**
* gets city in given location
* @param corner
* @return the city if exists or null if no city exists in location
*/
public City getCity(Integer corner) {
return mCities.get(corner);
}
/**
* return the tile by the given char
* @param tile
* @return
* @precondition - tile < 'S'
*/
public Tile getTileByChar(char tile) {
Character c = Character.toLowerCase(tile);
int index = Character.getNumericValue(c)
- Character.getNumericValue('a');
return mTiles.get(index);
}
/**
*
*/
public String toString()
{
StringBuffer str = new StringBuffer();
str.append("Tiles:\n");
for (Tile t : mTiles) {
str.append(t.toString() + "\n");
}
str.append("Settlements:\n");
for (Integer k : mSettlements.keySet()) {
str.append("player: "
+ ((BasePart) mSettlements.get(k)).getPlayerID()
+ ", corner: " + k + "\n");
}
str.append("Cities:\n");
for (Integer k : mCities.keySet()) {
str.append("player: " + ((BasePart) mCities.get(k)).getPlayerID()
+ ", corner: " + k + "\n");
}
str.append("Roads:\n");
for (String k : mRoads.keySet()) {
str.append("player: " + ((BasePart) mRoads.get(k)).getPlayerID()
+ ", location: " + k + "\n");
}
str.append("Robber: " + this.getRobberLocation() + "\n");
return str.toString();
}
/**
* gets the tiles the have the dice number given in the roll
* @param roll
* @return list of tiles corresponding with the results
* @precondition - 2 < roll < 12
*/
public List<Tile> getDiceResult(int roll) {
List<Tile> result = new ArrayList<Tile>();
for (Tile t : mTiles)
{
if (t.getDiceNum() == roll)
{
result.add(t);
}
}
return result;
}
/**
* @param player - the ID of the player to check for
* @param corner - the number of the corner to check for
* @param state - the state of the game
* @return True iff player can build a settlement in corner when the game is in the given state
*/
public boolean canAddSettlement(int player, int corner, GameState state) {
if (! BoardUtils.cornerIsValid(corner)) {
return false;
}
if ((getSettlement(corner) != null) || (getCity(corner) != null)) {
return false;
}
for (int i=0; i<BoardUtils.getCornerNeighborsAmount(corner); ++i) {
if (getSettlement(BoardUtils.getCornerNeighbors(corner)[i]) != null) {
return false;
}
}
switch(state) {
case INIT: {
return true;
}
case INGAME: {
int[] neighbors = BoardUtils.getCornerNeighbors(corner);
for (int i=0; i<neighbors.length; ++i) {
Road road = getRoad(corner, neighbors[i]);
if ((road != null) && (road.getPlayerID() == player)) {
return true;
}
}
return false;
}
default: {
return false;
}
}
}
/**
* @param player - the ID of the player to check for
* @param corner - the number of the corner to check for
* @param state - the state of the game
* @return True iff player can build a city in corner when the game is in the given state
*/
public boolean canAddCity(int player, int corner, GameState state) {
if (state != GameState.INGAME) {
return false;
}
Settlement s = getSettlement(corner);
if ((s != null) && (player == s.getPlayerID())) {
return true;
}
return false;
}
/**
* @param player - the ID of the player to check for
* @param corner1 - the first side of the wanted road
* @param corner2 - the second side of the wanted road
* @param state - the state of the game
* @return True iff player can build a road between corner1 and corner2 when the game is in the given state
*/
public boolean canAddRoad(int player, int corner1, int corner2, GameState state) {
if (!BoardUtils.cornersAreNeighbors(corner1, corner2)) {
return false;
}
if (getRoad(corner1, corner2) != null) {
return false;
}
switch (state) {
case INIT: {
Settlement s1 = getSettlement(corner1);
Settlement s2 = getSettlement(corner2);
return (((s1 != null) && (s1.getPlayerID() == player)) || ((s2 != null) && (s2.getPlayerID() == player)));
}
case INGAME: {
return (cornerHasPlayerRoad(player, corner1) || cornerHasPlayerRoad(player, corner2));
}
default: {
return false;
}
}
}
private boolean cornerHasPlayerRoad(int player, int corner) {
int[] neighbors = BoardUtils.getCornerNeighbors(corner);
for (int i=0; i<neighbors.length; ++i) {
Road road = getRoad(corner, neighbors[i]);
if ((road != null) && (road.getPlayerID() == player)) {
return true;
}
}
return false;
}
}
|