Skip to content

Content of file MinMaxViergewinnt.java

package de.fhdw.gaming.ipspiel22.vierGewinnt.strategy;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.VGMove;
import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.AbstractVGMove;
import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG1ColumnMove;
import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG2ColumnMove;
import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG3ColumnMove;
import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG4ColumnMove;
import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG5ColumnMove;
import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG6ColumnMove;
import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG7ColumnMove;
import de.fhdw.gaming.core.domain.GameException;
import de.fhdw.gaming.ipspiel22.searchtree.domain.MinMaxGame;
import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGAnswerEnum;
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.VGPosition;
import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGState;
import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.impl.VGBoardImpl;

/**
 * MinMaxViergewinnt.
 */
public class MinMaxViergewinnt implements MinMaxGame<VGPlayer, VGState, VGMove> {
    /**
     * Current given state.
     */
    private final VGState vgState;

    /**
     * Current given state.
     */
    private final VGBoard inistialBoard;

    /**
     * Current given player.
     */
    private final VGPlayer player;

    /**
     * Playercolour for algorithm.
     */
    private Boolean playercolour;

    /**
     * Saved Move.
     */
    private VGMove savedMove;

    /**
     * For creating MinMaxViergewinnt.
     * 
     * @param state  Current given state.
     * @param player Current given player.
     */
    public MinMaxViergewinnt(final VGState state, final VGPlayer player) {
        this.vgState = state;
        this.player = player;
        this.playercolour = player.isUsingRedChips();
        this.inistialBoard = new VGBoardImpl((VGBoardImpl) state.getBoard());
    }

    @Override
    public double evaluateStateful() {
        double stateful;

        final VGFieldState state = playercolour ? VGFieldState.RED : VGFieldState.YELLOW;
        final VGFieldState otherPlayerState = !playercolour ? VGFieldState.RED : VGFieldState.YELLOW;

        final List<Double> checkedStates = new ArrayList<>();
        if (this.playercolour == this.player.isUsingRedChips()) {

            checkedStates.addAll(twoCombo(vgState.getBoard(), state, 6.0));
            checkedStates.addAll(threeCombo(vgState.getBoard(), state, 12.0));
            checkedStates.addAll(fourCombo(vgState.getBoard(), state, 24.0));

            stateful = Collections.max(checkedStates);
            stateful += checkMiddle(vgState.getBoard(), playercolour);

            final List<Double> firstPossibleMoves = new ArrayList<>();
            firstPossibleMoves.add(ifThreeWithMove(otherPlayerState,
                    !this.player.isUsingRedChips()));
            firstPossibleMoves.add(ifThreeWithMove(state, this.player.isUsingRedChips()));
            firstPossibleMoves.add(ifWonWithMove(otherPlayerState,
                    !this.player.isUsingRedChips()));
            firstPossibleMoves.add(ifWonWithMove(state, this.player.isUsingRedChips()));
            stateful += Collections.max(firstPossibleMoves);

        } else {
            checkedStates.addAll(threeCombo(vgState.getBoard(), state, 5.0));
            checkedStates.addAll(fourCombo(vgState.getBoard(), state, 20.0));

            stateful = Collections.max(checkedStates);
        }
        return stateful;
    }

    @Override
    public boolean isGameOver() {
        final List<VGField> allFields = new ArrayList<>();
        vgState.getBoard().getFields().forEach(allFields::addAll);

        if (allFields.stream().noneMatch(vgField -> vgField.getState().equals(VGFieldState.EMPTY))) {
            return true;
        } else {
            return checkWinner(vgState.getBoard(), playercolour); // checkWinner(!playercolour);
        }
    }

    @Override
    public List<VGMove> getPossibleMoves() {
        final List<VGMove> movesList = new ArrayList<>();

        if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.FIRSTCOLUMN))) {
            movesList.add(new VG1ColumnMove());
        }
        if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.SECONDCOLUMN))) {
            movesList.add(new VG2ColumnMove());
        }
        if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.THIRDCOLUMN))) {
            movesList.add(new VG3ColumnMove());
        }
        if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.FOURTHCOLUMN))) {
            movesList.add(new VG4ColumnMove());
        }
        if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.FITFHCOLUMN))) {
            movesList.add(new VG5ColumnMove());
        }
        if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.SIXTHCOLUMN))) {
            movesList.add(new VG6ColumnMove());
        }
        if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.SEVENTHCOLUMN))) {
            movesList.add(new VG7ColumnMove());
        }
        Collections.shuffle(movesList);
        return movesList;
    }

    @Override
    public void commitMove(final VGMove move) throws GameException {
        final VGPlayer playerMove = this.playercolour ? vgState.getRedPlayer() : vgState.getYellowPlayer();

        move.applyTo(this.vgState, playerMove);
        this.playercolour = !this.playercolour;

    }

    @Override
    public void rollbackMove(final VGMove move) {
        if (move instanceof AbstractVGMove) {
            vgState.getBoard().getFields().get(((AbstractVGMove) move).getColumnInt() - 1);

            int count = 0;
            VGField field = vgState.getBoard().getFields().get(((AbstractVGMove) move)
                    .getColumnInt() - 1).get(count);
            while (!field.getState().equals(VGFieldState.EMPTY) && count < 5) {
                count += 1;
                field = vgState.getBoard().getFields().get(((AbstractVGMove) move)
                        .getColumnInt() - 1).get(count);
            }
            vgState.getBoard().getFields().get(((AbstractVGMove) move).getColumnInt() - 1)
                    .get(count == 0 ? count : count - 1)
                    .setState(VGFieldState.EMPTY);
        }
        this.playercolour = !this.playercolour;
    }

    @Override
    public VGMove saveFirstMoves(final VGMove move) {
        this.savedMove = move;
        return move;
    }

    /**
     * If possible to win with next move.
     * 
     * @param state
     * @param playercolor
     * @return
     */
    private double ifWonWithMove(final VGFieldState state, final Boolean playercolor) {
        final double value = playercolor == player.isUsingRedChips() ? 100.0 : 50.0;
        return letsWinIfPossible(state, getMoveAsAnswer(this.savedMove),
                playercolor) ? value : 0;
    }

    /**
     * converts Move to Answer.
     * 
     * @param move
     * @return
     */
    private VGAnswerEnum getMoveAsAnswer(final VGMove move) {
        if (move instanceof VG1ColumnMove) {
            return VGAnswerEnum.FIRSTCOLUMN;
        } else if (move instanceof VG2ColumnMove) {
            return VGAnswerEnum.SECONDCOLUMN;
        } else if (move instanceof VG3ColumnMove) {
            return VGAnswerEnum.THIRDCOLUMN;
        } else if (move instanceof VG4ColumnMove) {
            return VGAnswerEnum.FOURTHCOLUMN;
        } else if (move instanceof VG5ColumnMove) {
            return VGAnswerEnum.FITFHCOLUMN;
        } else if (move instanceof VG6ColumnMove) {
            return VGAnswerEnum.SIXTHCOLUMN;
        } else {
            return VGAnswerEnum.SEVENTHCOLUMN;
        }
    }

    /**
     * If possible to have three chips in next move.
     * 
     * @param state
     * @param playercolor
     * @return
     */
    private double ifThreeWithMove(final VGFieldState state, final boolean playercolor) {
        final double value = playercolor == player.isUsingRedChips() ? 20.0 : 10.0;
        return putThreeIfPossible(state, getMoveAsAnswer(this.savedMove)) ? value : 0;
    }

    /**
     * Win if possible.
     * 
     * @param state
     * @param column
     * @param playercolor
     * @return
     */
    private Boolean letsWinIfPossible(final VGFieldState state, final VGAnswerEnum column,
            final Boolean playercolor) {
        final VGField field = inistialBoard.getNextFieldInColumn(column);
        Boolean won = false;
        if (Objects.nonNull(field)) {
            field.setState(state);
            won = checkWinner(inistialBoard, playercolor);
            field.setState(VGFieldState.EMPTY);
        }
        return won;
    }

    /**
     * Three if possible.
     * 
     * @param state
     * @param column
     * @return
     */
    private Boolean putThreeIfPossible(final VGFieldState state, final VGAnswerEnum column) {
        final VGField field = inistialBoard.getNextFieldInColumn(column);
        Boolean won = false;
        if (Objects.nonNull(field)) {
            field.setState(state);
            won = Collections.max(threeCombo(inistialBoard, state, 20.0)) > 0;
            field.setState(VGFieldState.EMPTY);
        }
        return won;
    }

    // -----------------------------------------------------------------------------------------------------

    /**
     * Returns boolean, if Player has won.
     *
     * @param board
     * @param usingRedChips The current player.
     */
    private boolean checkWinner(final VGBoard board, final Boolean usingRedChips) {
        final VGFieldState state = usingRedChips ? VGFieldState.RED : VGFieldState.YELLOW;
        return checkHorizontaleLeftToRight(board, state, state, state, state) 
                || checkVertikaleDownUp(board, state, state, state, state) 
                || checkDiagonaleDownLeftUpRight(board, state, state, state, state) 
                || checkDiagonaleDownRightUpLeftght(board, state, state, state, state);
    }
    
    /**
     * Checks condition, if true return rating else 0.0.
     * @param condition
     * @param rating
     * @return
     */
    private Double checkCondition(final Boolean condition, final Double rating) {
        return condition ? rating : 0.0;
    }

    /**
     * Checks if a two combo exists.
     * 
     * @param board
     * @param state
     * @param rating
     * @return
     */
    public List<Double> twoCombo(final VGBoard board, final VGFieldState state,
            final Double rating) {
        final List<Double> checkedStates = new ArrayList<>();
        checkedStates
                .add(checkCondition(checkDiagonaleDownLeftUpRight(board, VGFieldState.EMPTY, state,
                        VGFieldState.EMPTY, state), rating));
        checkedStates.add(
                checkCondition(checkDiagonaleDownRightUpLeftght(board, VGFieldState.EMPTY, state,
                        VGFieldState.EMPTY, state), rating));
        checkedStates
                .add(checkCondition(checkHorizontaleLeftToRight(board, VGFieldState.EMPTY, state,
                        VGFieldState.EMPTY, state), rating));

        checkedStates
                .add(checkCondition(checkDiagonaleDownLeftUpRight(board, state, VGFieldState.EMPTY,
                        state, VGFieldState.EMPTY), rating));
        checkedStates.add(
                checkCondition(checkDiagonaleDownRightUpLeftght(board, state, VGFieldState.EMPTY,
                        state, VGFieldState.EMPTY), rating));
        checkedStates
                .add(checkCondition(checkHorizontaleLeftToRight(board, state, VGFieldState.EMPTY,
                        state, VGFieldState.EMPTY), rating));

        checkedStates
                .add(checkCondition(checkDiagonaleDownLeftUpRight(board, state, state, VGFieldState.EMPTY,
                        VGFieldState.EMPTY), rating));
        checkedStates.add(
                checkCondition(checkDiagonaleDownRightUpLeftght(board, state, state, VGFieldState.EMPTY,
                        VGFieldState.EMPTY), rating));
        checkedStates
                .add(checkCondition(checkHorizontaleLeftToRight(board, state, state, VGFieldState.EMPTY,
                        VGFieldState.EMPTY), rating));

        checkedStates
                .add(checkCondition(checkDiagonaleDownLeftUpRight(board, state, VGFieldState.EMPTY,
                        VGFieldState.EMPTY, state), rating));
        checkedStates.add(
                checkCondition(checkDiagonaleDownRightUpLeftght(board, state, VGFieldState.EMPTY,
                        VGFieldState.EMPTY, state), rating));
        checkedStates
                .add(checkCondition(checkHorizontaleLeftToRight(board, state, VGFieldState.EMPTY,
                        VGFieldState.EMPTY, state), rating));

        checkedStates
                .add(checkCondition(checkDiagonaleDownLeftUpRight(board, VGFieldState.EMPTY,
                        VGFieldState.EMPTY, state, state), rating));
        checkedStates.add(
                checkCondition(checkDiagonaleDownRightUpLeftght(board, VGFieldState.EMPTY,
                        VGFieldState.EMPTY, state, state), rating));
        checkedStates
                .add(checkCondition(checkHorizontaleLeftToRight(board, VGFieldState.EMPTY,
                        VGFieldState.EMPTY, state, state), rating));

        checkedStates
                .add(checkCondition(checkVertikaleDownUp(board, state, state, VGFieldState.EMPTY,
                        VGFieldState.EMPTY), rating));
        return checkedStates;
    }

    /**
     * Checks if three Combo exists.
     * 
     * @param board
     * @param state
     * @param rating
     * @return
     */
    public List<Double> threeCombo(final VGBoard board, final VGFieldState state, final Double rating) {
        // Drei gewinnt
        final List<Double> checkedStates = new ArrayList<>();
        checkedStates.add(checkCondition(checkDiagonaleDownLeftUpRight(board, state, state, 
                VGFieldState.EMPTY, state), rating));
        checkedStates
                .add(checkCondition(checkDiagonaleDownRightUpLeftght(board, state, state, 
                        VGFieldState.EMPTY, state), rating));
        checkedStates.add(checkCondition(checkHorizontaleLeftToRight(board, state, state, 
                VGFieldState.EMPTY, state), rating));

        checkedStates.add(checkCondition(checkDiagonaleDownLeftUpRight(board, state, 
                VGFieldState.EMPTY, state, state), rating));
        checkedStates
                .add(checkCondition(checkDiagonaleDownRightUpLeftght(board, state, 
                        VGFieldState.EMPTY, state, state), rating));
        checkedStates.add(checkCondition(checkHorizontaleLeftToRight(board, state, 
                VGFieldState.EMPTY, state, state), rating));

        checkedStates.add(checkCondition(checkDiagonaleDownLeftUpRight(board, 
                VGFieldState.EMPTY, state, state, state), rating));
        checkedStates
                .add(checkCondition(checkDiagonaleDownRightUpLeftght(board, 
                        VGFieldState.EMPTY, state, state, state), rating));
        checkedStates.add(checkCondition(checkHorizontaleLeftToRight(board, 
                VGFieldState.EMPTY, state, state, state), rating));

        checkedStates.add(checkCondition(checkDiagonaleDownLeftUpRight(board, state, 
                state, state, VGFieldState.EMPTY), rating));
        checkedStates.add(checkCondition(checkVertikaleDownUp(board, state, state, 
                state, VGFieldState.EMPTY), rating));
        checkedStates
                .add(checkCondition(checkDiagonaleDownRightUpLeftght(board, state, 
                        state, state, VGFieldState.EMPTY), rating));
        checkedStates.add(checkCondition(checkHorizontaleLeftToRight(board, state, 
                state, state, VGFieldState.EMPTY), rating));
        return checkedStates;
    }

    /**
     * If four combo exists.
     * 
     * @param board
     * @param state
     * @param rating
     * @return
     */
    public List<Double> fourCombo(final VGBoard board, final VGFieldState state, final Double rating) {
        // Vier gewinnt
        final List<Double> checkedStates = new ArrayList<>();
        checkedStates.add(checkDiagonaleDownLeftUpRight(board, state, state, state, state) ? rating : 0.0);
        checkedStates.add(checkVertikaleDownUp(board, state, state, state, state) ? rating : 0.0);
        checkedStates.add(checkDiagonaleDownRightUpLeftght(board, state, state, state, state) ? rating : 0.0);
        checkedStates.add(checkHorizontaleLeftToRight(board, state, state, state, state) ? rating : 0.0);
        return checkedStates;
    }

   
    /**
     * Extra Points for chips in the middle.
     * 
     * @param board
     * @param usingRedChips
     * @return result
     */
    private double checkMiddle(final VGBoard board, final boolean usingRedChips) {
        double result = 0.0;
        final VGFieldState state = usingRedChips ? VGFieldState.RED : VGFieldState.YELLOW;

        result += board.getFields().get(2).stream().filter(field -> field.getState().equals(state))
                .mapToDouble(field -> {
                    return 2.0;
                }).sum(); // Dritte Spalte
        result += board.getFields().get(3).stream().filter(field -> field.getState().equals(state))
                .mapToDouble(field -> {
                    return 5.0;
                }).sum(); // Vierte Spalte
        result += board.getFields().get(4).stream().filter(field -> field.getState().equals(state))
                .mapToDouble(field -> {
                    return 2.0;
                }).sum(); // Fünfte Spa 0;

        return result;
    }

    /**
     * Checks horizontal.
     * 
     * @param board
     * @param chip1
     * @param chip2
     * @param chip3
     * @param chip4
     * @return
     */
    private Boolean checkHorizontaleLeftToRight(final VGBoard board, final VGFieldState chip1,
            final VGFieldState chip2,
            final VGFieldState chip3, final VGFieldState chip4) {
        for (int i = 0; i < board.getRows(); i++) {
            for (int j = 0; j < 4; j++) {
                if (board.getFieldAt(VGPosition.of(j, i)).getState().equals(chip1)
                        && board.getFieldAt(VGPosition.of(j + 1, i)).getState().equals(chip2)
                        && board.getFieldAt(VGPosition.of(j + 2, i)).getState().equals(chip3)
                        && board.getFieldAt(VGPosition.of(j + 3, i)).getState().equals(chip4)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * checks vertical.
     * 
     * @param board
     * @param chip1
     * @param chip2
     * @param chip3
     * @param chip4
     * @return
     */
    private Boolean checkVertikaleDownUp(final VGBoard board, final VGFieldState chip1, final VGFieldState chip2,
            final VGFieldState chip3,
            final VGFieldState chip4) {
        for (int i = 0; i < board.getColumns(); i++) {
            for (int j = 0; j < 3; j++) {
                if (board.getFieldAt(VGPosition.of(i, j)).getState().equals(chip1)
                        && board.getFieldAt(VGPosition.of(i, j + 1)).getState().equals(chip2)
                        && board.getFieldAt(VGPosition.of(i, j + 2)).getState().equals(chip3)
                        && board.getFieldAt(VGPosition.of(i, j + 3)).getState().equals(chip4)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * checks diagonale down left to up right.
     * 
     * @param board
     * @param chip1
     * @param chip2
     * @param chip3
     * @param chip4
     * @return
     */
    private Boolean checkDiagonaleDownLeftUpRight(final VGBoard board, final VGFieldState chip1,
            final VGFieldState chip2,
            final VGFieldState chip3, final VGFieldState chip4) {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 4; j++) {
                if (board.getFieldAt(VGPosition.of(j, i)).getState().equals(chip1)
                        && board.getFieldAt(VGPosition.of(j + 1, i + 1)).getState()
                                .equals(chip2)
                        && board.getFieldAt(VGPosition.of(j + 2, i + 2)).getState()
                                .equals(chip3)
                        && board.getFieldAt(VGPosition.of(j + 3, i + 3)).getState()
                                .equals(chip4)) {
                    return true;
                }
            }
        }
        return false;

    }

    /**
     * checks diagonle down right to up left.
     * 
     * @param board
     * @param chip1
     * @param chip2
     * @param chip3
     * @param chip4
     * @return
     */
    private Boolean checkDiagonaleDownRightUpLeftght(final VGBoard board, final VGFieldState chip1,
            final VGFieldState chip2, final VGFieldState chip3, final VGFieldState chip4) {
        for (int i = 0; i < 3; i++) {
            for (int j = 3; j < 7; j++) {
                if (board.getFieldAt(VGPosition.of(j, i)).getState().equals(chip1)
                        && board.getFieldAt(VGPosition.of(j - 1, i + 1)).getState()
                                .equals(chip2)
                        && board.getFieldAt(VGPosition.of(j - 2, i + 2)).getState()
                                .equals(chip3)
                        && board.getFieldAt(VGPosition.of(j - 3, i + 3)).getState()
                                .equals(chip4)) {
                    return true;
                }
            }
        }

        return false;
    }

}
Possible God Class (WMC=81, ATFD=193, TCC=6.667%).
The God Class rule detects the God Class design flaw using metrics. God classes do too many things, are very big and overly complex. They should be split apart to be more object-oriented. The rule uses the detection strategy described in "Object-Oriented Metrics in Practice". The violations are reported against the entire class. 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, see {% jdoc java::lang.java.metrics.JavaMetrics#WEIGHED_METHOD_COUNT %} * ATFD: a measure of how much data external data the class uses, see {% jdoc java::lang.java.metrics.JavaMetrics#ACCESS_TO_FOREIGN_DATA %} * TCC: a measure of how tightly related the methods are, see {% jdoc java::lang.java.metrics.JavaMetrics#TIGHT_CLASS_COHESION %} The rule identifies a god class by looking for classes which have all of the following properties: * High WMC * High ATFD * Low TCC See also the reference: Michele Lanza and Radu Marinescu. *Object-Oriented Metrics in Practice: Using Software Metrics to Characterize, Evaluate, and Improve the Design of Object-Oriented Systems.* Springer, Berlin, 1 edition, October 2006. Page 80. See PMD documentation.