TournamentController.java
package soen6441riskgame.controllers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import de.vandermeer.asciitable.AsciiTable;
import soen6441riskgame.App;
import soen6441riskgame.enums.GamePhase;
import soen6441riskgame.enums.StrategyName;
import soen6441riskgame.models.Boundary;
import soen6441riskgame.models.ModelCommands;
import soen6441riskgame.models.Player;
import soen6441riskgame.models.commands.GameCommands;
import soen6441riskgame.models.commands.MapEditorCommands;
import soen6441riskgame.models.commands.TournamentCommands;
import soen6441riskgame.models.strategies.Strategy;
import soen6441riskgame.singleton.GameBoard;
import soen6441riskgame.utils.ConsolePrinter;
import soen6441riskgame.utils.GameHelper;
import soen6441riskgame.utils.Parser;
/**
* The tournament should proceed without any user interaction and show the results of the tournament
* at the end. Both the phase view and player domination view should be enabled in tournament mode.
*
* A tournament starts with the user choosing
*
* M = 1 to 5 different maps
*
* P = 2 to 4 different computer players strategies
*
* G = 1 to 5 games to be played on each map
*
* D = 10 to 50 maximum number of turns for each game.
*
* A tournament is then automatically played by playing G games on each of the M different maps
* between the chosen computer player strategies. In order to minimize run completion time, each
* game should be declared a draw after D turns. Once started, the tournament plays all the games
* automatically without user interaction. At the end of the tournament, a report of the results
* should be displayed, e.g.
*
* M: Map1, Map2, Map3
*
* P: Aggressive, Benevolent, Random, Cheater.
*
* G: 4
*
* D: 30
*
* <table summary="sample result">
* <tr>
* <th></th>
* <th>Game 1</th>
* <th>Game 2</th>
* <th>Game 3</th>
* <th>Game 4</th>
* </tr>
* <tr>
* <td>Map 1</td>
* <td>Aggressive</td>
* <td>Random</td>
* <td>Cheater</td>
* <td>Cheater</td>
* </tr>
* <tr>
* <td>Map 2</td>
* <td>Cheater</td>
* <td>Draw</td>
* <td>Cheater</td>
* <td>Aggressive</td>
* </tr>
* <tr>
* <td>Map 3</td>
* <td>Cheater</td>
* <td>Aggressive</td>
* <td>Cheater</td>
* <td>Draw</td>
* </tr>
* </table>
*/
public class TournamentController {
public static final Boundary mapBoundary = new Boundary(1, 6);
public static final Boundary strategyBoundary = new Boundary(2, 4);
public static final Boundary numberOfGameBoundary = new Boundary(1, 5);
public static final Boundary maxNumberOfTurnBoundary = new Boundary(10, 50);
private Strategy[] strategies;
private String[] maps;
private int numberOfGame;
private int maxNumberOfTurn;
private GameController gameController;
/**
* because of ModelCommands logic, this function have to do extra work to take the correct argument
* for each parameter
*
* @param args tournament's parameters
*/
public void enterTournament(List<String> args) {
String[] parameters = new String[args.size()];
parameters = args.toArray(parameters);
parseTournamentParameters(parameters);
String[][] results = new String[numberOfGame][maps.length];
if (isTournamentValid()) {
gameController = new GameController();
for (int gameIndex = 0; gameIndex < numberOfGame; gameIndex++) {
for (int mapIndex = 0; mapIndex < maps.length; mapIndex++) {
Player winner = simulateGamePlay(maps[mapIndex]);
if (winner == null) {
results[gameIndex][mapIndex] = "DRAW";
} else {
results[gameIndex][mapIndex] = winner.getName();
}
}
}
ConsolePrinter.printFormat(getGamePlayResultAsTable(results));
} else {
ConsolePrinter.printFormat("Parameter invalid");
}
}
/**
* convert the game play results to a table-like string
*
* @param results game play results
* @return printable string
*/
private String getGamePlayResultAsTable(String[][] results) {
AsciiTable table = new AsciiTable();
ArrayList<String> mapHeaders = new ArrayList<String>(Arrays.asList(maps));
mapHeaders.add(0, "");
table.addRule();
table.addRow(mapHeaders);
int gameIndex = 1;
for (String[] row : results) {
table.addRule();
ArrayList<String> gameResultsWithColumn = new ArrayList<String>(Arrays.asList(row));
gameResultsWithColumn.add(0, "Game " + gameIndex);
table.addRow(gameResultsWithColumn);
gameIndex++;
}
table.addRule();
return table.render();
}
/**
* simulate a game play
*
* @param map map to play
* @return the winner of this game
*/
private Player simulateGamePlay(String map) {
GameBoard.getInstance().reset();
App.jumpToCommand(new ModelCommands(MapEditorCommands.LOADMAP + " " + map));
initializePlayers();
App.jumpToCommand(new ModelCommands(GameCommands.POPULATECOUNTRIES));
App.jumpToCommand(new ModelCommands(GameCommands.PLACEALL));
// get first player
Player currentPlayer = gameController.getCurrentPlayer();
for (int turnPlayed = 0; turnPlayed < maxNumberOfTurn; turnPlayed++) {
currentPlayer.getStrategy().playTurn(currentPlayer);
if (currentPlayer.getCurrentPhase() == GamePhase.END_OF_GAME) {
return currentPlayer;
}
currentPlayer = gameController.getCurrentPlayer();
}
return null;
}
/**
* init players with strategy
*/
private void initializePlayers() {
StringBuilder addPlayerCommand = new StringBuilder(GameCommands.GAMEPLAYER + " ");
for (Strategy strategy : strategies) {
addPlayerCommand.append("-add ")
.append(strategy.getName().toString())
.append(" ");
}
App.jumpToCommand(new ModelCommands(addPlayerCommand.toString()));
for (Player player : GameBoard.getInstance().getGameBoardPlayer().getPlayers()) {
player.setStrategy(StrategyName.fromString(player.getName()));
}
}
/**
* parse tournament parameters
*
* @param args tournament parameters
*/
private void parseTournamentParameters(String[] args) {
for (int index = 0; index < args.length; index = index + 2) {
switch (args[index]) {
case TournamentCommands.TOURNAMENT_MAP_LIST: {
maps = args[index + 1].split(",");
break;
}
case TournamentCommands.TOURNAMENT_PLAYER_STRATEGY_LIST: {
String[] playerStrategies = args[index + 1].split(",");
ArrayList<Strategy> parsedStrategies = parsePlayerStrategies(playerStrategies);
strategies = new Strategy[parsedStrategies.size()];
strategies = parsedStrategies.toArray(strategies);
break;
}
case TournamentCommands.TOURNAMENT_NUMBER_OF_GAME: {
numberOfGame = Parser.parseWithDefault(args[index + 1], 0);
break;
}
case TournamentCommands.TOURNAMENT_MAX_NUMBER_OF_TURN: {
maxNumberOfTurn = Parser.parseWithDefault(args[index + 1], 0);
break;
}
}
}
}
/**
* parse player's strategies
*
* @param playerStrategies player's strategies
* @return a list of strategy
*/
private ArrayList<Strategy> parsePlayerStrategies(String[] playerStrategies) {
ArrayList<Strategy> strategies = new ArrayList<Strategy>();
for (String strategy : playerStrategies) {
Strategy parsed = StrategyName.fromString(strategy);
if (parsed != null) {
strategies.add(parsed);
}
}
return strategies;
}
/**
* M = 1 to 5 different maps
*
* @return is maps array valid
*/
private boolean isMapsValid() {
if (mapBoundary.isInBoundary(maps.length, true)) {
return GameHelper.countDistinct(maps) == maps.length;
}
return false;
}
/**
* P = 2 to 4 different computer players strategies
*
* @return is strategies valid
*/
private boolean isStrategiesValid() {
StrategyName[] strategyNames = new StrategyName[strategies.length];
for (int i = 0; i < strategies.length; i++) {
strategyNames[i] = strategies[i].getName();
}
if (strategyBoundary.isInBoundary(strategies.length, true)) {
return GameHelper.countDistinct(strategyNames) == strategies.length;
}
return false;
}
/**
* M = 1 to 5 different maps
*
* P = 2 to 4 different computer players strategies
*
* G = 1 to 5 games to be played on each map
*
* D = 10 to 50 maximum number of turns for each game.
*/
private boolean isTournamentValid() {
return isMapsValid()
&& isStrategiesValid()
&& numberOfGameBoundary.isInBoundary(numberOfGame, true)
&& maxNumberOfTurnBoundary.isInBoundary(maxNumberOfTurn, true);
}
}