package de.fhdw.gaming.ipspiel21.dilemmaOriginal.strategy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import de.fhdw.gaming.core.domain.GameException;
import de.fhdw.gaming.ipspiel21.dilemmaOriginal.domain.DilemmaPlayer;
import de.fhdw.gaming.ipspiel21.dilemmaOriginal.domain.DilemmaState;
import de.fhdw.gaming.ipspiel21.dilemmaOriginal.domain.DilemmaStrategy;
import de.fhdw.gaming.ipspiel21.dilemmaOriginal.moves.DilemmaMove;
import de.fhdw.gaming.ipspiel21.dilemmaOriginal.moves.impl.DilemmaBeSilentMove;
import de.fhdw.gaming.ipspiel21.dilemmaOriginal.moves.impl.DilemmaConfessMove;
/**
* Implements {@link DilemmaStrategy} by saying that what was set before the game started.
*/
public final class DilemmaCustomStrategy implements DilemmaStrategy {
/**
* Constant that represents the identifier when the opponent moves are {@link DilemmaConfessMove) for 100 percent.
*/
private static final String IDENTIFIER_100_CONFESS = new DilemmaConfessMove().toString() + " Numberbased100";
/**
* Constant that represents the identifier when the opponent moves are {@link DilemmaConfessMove) for >50 percent.
*/
private static final String IDENTIFIER_50_CONFESS = new DilemmaConfessMove().toString() + " Numberbased50";
/**
* Constant that represents the identifier when the opponent moves are {@link DilemmaBeSilentMove) for 100 percent.
*/
private static final String IDENTIFIER_100_BESILENT = new DilemmaBeSilentMove().toString() + " Numberbased100";
/**
* Constant that represents the identifier when the opponent moves are {@link DilemmaBeSilentMove) for >50 percent.
*/
private static final String IDENTIFIER_50_BESILENT = new DilemmaBeSilentMove().toString() + " Numberbased50";
/**
* The provided Data.
*/
private Map<String, DilemmaMove> providedMoveData;
/**
* Amount of considered games.
*/
private Integer amountOfGames;
/**
* Default move of player.
*/
private DilemmaMove initialMove;
/**
* Sets the provided moves.
*
* @param providedMoveData
*/
public void setProvidedMoveData(final Map<String, Object> providedMoveData) {
final Set<Entry<String, Object>> entrySet = providedMoveData.entrySet();
for (final Entry<String, Object> entry : entrySet) {
if (IDENTIFIER_100_BESILENT.equals(entry.getKey()) || IDENTIFIER_100_CONFESS.equals(entry.getKey())
|| IDENTIFIER_50_BESILENT.equals(entry.getKey()) || IDENTIFIER_50_CONFESS.equals(entry.getKey())) {
providedMoveData.put(entry.getKey(), (DilemmaMove) entry.getValue());
}
}
}
/**
* Returns the provided moves.
*
* @return provided moves.
*/
public Map<String, DilemmaMove> getProvidedMoveData() {
return providedMoveData;
}
/**
* Returns the amount of considered games.
*
* @return amount of considered games.
*/
public Integer getAmountOfGames() {
return amountOfGames;
}
/**
* Sets the amount of considered games.
*
* @param amountOfGames The amount of considered games.
*/
public void setAmountOfGames(final Integer amountOfGames) {
this.amountOfGames = amountOfGames;
}
/**
* Returns the initial move choice of the player.
*
* @return initial move.
*/
public DilemmaMove getInitialMove() {
return initialMove;
}
/**
* Sets the initial move.
*
* @param initialMove The initial move choice of the player
*/
public void setInitialMove(final DilemmaMove initialMove) {
this.initialMove = initialMove;
}
@Override
public Optional<DilemmaMove> computeNextMove(final int gameId, final DilemmaPlayer player,
final DilemmaState state)
throws GameException, InterruptedException {
if (providedMoveData.isEmpty()) {
return Optional.of(initialMove);
}
final List<DilemmaMove> opponentMoves = new ArrayList<>();
for (int i = 0; i < amountOfGames; i++) {
opponentMoves.add((DilemmaMove) player.getGameHistoryCollection().getSpecificGameHistory(i)
.getOpponentMove(i));
}
if (opponentMoves.isEmpty()) {
return Optional.of(initialMove);
}
Integer countBeSilentMoves = 0;
for (final DilemmaMove dilemmaMove : opponentMoves) {
if (dilemmaMove instanceof DilemmaBeSilentMove) {
countBeSilentMoves++;
}
}
return getMoveByPercentage(Double.valueOf(countBeSilentMoves), Double.valueOf(opponentMoves.size()));
}
/**
* Returns the move choice of the current player by integrating the number based evaluation.
*
* @param countBeSilentMoves The amount of {@link DilemmaBeSilentMove}.
* @param amountOfOppenentMoves The amount of opponent moves which are played.
* @return
*/
private Optional<DilemmaMove> getMoveByPercentage(final Double countBeSilentMoves,
final Double amountOfOppenentMoves) {
final Double percent = countBeSilentMoves / amountOfOppenentMoves;
if (percent == 1.0) {
return Optional.of(this.providedMoveData.get(IDENTIFIER_100_BESILENT));
} else if (percent > 0.5) {
return Optional.of(this.providedMoveData.get(IDENTIFIER_50_BESILENT));
} else if (percent <= 0.5 && percent > 0.0) {
return Optional.of(this.providedMoveData.get(IDENTIFIER_50_CONFESS));
} else {
return Optional.of(this.providedMoveData.get(IDENTIFIER_100_CONFESS));
}
}
}
The class 'DilemmaCustomStrategy' is suspected to be a Data Class (WOC=14.286%, NOPA=0, NOAM=6, WMC=22).
Data Classes are simple data holders, which reveal most of their state, and
without complex functionality. The lack of functionality may indicate that
their behaviour is defined elsewhere, which is a sign of poor data-behaviour
proximity. By directly exposing their internals, Data Classes break encapsulation,
and therefore reduce the system's maintainability and understandability. Moreover,
classes tend to strongly rely on their data representation, which makes for a brittle
design.
Refactoring a Data Class should focus on restoring a good data-behaviour proximity. In
most cases, that means moving the operations defined on the data back into the class.
In some other cases it may make sense to remove entirely the class and move the data
into the former client classes.
The rule uses metrics to implement its detection strategy. The violation message
gives information about the values of these metrics:
* WMC: a class complexity measure for a class, see {% jdoc java::lang.java.metrics.JavaMetrics#WEIGHED_METHOD_COUNT %}
* WOC: a 'non-triviality' measure for a class, see {% jdoc java::lang.java.metrics.JavaMetrics#WEIGHT_OF_CLASS %}
* NOPA: number of public attributes, see {% jdoc java::lang.java.metrics.JavaMetrics#NUMBER_OF_PUBLIC_FIELDS %}
* NOAM: number of public accessor methods, see {% jdoc java::lang.java.metrics.JavaMetrics#NUMBER_OF_ACCESSORS %}
The rule identifies a god class by looking for classes which have all of the following properties:
* High NOPA + NOAM
* Low WOC
* Low WMC
public class DataClass {
// class exposes public attributes
public String name = "";
public int bar = 0;
public int na = 0;
private int bee = 0;
// and private ones through getters
public void setBee(int n) {
bee = n;
}
}