org.nla.tarotdroid.biz.computers.GuavaGameSetStatisticsComputer.java Source code

Java tutorial

Introduction

Here is the source code for org.nla.tarotdroid.biz.computers.GuavaGameSetStatisticsComputer.java

Source

/*
This file is part of the Android application TarotDroid.
    
TarotDroid is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
TarotDroid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with TarotDroid. If not, see <http://www.gnu.org/licenses/>.
*/
package org.nla.tarotdroid.biz.computers;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Maps.newHashMap;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.nla.tarotdroid.biz.BaseGame;
import org.nla.tarotdroid.biz.BelgianBaseGame;
import org.nla.tarotdroid.biz.GameSet;
import org.nla.tarotdroid.biz.PassedGame;
import org.nla.tarotdroid.biz.PenaltyGame;
import org.nla.tarotdroid.biz.Player;
import org.nla.tarotdroid.biz.StandardBaseGame;
import org.nla.tarotdroid.biz.StandardTarot5Game;
import org.nla.tarotdroid.biz.enums.BetType;
import org.nla.tarotdroid.biz.enums.KingType;
import org.nla.tarotdroid.biz.enums.ResultType;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimaps;

/**
 * @author Nicolas LAURENT daffycricket<a>yahoo.fr
 * A class designed to compute the statistics of a GameSet.
 */
public final class GuavaGameSetStatisticsComputer implements IGameSetStatisticsComputer {

    /**
     * Constant for GREEN Color. See http://developer.android.com/reference/android/graphics/Color.html#GREEN for code reference.
     */
    private static final int COLOR_GREEN = -16711936;

    /**
     * Constant for BLUE Color. See http://developer.android.com/reference/android/graphics/Color.html#BLUE for code reference.
     */
    private static final int COLOR_BLUE = -16776961;

    /**
     * Constant for CYAN Color. See http://developer.android.com/reference/android/graphics/Color.html#CYAN for code reference.
     */
    private static final int COLOR_CYAN = -16711681;

    /**
     * Constant for YELLOW Color. See http://developer.android.com/reference/android/graphics/Color.html#YELLOW for code reference.
     */
    private static final int COLOR_YELLOW = -256;

    /**
     * Constant for RED Color. See http://developer.android.com/reference/android/graphics/Color.html#RED for code reference.
     */
    private static final int COLOR_RED = -65536;

    /**
     * Constant for MAGENTA Color. See http://developer.android.com/reference/android/graphics/Color.html#MAGENTA for code reference.
     */
    private static final int COLOR_MAGENTA = -65281;

    /**
     * Array of display COLORS.
     */
    protected static final List<Integer> COLORS = new ArrayList<Integer>();
    static {
        GuavaGameSetStatisticsComputer.COLORS.add(GuavaGameSetStatisticsComputer.COLOR_GREEN);
        GuavaGameSetStatisticsComputer.COLORS.add(GuavaGameSetStatisticsComputer.COLOR_BLUE);
        GuavaGameSetStatisticsComputer.COLORS.add(GuavaGameSetStatisticsComputer.COLOR_CYAN);
        GuavaGameSetStatisticsComputer.COLORS.add(GuavaGameSetStatisticsComputer.COLOR_YELLOW);
        GuavaGameSetStatisticsComputer.COLORS.add(GuavaGameSetStatisticsComputer.COLOR_RED);
        GuavaGameSetStatisticsComputer.COLORS.add(GuavaGameSetStatisticsComputer.COLOR_MAGENTA);
    }

    /**
     * The game set on which to compute the statistics.
     */
    private GameSet gameSet;

    /**
     * Number of necessary leading player series. 
     */
    private int leadingPlayerSeriesCount;

    /**
     * Number of necessary called player series. 
     */
    private int calledPlayerSeriesCount;

    /**
     * Number of necessary bet series. 
     */
    private int betSeriesCount;

    /**
     * Number of necessary full bet series. 
     */
    private int fullBetSeriesCount;

    /**
     * Number of necessary king series. 
     */
    private int kingSeriesCount;

    /**
     * Constructor using a GameSet.
     * @param gameSet
     */
    protected GuavaGameSetStatisticsComputer(final GameSet gameSet) {
        if (gameSet == null) {
            throw new IllegalArgumentException("gameSet is null");
        }
        this.gameSet = gameSet;
        this.leadingPlayerSeriesCount = Integer.MIN_VALUE;
        this.calledPlayerSeriesCount = Integer.MIN_VALUE;
        this.betSeriesCount = Integer.MIN_VALUE;
        this.fullBetSeriesCount = Integer.MIN_VALUE;
        this.kingSeriesCount = Integer.MIN_VALUE;
    }

    /**
     * Returns an array corresponding to successes and failures COLORS.
     * @return an array corresponding to successes and failures COLORS.
     */
    public int[] getResultsColors() {
        return new int[] { GuavaGameSetStatisticsComputer.COLOR_RED, GuavaGameSetStatisticsComputer.COLOR_GREEN };
    }

    /**
     * Returns the count of successes and failures.   
     * @return the count of successes and failures as a Map<GameResultTypes, Integer>.
     */
    public Map<ResultType, Integer> getResultsCount() {
        // won predicate
        Predicate<BaseGame> successPredicate = new Predicate<BaseGame>() {
            @Override
            public boolean apply(final BaseGame game) {
                return game != null && game instanceof StandardBaseGame && ((StandardBaseGame) game).isGameWon();
            }
        };

        // lost predicate
        Predicate<BaseGame> failurePredicate = new Predicate<BaseGame>() {
            @Override
            public boolean apply(final BaseGame game) {
                return game != null && game instanceof StandardBaseGame && !((StandardBaseGame) game).isGameWon();
            }
        };

        // computing info about prise games
        int successCount = Collections2.filter(this.gameSet.getStandardGames(), successPredicate).size();
        int failureCount = Collections2.filter(this.gameSet.getStandardGames(), failurePredicate).size();

        Map<ResultType, Integer> toReturn = newHashMap();
        toReturn.put(ResultType.Success, successCount);
        toReturn.put(ResultType.Failure, failureCount);

        return toReturn;
    }

    /**
     * Returns for each player the number of games he has been a leading player.   
     * @return for each player the number of games he has been a leading player as a Map<Player, Integer>.
     */
    public Map<Player, Integer> getLeadingCount() {
        // transform StandardBaseGame into Player
        Function<StandardBaseGame, Player> gameSetToLeadingPlayerFunction = new Function<StandardBaseGame, Player>() {

            @Override
            public Player apply(final StandardBaseGame stdBaseGame) {
                return stdBaseGame.getLeadingPlayer();
            }
        };

        // group standard games by player 
        ImmutableListMultimap<Player, StandardBaseGame> leadingPlayerMultimap = Multimaps
                .index(this.gameSet.getStandardGames(), gameSetToLeadingPlayerFunction);

        // build return object
        Map<Player, Integer> toReturn = newHashMap();
        for (Player player : leadingPlayerMultimap.keys()) {
            toReturn.put(player, leadingPlayerMultimap.get(player).size());
        }
        this.leadingPlayerSeriesCount = toReturn.keySet().size();

        return toReturn;
    }

    /**
     * Returns an array corresponding to leading user COLORS.
     * @return an array corresponding to leading user COLORS.
     */
    public int[] getLeadingCountColors() {
        if (this.leadingPlayerSeriesCount == Integer.MIN_VALUE) {
            throw new IllegalStateException("you must call getLeadingCount() first");
        }
        return GuavaGameSetStatisticsComputer
                .convert(GuavaGameSetStatisticsComputer.COLORS.subList(0, this.leadingPlayerSeriesCount));
    }

    /**
     * Returns for each player the number of games he won as a leading player.   
     * @return for each player the number of games he won as a leading player as a Map<Player, Integer>.
     */
    public Map<Player, Integer> getLeadingSuccessCount() {
        Map<Player, Integer> toReturn = newHashMap();
        for (Player player : this.gameSet.getPlayers()) {
            toReturn.put(player, Collections2
                    .filter(this.gameSet.getStandardGames(), new LeaderPlayerWinsPredicate(player)).size());
        }
        return toReturn;
    }

    /**
     * Returns for each player the number of games he has been called.   
     * @return for each player the number of games he has been called as a Map<Player, Integer>.
     */
    public Map<Player, Integer> getCalledCount() {
        // transform StandardBaseGame into Player
        Function<StandardTarot5Game, Player> gameSetToCalledPlayerFunction = new Function<StandardTarot5Game, Player>() {

            @Override
            public Player apply(final StandardTarot5Game stdBaseGame) {
                return stdBaseGame.getCalledPlayer();
            }
        };

        // group standard games by player 
        ImmutableListMultimap<Player, StandardTarot5Game> calledPlayerMultimap = Multimaps
                .index(this.gameSet.getStandard5Games(), gameSetToCalledPlayerFunction);

        // build return object
        Map<Player, Integer> toReturn = newHashMap();
        for (Player player : calledPlayerMultimap.keys()) {
            toReturn.put(player, calledPlayerMultimap.get(player).size());
        }
        this.calledPlayerSeriesCount = toReturn.keySet().size();

        return toReturn;
    }

    /**
     * Returns an array corresponding to called players.
     * @return an array corresponding to called players.
     */
    public int[] getCalledCountColors() {
        if (this.calledPlayerSeriesCount == Integer.MIN_VALUE) {
            throw new IllegalStateException("you must call getCalledCount() first");
        }
        return GuavaGameSetStatisticsComputer
                .convert(GuavaGameSetStatisticsComputer.COLORS.subList(0, this.calledPlayerSeriesCount));
    }

    /**
     * Returns for each bet the number of games this bet has been called.   
     * @return for each bet the number of games this bet has been called as a Map<BetType, Double>.
     */
    public Map<BetType, Integer> getBetCount() {

        // transform StandardBaseGame into BetType
        Function<StandardBaseGame, BetType> gameToBetTypeFunction = new Function<StandardBaseGame, BetType>() {

            @Override
            public BetType apply(final StandardBaseGame stdBaseGame) {
                return stdBaseGame.getBet().getBetType();
            }
        };

        // group standard games by bet type 
        ImmutableListMultimap<BetType, StandardBaseGame> betTypeMultimap = Multimaps
                .index(this.gameSet.getStandardGames(), gameToBetTypeFunction);

        // build return object
        Map<BetType, Integer> toReturn = newHashMap();
        for (BetType betType : betTypeMultimap.keys()) {
            toReturn.put(betType, betTypeMultimap.get(betType).size());
        }
        this.betSeriesCount = toReturn.keySet().size();

        return toReturn;
    }

    /**
     * Returns an array corresponding to called bet COLORS.
     * @return an array corresponding to called bet COLORS.
     */
    public int[] getBetCountColors() {
        if (this.betSeriesCount == Integer.MIN_VALUE) {
            throw new IllegalStateException("you must call getBetCount() first");
        }
        return GuavaGameSetStatisticsComputer
                .convert(GuavaGameSetStatisticsComputer.COLORS.subList(0, this.betSeriesCount));
    }

    /**
     * TODO IMPROVE   
     * @return 
     */
    public Map<String, Integer> getFullBetCount() {

        // transform BaseGame into string description
        Function<BaseGame, String> gameToStringFunction = new Function<BaseGame, String>() {

            @Override
            public String apply(final BaseGame baseGame) {
                if (baseGame instanceof StandardBaseGame) {
                    return "Standard";
                } else if (baseGame instanceof BelgianBaseGame) {
                    return "Belge";
                } else if (baseGame instanceof PassedGame) {
                    return "Passe";
                } else if (baseGame instanceof PenaltyGame) {
                    return "Fausse donne";
                } else {
                    throw new IllegalArgumentException("GetFullBetCount() Unknow game type");
                }

            }
        };

        // group games by string description 
        ImmutableListMultimap<String, BaseGame> descriptionMultimap = Multimaps.index(this.gameSet.getGames(),
                gameToStringFunction);

        // build return object
        Map<String, Integer> toReturn = newHashMap();
        for (String description : descriptionMultimap.keys()) {
            toReturn.put(description, descriptionMultimap.get(description).size());
        }
        this.fullBetSeriesCount = toReturn.keySet().size();

        return toReturn;
    }

    /**
     * Returns an array corresponding to called bet COLORS.
     * @return an array corresponding to called bet COLORS.
     */
    public int[] getFullBetCountColors() {
        checkArgument(this.fullBetSeriesCount != Integer.MIN_VALUE, "you must call getFullBetCount() first");
        return GuavaGameSetStatisticsComputer
                .convert(GuavaGameSetStatisticsComputer.COLORS.subList(0, this.fullBetSeriesCount));
    }

    /**
     * Returns for each bet the number of games this king has been called.   
     * @return for each bet the number of games this king has been called as a Map<KingType, Double>.
     */
    public Map<KingType, Integer> getKingCount() {

        // transform StandardTarot5Game into BetType
        Function<StandardTarot5Game, KingType> gameToBetTypeFunction = new Function<StandardTarot5Game, KingType>() {

            @Override
            public KingType apply(final StandardTarot5Game stdBaseGame) {
                return stdBaseGame.getCalledKing().getKingType();
            }
        };

        // group standard games by bet type 
        ImmutableListMultimap<KingType, StandardTarot5Game> kingTypeMultimap = Multimaps
                .index(this.gameSet.getStandard5Games(), gameToBetTypeFunction);

        // build return object
        Map<KingType, Integer> toReturn = newHashMap();
        for (KingType kingType : kingTypeMultimap.keys()) {
            toReturn.put(kingType, kingTypeMultimap.get(kingType).size());
        }
        this.kingSeriesCount = toReturn.keySet().size();

        return toReturn;
    }

    /**
     * Returns an array corresponding to called king COLORS.
     * @return an array corresponding to called king COLORS.
     */
    public int[] getKingCountColors() {
        if (this.kingSeriesCount == Integer.MIN_VALUE) {
            throw new IllegalStateException("you must call getKingCount() first");
        }
        return GuavaGameSetStatisticsComputer
                .convert(GuavaGameSetStatisticsComputer.COLORS.subList(0, this.kingSeriesCount));
    }

    /**
     * Returns an array containing all the scores per game per player. 
     * @return an array containing all the scores per game per player as a List<double[]>. 
     */
    public List<double[]> getScores() {
        List<double[]> toReturn = new ArrayList<double[]>();

        // creates an array of all game scores for each player 
        for (Player player : this.gameSet.getPlayers()) {
            double[] playerScores = new double[this.gameSet.getGameCount() + 1];
            playerScores[0] = 0;
            for (int gameIndex = 0; gameIndex < this.gameSet.getGameCount(); ++gameIndex) {
                int score = this.gameSet.getGameSetScores().getIndividualResultsAtGameOfIndex(gameIndex + 1,
                        player);
                playerScores[gameIndex + 1] = score;
            }
            toReturn.add(playerScores);
        }

        return toReturn;
    }

    /**
     * Returns the maximum score ever.
     * @return the maximum score ever.
     */
    public int getMaxScoreEver() {
        return this.gameSet.getGameSetScores().getMaxScoreEver();
    }

    /**
     * Returns the minimum score ever.
     * @return the minimum score ever.
     */
    public int getMinScoreEver() {
        return this.gameSet.getGameSetScores().getMinScoreEver();
    }

    /**
     * Returns the minimum score ever for the given player..
     * @return the minimum score ever for the given player.
     */
    public int getMinScoreEverForPlayer(final Player player) {
        return this.gameSet.getGameSetScores().getMinScoreEverForPlayer(player);
    }

    /**
     * Returns the maximum score ever for the given player.
     * @return the maximum score ever for the given player.
     */
    public int getMaxScoreEverForPlayer(final Player player) {
        return this.gameSet.getGameSetScores().getMaxScoreEverForPlayer(player);
    }

    /**
     * Returns the maximum absolute score.
     * @return the maximum absolute score.
     */
    public int getMaxAbsoluteScore() {
        return this.gameSet.getGameSetScores().getMaxAbsoluteScore();
    }

    /**
     * Returns the player count.
     * @return the player count.
     */
    public int getPlayerCount() {
        return this.gameSet.getPlayers().size();
    }

    /**
     * Returns the game count.
     * @return the game count.
     */
    public int getGameCount() {
        return this.gameSet.getGameCount();
    }

    /**
     * Returns the player names as a String[].
     * @return the player names as a String[].
     */
    public String[] getPlayerNames() {
        return this.gameSet.getPlayers().getPlayerNames();
    }

    /**
     * Returns an array corresponding to the scores COLORS.
     * @return an array corresponding to the scores COLORS. 
     */
    public int[] getScoresColors() {
        ArrayList<Integer> lstColors = new ArrayList<Integer>();

        switch (this.gameSet.getGameStyleType()) {
        case Tarot3:
            if (this.gameSet.getPlayers().size() == 3) {
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_GREEN);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_BLUE);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_RED);
            } else {
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_GREEN);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_BLUE);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_YELLOW);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_RED);
            }
            break;
        case Tarot4:
            if (this.gameSet.getPlayers().size() == 4) {
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_GREEN);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_BLUE);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_YELLOW);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_RED);
            } else {
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_GREEN);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_BLUE);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_CYAN);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_YELLOW);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_RED);
            }
            break;
        case Tarot5:
            if (this.gameSet.getPlayers().size() == 5) {
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_GREEN);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_BLUE);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_CYAN);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_YELLOW);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_RED);
            } else {
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_GREEN);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_BLUE);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_CYAN);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_YELLOW);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_RED);
                lstColors.add(GuavaGameSetStatisticsComputer.COLOR_MAGENTA);
            }
            break;
        case None:
        default:
            throw new IllegalArgumentException("Incorrect game style type:" + this.gameSet.getGameStyleType());
        }
        return GuavaGameSetStatisticsComputer.convert(lstColors);
    }

    /**
     * Method to convert a List<Integer> into a int[]. Ugly code but there's no way to do it natively with the sdk...
     * @param toConvert
     * @return
     */
    private static int[] convert(final List<Integer> toConvert) {
        int[] toReturn = new int[toConvert.size()];
        for (int i = 0; i < toConvert.size(); ++i) {
            toReturn[i] = toConvert.get(i);
        }
        return toReturn;
    }

    /**
     * A Predicate to find all games where player is leader.
     * @author Nico
     *
     */
    protected class LeaderPlayerWinsPredicate implements Predicate<StandardBaseGame> {

        /**
         * The player to check.
         */
        private Player player;

        /**
         * @param player
         */
        protected LeaderPlayerWinsPredicate(final Player player) {
            this.player = player;
        }

        /* (non-Javadoc)
         * @see ch.lambdaj.function.matcher.Predicate#apply(java.lang.Object)
         */
        @Override
        public boolean apply(final StandardBaseGame game) {
            if (game == null) {
                return false;
            }
            return game.getLeadingPlayer() == this.player && game.isWinner(this.player);
        }
    }
}