package de.fhdw.gaming.ipspiel22.vierGewinnt.domain.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import de.fhdw.gaming.core.domain.GameException;
import de.fhdw.gaming.core.domain.PlayerState;
import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGBoard;
import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGField;
import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGFieldState;
import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGPlayer;
import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGState;
/**
* Implements {@link VGState}.
*/
public class VGStateImpl implements VGState {
/**
* The board.
*/
private final VGBoard board;
/**
* The first player.
*/
private final VGPlayer redPlayer;
/**
* The second player.
*/
private final VGPlayer yellowPlayer;
/**
* The current player.
*/
private VGPlayer currentPlayer;
/**
* Creates a Vier gewinnt state.
*
* @param board A board.s
* @param redPlayer The first player.
* @param yellowPlayer The second player.
* @param redIsNext Is red next.
* @throws GameException if the state cannot be created according to the rules of the game.
*/
public VGStateImpl(final VGBoard board, final VGPlayer redPlayer, final VGPlayer yellowPlayer,
final boolean redIsNext)
throws GameException {
this.board = Objects.requireNonNull(board, "board");
this.redPlayer = Objects.requireNonNull(redPlayer, "redPlayerBuilder");
this.yellowPlayer = Objects.requireNonNull(yellowPlayer, "yellowPlayerBuilder");
this.currentPlayer = redIsNext ? this.redPlayer : this.yellowPlayer;
if (!this.redPlayer.isUsingRedChips()) {
throw new IllegalArgumentException(
String.format("Red player %s does not use red chips.", this.redPlayer));
}
if (this.yellowPlayer.isUsingRedChips()) {
throw new IllegalArgumentException(
String.format("Yellow player %s does not use yellow tokens.", this.yellowPlayer));
}
if (this.redPlayer.getName().equals(this.yellowPlayer.getName())) {
throw new IllegalArgumentException(
String.format("Both players have the same name '%s'.", this.redPlayer.getName()));
}
}
/**
* Creates a Vier gewinnt state by copying an existing one.
*
* @param source The state to copy.
*/
VGStateImpl(final VGStateImpl source) {
this.board = source.board.deepCopy();
this.redPlayer = source.redPlayer.deepCopy();
this.yellowPlayer = source.yellowPlayer.deepCopy();
this.currentPlayer = source.isRedPlayerCurrent() ? this.redPlayer : this.yellowPlayer;
}
@Override
public String toString() {
return String.format(
"VGState[board=%s, redPlayer=%s, yellowPlayer=%s, currentPlayer=%s]",
this.board,
this.redPlayer,
this.yellowPlayer,
this.currentPlayer.isUsingRedChips() ? VGFieldState.RED : VGFieldState.YELLOW);
}
@Override
public boolean equals(final Object obj) {
if (obj instanceof VGStateImpl) {
final VGStateImpl other = (VGStateImpl) obj;
return this.board.equals(other.board)
&& this.redPlayer.equals(other.redPlayer)
&& this.yellowPlayer.equals(other.yellowPlayer)
&& this.isRedPlayerCurrent() == other.isRedPlayerCurrent();
}
return false;
}
@Override
public VGState deepCopy() {
return new VGStateImpl(this);
}
@Override
public int hashCode() {
return Objects.hash(this.board, this.redPlayer, this.yellowPlayer, this.isRedPlayerCurrent());
}
@Override
public Map<String, VGPlayer> getPlayers() {
final Map<String, VGPlayer> result = new LinkedHashMap<>();
result.put(this.redPlayer.getName(), this.redPlayer);
result.put(this.yellowPlayer.getName(), this.yellowPlayer);
return result;
}
@Override
public Set<VGPlayer> computeNextPlayers() {
return Collections.singleton(this.currentPlayer);
}
@Override
public void nextTurn() {
final List<VGField> allFields = new ArrayList<>();
this.getBoard().getFields().forEach(allFields::addAll);
if (allFields.stream().noneMatch(vgField -> vgField.getState().equals(VGFieldState.EMPTY))) {
System.out.println("Board ist voll");
if (this.checkWinner(this.currentPlayer)) {
this.currentPlayer.setState(PlayerState.WON);
System.out.println(this.currentPlayer.getName() + " hat gewonnen, mit der Farbe: "
+ (this.currentPlayer.isUsingRedChips()
? VGFieldState.RED.toString()
: VGFieldState.YELLOW.toString()));
this.getOtherPlayer().setState(PlayerState.LOST);
System.out.println(this.getOtherPlayer().getName() + " hat verloren, mit der Farbe: "
+ (this.currentPlayer.isUsingRedChips()
? VGFieldState.YELLOW.toString()
: VGFieldState.RED.toString()));
} else {
this.gameOver();
}
} else if (this.checkWinner(this.currentPlayer)) {
this.currentPlayer.setState(PlayerState.WON);
System.out.println(this.currentPlayer.getName() + " hat gewonnen, mit der Farbe: "
+ (this.currentPlayer.isUsingRedChips()
? VGFieldState.RED.toString()
: VGFieldState.YELLOW.toString()));
this.getOtherPlayer().setState(PlayerState.LOST);
System.out.println(this.getOtherPlayer().getName() + " hat verloren, mit der Farbe: "
+ (this.currentPlayer.isUsingRedChips()
? VGFieldState.YELLOW.toString()
: VGFieldState.RED.toString()));
}
this.currentPlayer = this.getOtherPlayer();
}
The method 'nextTurn()' has a cognitive complexity of 15, current threshold is 15.
Methods that are highly complex are difficult to read and more costly to maintain. If you include too much decisional
logic within a single method, you make its behavior hard to understand and more difficult to modify.
Cognitive complexity is a measure of how difficult it is for humans to read and understand a method. Code that contains
a break in the control flow is more complex, whereas the use of language shorthands doesn't increase the level of
complexity. Nested control flows can make a method more difficult to understand, with each additional nesting of the
control flow leading to an increase in cognitive complexity.
Information about Cognitive complexity can be found in the original paper here:
By default, this rule reports methods with a complexity of 15 or more. Reported methods should be broken down into less
complex components.
public class Foo {
// Has a cognitive complexity of 0
public void createAccount() {
Account account = new Account("PMD");
// save account
}
// Has a cognitive complexity of 1
public Boolean setPhoneNumberIfNotExisting(Account a, String phone) {
if (a.phone == null) { // +1
a.phone = phone;
return true;
}
return false;
}
// Has a cognitive complexity of 4
public void updateContacts(List<Contact> contacts) {
List<Contact> contactsToUpdate = new ArrayList<Contact>();
for (Contact contact : contacts) { // +1
if (contact.department.equals("Finance")) { // +2 (nesting = 1)
contact.title = "Finance Specialist";
contactsToUpdate.add(contact);
} else if (contact.department.equals("Sales")) { // +1
contact.title = "Sales Specialist";
contactsToUpdate.add(contact);
}
}
// save contacts
}
}