oglimmer/ggo

View on GitHub
core/src/main/java/de/oglimmer/ggo/logic/phase/DeployPhase.java

Summary

Maintainability
A
55 mins
Test Coverage
package de.oglimmer.ggo.logic.phase;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import de.oglimmer.ggo.logic.Field;
import de.oglimmer.ggo.logic.Game;
import de.oglimmer.ggo.logic.Player;
import de.oglimmer.ggo.logic.Side;
import de.oglimmer.ggo.logic.Unit;
import de.oglimmer.ggo.logic.UnitType;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DeployPhase extends BasePhase {

    private static final long serialVersionUID = 1L;

    private Player activePlayer;

    private Unit selectedUnit;

    private Map<Player, Set<Field>> additionalAirborneTargetFields = new HashMap<>();

    public DeployPhase(Game game) {
        super(game);
    }

    @Override
    public void init() {
        Player firstActivePlayer = findFirstPlayer();
        findActivePlayer(firstActivePlayer);
        if (this.activePlayer != null) {
            getGame().getPlayers().forEach(p -> p.getMessages().clearErrorInfo());
            getGame().getPlayers()
                    .forEach(p -> additionalAirborneTargetFields.put(p, calcAdditionalTargetFieldsAirborne(p)));
            notifyPlayer(activePlayer);
        }
    }

    private Player findFirstPlayer() {
        Player player1 = getGame().getPlayers().get(0);
        Player player2 = getGame().getPlayers().get(1);
        if (player1.getCredits() > player2.getCredits()) {
            return player1;
        } else if (player1.getCredits() < player2.getCredits()) {
            return player2;
        }
        int totalUnits1 = getTotalUnits(player1);
        int totalUnits2 = getTotalUnits(player2);
        if (totalUnits1 < totalUnits2) {
            return player1;
        } else if (totalUnits1 > totalUnits2) {
            return player2;
        }
        return Math.random() < 0.5 ? player1 : player2;
    }

    private int getTotalUnits(Player player) {
        return (int) (player.getUnitInHand().size() + getGame().getBoard().getFields().stream()
                .filter(f -> f.getUnit() != null).filter(f -> f.getUnit().getPlayer() == player).count());
    }

    private void findActivePlayer(Player firstActivePlayer) {
        if (!firstActivePlayer.getUnitInHand().isEmpty()) {
            this.activePlayer = firstActivePlayer;
        } else {
            Player otherPlayer = getGame().getOtherPlayer(firstActivePlayer);
            if (!otherPlayer.getUnitInHand().isEmpty()) {
                this.activePlayer = otherPlayer;
            } else {
                this.activePlayer = null;
                nextPhase();
            }
        }
    }

    private Set<Field> getDefaultDeployZone(Player player) {
        Predicate<? super Field> filter;
        if (player.getSide() == Side.GREEN) {
            filter = f -> f.getPos().getX() <= 4;
        } else {
            filter = f -> f.getPos().getX() >= 5;
        }
        return getGame().getBoard().getFields().stream().filter(filter).collect(Collectors.toSet());
    }

    private Set<Field> calcAdditionalTargetFieldsAirborne(Player player) {
        return getGame().getBoard().getFields().stream().filter(f -> f.getUnit() != null)
                .filter(f -> f.getUnit().getPlayer() == player).flatMap(f -> f.getNeighbors().stream())
                .collect(Collectors.toSet());
    }

    @Override
    public boolean isHighlighted(Field field, Player forPlayer) {
        Set<Field> tmp = getDeployFields(forPlayer);
        return forPlayer == activePlayer && selectedUnit != null && tmp.contains(field);
    }

    public Set<Field> getDeployFields(Player forPlayer) {
        Set<Field> tmp = new HashSet<>(getDefaultDeployZone(forPlayer));
        if (selectedUnit != null && selectedUnit.getUnitType() == UnitType.AIRBORNE) {
            tmp.addAll(additionalAirborneTargetFields.get(forPlayer));
        }
        // remove fields with unit
        getGame().getBoard().getFields().stream().filter(f -> f.getUnit() != null).forEach(f -> tmp.remove(f));
        return tmp;
    }

    @Override
    public boolean isSelectable(Field field, Player forPlayer) {
        return getGame().getCurrentPhase().isHighlighted(field, forPlayer);
    }

    @Override
    public boolean isSelected(Unit unit, Player forPlayer) {
        return forPlayer == activePlayer && selectedUnit == unit;
    }

    @Override
    public boolean isSelectable(Unit unit, Player forPlayer) {
        return forPlayer == activePlayer && forPlayer.getUnitInHand().contains(unit)
                && (selectedUnit == null || selectedUnit == unit);
    }

    @Override
    public void execCmd(Player player, String cmd, String param) {
        super.execCmd(player, cmd, param);
        switch (cmd) {
        case "selectHandCard":
            execSelectHandCard(player, param);
            break;
        case "selectTargetField":
            execSelectTargetField(player, param);
            break;
        }
    }

    private void execSelectHandCard(Player player, String param) {
        if (player != activePlayer) {
            log.error("got cmd selectHandCard from not active player");
            return;
        }
        Unit paramSelectedUnit = player.getUnitInHand().stream().filter(u -> u.getId().equals(param)).findFirst().get();
        if (selectedUnit != null && selectedUnit != paramSelectedUnit) {
            log.error("execSelectHandCard but selectedUnit was " + selectedUnit.getUnitType());
            return;
        }
        if (selectedUnit == paramSelectedUnit) {
            selectedUnit = null;
        } else {
            selectedUnit = paramSelectedUnit;
        }
    }

    private void execSelectTargetField(Player player, String param) {
        if (player != activePlayer) {
            log.error("got cmd selectHandCard from not active player");
            return;
        }
        if (selectedUnit == null) {
            log.error("execSelectTargetField but selectedUnit was null");
            return;
        }
        Field target = getGame().getBoard().getField(param);
        if (target.getUnit() != null) {
            log.error("execSelectTargetField but already occupied field was seleted");
            return;
        }
        target.setUnit(selectedUnit);
        selectedUnit.setDeployedOn(target);
        player.getUnitInHand().remove(selectedUnit);
        selectedUnit = null;
        switchPlayer(player);

    }

    protected void switchPlayer(Player player) {
        boolean nextPhase = false;
        activePlayer.getMessages().clearErrorInfo();
        Player nextPlayer = getGame().getOtherPlayer(activePlayer);
        if (!hasMoreMoves(nextPlayer)) {
            if (hasMoreMoves(activePlayer)) {
                nextPlayer = activePlayer;
            } else {
                nextPhase = true;
            }
        }
        if (nextPhase) {
            nextPhase();
        } else {
            activePlayer = nextPlayer;
            notifyPlayer(activePlayer);
        }
    }

    @Override
    protected void updateTitleMessage(Player player) {
        if (player == activePlayer) {
            if (selectedUnit != null) {
                player.getMessages().setTitle("Select a highlighted field to deploy " + selectedUnit.getUnitType()
                        + " or click the unit again to de-select it");
            } else {
                player.getMessages().setTitle("Select a unit from your hand to deploy it");
            }
        } else {
            player.getMessages().setTitle("waiting for other player's deployment");
        }
    }

    @Override
    protected void nextPhase() {
        boolean initShouldBeCalled = getGame().setCurrentPhase(new CombatCommandPhase(getGame(), null));
        assert initShouldBeCalled;
        getGame().getCurrentPhase().init();
    }

    private boolean hasMoreMoves(Player p) {
        return !p.getUnitInHand().isEmpty();
    }

    @Override
    public String toString() {
        return "DeployPhase [activePlayer = " + activePlayer.getSide() + ", selectedUnit="
                + (selectedUnit != null ? selectedUnit.getUnitType() : "null") + "]";
    }

}