MapController.java
package soen6441riskgame.controllers;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import soen6441riskgame.enums.CommonCommandArgs;
import soen6441riskgame.models.Continent;
import soen6441riskgame.models.Coordinate;
import soen6441riskgame.models.Country;
import soen6441riskgame.singleton.GameBoard;
import soen6441riskgame.utils.ConsolePrinter;
import soen6441riskgame.utils.GraphChecker;
import soen6441riskgame.utils.map.ConquestMapReadable;
import soen6441riskgame.utils.map.DominationMapReadable;
import soen6441riskgame.utils.map.MapReaderAdapter;
/**
* handle the operations to generate, edit and control the map.
*/
public final class MapController {
private static final int MINIMUM_AMOUNT_OF_COUNTRIES = 6;
private DominationMapReadable dominationMapReader = new MapReaderAdapter();
private ConquestMapReadable conquestMapReader = new MapReaderAdapter();
/**
* load the map from file
*
* @param fileName path to file
* @param isConquestMapType is this file a 'conquest' map type
* @throws IOException if file not found or cannot read
*/
public void loadMap(String fileName, boolean isConquestMapType) throws IOException {
if (isConquestMapType) {
conquestMapReader.loadConquestMap(fileName);
} else {
dominationMapReader.loadMap(fileName);
}
}
/**
* load the map from file in domination type
*
* @param fileName path to file
* @throws IOException if file not found or cannot read
*/
public void loadMap(String fileName) throws IOException {
loadMap(fileName, false);
}
/**
* add continent to game
*
* @param continentName name of the continent
* @param continentValue army rewarded to player if he conquered this continent
* @param order order of the continent in the file
*/
public void addContinent(String continentName, String continentValue, int... order) {
dominationMapReader.addContinent(continentName, continentValue, order);
}
/**
* add new country to an existed continent OR add existing country to an existed continent
*
* @param countryName the new country name
* @param continentName the existed continent name
*/
public void addCountry(String countryName, String continentName) {
Continent continent = GameBoard.getInstance().getGameBoardMap().getContinentFromName(continentName);
Country country = GameBoard.getInstance().getGameBoardMap().getCountryFromName(countryName);
if (continent == null) {
ConsolePrinter.printFormat("Continent %s is not existed", continentName);
return;
}
if (country == null) {
createNewCountry(countryName, continent);
} else {
continent.getCountries().add(country);
}
ConsolePrinter.printFormat("Country %s is added to continent %s", countryName, continentName);
}
/**
* connect 2 countries with each other on the borderGraph
*
* @param countryName name of the country
* @param neighborCountryName name of the neighbor country
*/
public void addNeighbor(String countryName, String neighborCountryName) {
Country country = GameBoard.getInstance().getGameBoardMap().getCountryFromName(countryName);
Country neighbor = GameBoard.getInstance().getGameBoardMap().getCountryFromName(neighborCountryName);
if (country == null || neighbor == null) {
ConsolePrinter.printFormat("The country name or neighbor country name is not existed!");
return;
}
dominationMapReader.addBorders(country.getOrder(), neighbor.getOrder());
}
/**
* create new country, add it to the borderGraph
*
* @param countryName name of the country
* @param continent the name of continent that country belong to
*/
public void createNewCountry(String countryName, Continent continent) {
if (GameBoard.getInstance().getGameBoardMap().getCountryFromName(countryName) != null) {
return;
}
int newBorderSize = GameBoard.getInstance().getGameBoardMap().getCountries().size() + 1;
Country newCountry = new Country(newBorderSize, countryName, new Coordinate(0, 0), continent);
increaseBorder(newBorderSize);
GameBoard.getInstance().getGameBoardMap().updateCountryContinent(newCountry, continent);
ConsolePrinter.printFormat("Country %s is created", countryName);
}
/**
* increase border
*
* @param newBorderSize location of the border to insert
*/
private void increaseBorder(int newBorderSize) {
int[][] originalBorder = GameBoard.getInstance().getGameBoardMap().getBorders();
int[][] newBorders = new int[newBorderSize][newBorderSize];
for (int row = 0; row < newBorderSize - 1; row++) {
newBorders[row] = Arrays.copyOf(originalBorder[row], newBorderSize);
newBorders[newBorderSize - 1][row] = 0;
}
for (int col = 0; col < newBorderSize; col++) {
newBorders[newBorderSize - 1][col] = 0;
}
GameBoard.getInstance().getGameBoardMap().setBorders(newBorders);
}
/**
* handle 'editcontient' command from console
*
* @param args -add continentName continentValue -remove continentName
*/
public void editContinent(String[] args) {
CommonCommandArgs continentCommand = CommonCommandArgs.fromString(args[0]);
switch (continentCommand) {
case ADD: {
dominationMapReader.addContinent(args[1], args[2]);
break;
}
case REMOVE: {
removeContinent(args[1]);
break;
}
case INVALID:
case NONE: {
ConsolePrinter.printFormat("Incorrect command");
break;
}
}
}
/**
* handle 'editcountry' command
*
* @param args -add countryName continentName -remove countryName
*/
public void editCountry(String[] args) {
CommonCommandArgs countryCommand = CommonCommandArgs.fromString(args[0]);
switch (countryCommand) {
case ADD: {
addCountry(args[1], args[2]);
break;
}
case REMOVE: {
removeCountry(args[1]);
break;
}
case INVALID:
case NONE: {
ConsolePrinter.printFormat("Incorrect command");
break;
}
}
}
/**
* edit an existing map from file
*
* @param fileName the map file
* @throws IOException exception
*/
public void editMap(String fileName) throws IOException {
try {
dominationMapReader.loadMap(fileName);
} catch (IOException e) {
// file not existed. Create new map
saveMap(fileName);
}
}
/**
* save the map to a file
*
* @param fileName path to file
* @param isConquestMapType true to save map as conquest map type
* @throws IOException exception
*/
public void saveMap(String fileName, boolean isConquestMapType) throws IOException {
if (!isMapValid()) {
ConsolePrinter.printFormat("Invalid map. Map not saved");
return;
}
if (isConquestMapType) {
conquestMapReader.writeMapToConquestFile(fileName);
} else {
dominationMapReader.writeMapToFile(fileName);
}
}
/**
* save the map to a file
*
* @param fileName path to file
* @throws IOException exception
*/
public void saveMap(String fileName) throws IOException {
saveMap(fileName, false);
}
/**
* handle 'editneighbor' command
*
* @param args -add countryName neighborCountryName -remove countryName neighborCountryName
*/
public void editNeighbor(String[] args) {
CommonCommandArgs neighborCommand = CommonCommandArgs.fromString(args[0]);
switch (neighborCommand) {
case ADD: {
addNeighbor(args[1], args[2]);
break;
}
case REMOVE: {
removeNeighbor(args[1], args[2]);
break;
}
case INVALID:
case NONE: {
ConsolePrinter.printFormat("Incorrect command");
break;
}
}
}
/**
* get all continents that have no country
*
* @return a list of empty continent, or an empty list if all continent have countries inside
*/
private ArrayList<Continent> getEmptyContinents() {
ArrayList<Continent> result = new ArrayList<Continent>();
for (Continent continent : GameBoard.getInstance().getGameBoardMap().getContinents()) {
if (continent.getCountries().size() == 0) {
result.add(continent);
}
}
return result;
}
/**
* get countries that not connected to any other countries
*
* @return a list of isolated country, or an empty list if all country is connected
*/
private ArrayList<Country> getIsolatedCountries() {
int[][] borders = GameBoard.getInstance().getGameBoardMap().getBorders();
int borderSize = borders[0].length;
ArrayList<Country> result = new ArrayList<Country>();
for (int row = 0; row < borderSize; row++) {
int rowSum = 0;
for (int col = 0; col < borderSize; col++) {
rowSum += borders[row][col];
}
if (rowSum == 0) {
result.add(GameBoard.getInstance().getGameBoardMap().getCountries().get(row));
}
}
return result;
}
/**
* check if the number of country is lower than the minimum amount of country required currently the
* minimum required is {@MINIMUM_AMOUNT_OF_COUNTRIES}
*
* @return false if the number of country is lower than the minimum amount of country required
*/
private boolean isNotEnoughCountries() {
int numberOfCountry = GameBoard.getInstance().getGameBoardMap().getCountries().size();
boolean isNotEnoughCountries = numberOfCountry < MapController.MINIMUM_AMOUNT_OF_COUNTRIES;
if (isNotEnoughCountries) {
ConsolePrinter.printFormat("Not enough countries. Created: %d - Minimum required: %s",
numberOfCountry,
MapController.MINIMUM_AMOUNT_OF_COUNTRIES);
}
return isNotEnoughCountries;
}
/**
* Remove a continent from map. Remove continent will make all country inside that continent
* invalid, thus make the map invalid.
*
* @param continentName name of the continent
*/
public void removeContinent(String continentName) {
ConsolePrinter.printFormat("Remove continent will remove all country inside that continent");
Continent continentToRemove = GameBoard.getInstance().getGameBoardMap().getContinentFromName(continentName);
if (continentToRemove != null) {
String[] countriesToRemove = new String[continentToRemove.getCountries().size()];
for (int index = 0; index < countriesToRemove.length; index++) {
countriesToRemove[index] = continentToRemove.getCountries().get(index).getName();
}
for (String country : countriesToRemove) {
removeCountry(country);
}
GameBoard.getInstance()
.getGameBoardMap()
.getContinents()
.remove(continentToRemove);
ConsolePrinter.printFormat("Continent %s is removed", continentToRemove.getName());
} else {
ConsolePrinter.printFormat("Continent %s is not existed", continentName);
}
}
/**
* remove a country from map, this including remove it border info and remove it from continent
*
* @param countryName name of the country to remove
*/
public void removeCountry(String countryName) {
Country country = GameBoard.getInstance().getGameBoardMap().getCountryFromName(countryName);
if (country == null) {
ConsolePrinter.printFormat("Country %s is not existed", countryName);
return;
}
// Remove it border
int countryOrder = country.getOrder();
removeBorder(countryOrder - 1);
// Remove it from continent
country.getContinent().getCountries().remove(country);
// Remove it from list country
GameBoard.getInstance().getGameBoardMap().getCountries().remove(country);
}
/**
* Remove border
*
* @param borderLocation location of the border to remove
*/
private void removeBorder(int borderLocation) {
int[][] originalBorder = GameBoard.getInstance().getGameBoardMap().getBorders();
int size = originalBorder[0].length - 1;
int[][] newBorders = new int[size][size];
for (int row = 0; row < borderLocation; row++) {
for (int col = 0; col < borderLocation; col++) {
newBorders[row][col] = originalBorder[row][col];
}
}
for (int row = size - 1; row >= borderLocation; row--) {
for (int col = size - 1; col >= borderLocation; col--) {
newBorders[row][col] = originalBorder[row + 1][col + 1];
}
}
GameBoard.getInstance().getGameBoardMap().setBorders(newBorders);
}
/**
* remove connection between 2 countries in the borderGraph
*
* @param countryName name of the country
* @param neighborCountryName name of the neighbor country
*/
public void removeNeighbor(String countryName, String neighborCountryName) {
Country country = GameBoard.getInstance().getGameBoardMap().getCountryFromName(countryName);
Country neighbor = GameBoard.getInstance().getGameBoardMap().getCountryFromName(neighborCountryName);
if (country == null || neighbor == null) {
ConsolePrinter.printFormat("One or both countries is not existed");
return;
}
GameBoard.getInstance().getGameBoardMap().getBorders()[country.getOrder() - 1][neighbor.getOrder() - 1] = 0;
GameBoard.getInstance().getGameBoardMap().getBorders()[country.getOrder() - 1][neighbor.getOrder() - 1] = 0;
}
/**
* Display all continents and it's countries to console
*/
public void showMap() {
GameBoard.getInstance().getGameBoardMap().showContinents();
}
/**
* get the country that not belong to any continent
*
* @return list of countries
*/
private ArrayList<Country> getCountriesHaveNoContinent() {
ArrayList<Country> countriesWithNoContinent = new ArrayList<Country>();
ArrayList<Country> countries = GameBoard.getInstance().getGameBoardMap().getCountries();
for (Country country : countries) {
if (country.getContinent() == null) {
countriesWithNoContinent.add(country);
}
}
return countriesWithNoContinent;
}
/**
* validate the map Types of errors: 1. less than 6 countries 2. some countries are isolated from
* the rest 3. empty continents 4. one country is linked to another but no link back There is no
* need to check for the last one, because not happened in our implementation
*
* @return is map valid or not
*/
public boolean isMapValid() {
if (isNotEnoughCountries()) {
return false;
}
ArrayList<Country> isolatedCountries = getIsolatedCountries();
boolean isIsolatedCountryExisted = isolatedCountries.size() > 0;
ArrayList<Continent> emptyContinents = getEmptyContinents();
boolean isEmptyContinentExisted = emptyContinents.size() > 0;
ArrayList<Country> countriesWithNoContinent = getCountriesHaveNoContinent();
boolean isCountryWithNoContinentExisted = countriesWithNoContinent.size() > 0;
if (isIsolatedCountryExisted) {
ConsolePrinter.printFormat("Isolated countries existed:");
for (Country country : isolatedCountries) {
country.view(1);
}
}
if (isEmptyContinentExisted) {
ConsolePrinter.printFormat("Empty continent existed:");
for (Continent continent : emptyContinents) {
continent.view(1);
}
}
if (isCountryWithNoContinentExisted) {
ConsolePrinter.printFormat("Country that not belong to any continent existed:");
for (Country country : countriesWithNoContinent) {
country.viewWithoutNeighbors(1);
}
}
// check if country in continents are connected
boolean isCountriesInContinentConnected = true;
ArrayList<Continent> continents = GameBoard.getInstance().getGameBoardMap().getContinents();
for (Continent continent : continents) {
if (!continent.isContinentConnected()) {
isCountriesInContinentConnected = false;
break;
}
}
boolean isMapConnected = GraphChecker.isCountriesConnected(GameBoard.getInstance()
.getGameBoardMap()
.getCountries());
return !isIsolatedCountryExisted
&& !isEmptyContinentExisted
&& !isCountryWithNoContinentExisted
&& isCountriesInContinentConnected
&& isMapConnected;
}
/**
* handle the map validation command
*/
public void validateMap() {
if (isMapValid()) {
ConsolePrinter.printFormat("Map valid");
} else {
ConsolePrinter.printFormat("Invalid map");
}
}
}