/* Copyright (C) 2008,2009 Martin Günther <mintar@gmx.de> This file is part of GgpRatingSystem. GgpRatingSystem 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. GgpRatingSystem 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 GgpRatingSystem. If not, see <http://www.gnu.org/licenses/>. */ package ggpratingsystem; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; public class MatchSet { private final String id; private final int year; private final int round; private final int day; private final int matchSetNumber; // the number of the MatchSet played on this day (1 for the first etc.) private final Game game; private Set<Player> players = new HashSet<Player>(); private List<Match> matches = new LinkedList<Match>(); public MatchSet(String id, int year, int round, int day, int matchSetNumber, Game game) { super(); this.id = id; this.year = year; this.round = round; this.day = day; this.matchSetNumber = matchSetNumber; this.game = game; } public int getDay() { return day; } public Game getGame() { return game; } public int getMatchSetNumber() { return matchSetNumber; } public String getId() { return id; } public int getRound() { return round; } public int getYear() { return year; } public List<Match> getMatches() { LinkedList<Match> result = new LinkedList<Match>(); result.addAll(matches); return result; } public void addMatch(Match match) { matches.add(match); List<Player> players = match.getPlayers(); for (Player player : players) { this.players.add(player); } } @Override public String toString() { // String result = ""; // result += getId() + ";"; // result += getGame().toString() + ";"; // result += getYear() + ";"; // result += getRound() + ";"; // result += getDay() + ";"; // result += getMatchSetNumber() + ";"; // result += getMatches(); // return result; return getId(); } /** * @return overall (sum) score for all players in the match set */ public Map<Player, Double> overallScores() { Map<Player, Double> overallScores = new HashMap<Player, Double>(); for (Match match : matches) { List<Player> players = match.getPlayers(); for (int i = 0; i < players.size(); i++) { Player player = players.get(i); Double overallScore = overallScores.get(player); if (overallScore == null) { overallScore = 0.0; } overallScore += match.getScores().get(i); overallScores.put(player, overallScore); } } return overallScores; } /** * @return the number of matches that each player in the set has played */ public Map<Player, Integer> numMatchesPerPlayer() { Map<Player, Integer> numMatchesPerPlayer = new HashMap<Player, Integer>(); for (Match match : matches) { List<Player> players = match.getPlayers(); for (Player player : players) { Integer numMatches = numMatchesPerPlayer.get(player); if (numMatches == null) { numMatches = 0; } numMatches++; numMatchesPerPlayer.put(player, numMatches); } } return numMatchesPerPlayer; } /** * Calculates kind of a "prior probability" of the player scores in this * MatchSet: The expected score without taking the player's ratings into * account. * * The formula used is: * score of player p = (number of games where p has played role r) * x (mean score for role r) * */ public Map<Player, Double> expectedScoreWithoutRatings() { Map<Player, List<Integer>> roleCounts = countRoles(); List<Double> averageRoleScore = averageRoleScore(); Map<Player, Double> result = new HashMap<Player, Double>(); assert(this.getPlayers().equals(roleCounts.keySet())); Set<Player> players = this.getPlayers(); for (Player player: players) { List<Integer> roleCountsThisPlayer = roleCounts.get(player); int numRoles = roleCountsThisPlayer.size(); assert (numRoles == averageRoleScore.size()); Double expectedScore = 0.0; for (int i = 0; i < numRoles; i++) { expectedScore += roleCountsThisPlayer.get(i) * averageRoleScore.get(i); } result.put(player, expectedScore); } return result; } /** * this method is simply for debugging purposes */ public void printMatches() { for (Match match : matches) { match.print(); } } /** * @return the average score per match per player. */ public double averageScorePerMatch() { return averageScorePerPlayer() / averageNumMatches(); } /** * @return the average score per player, summed up over all matches the player played. */ public double averageScorePerPlayer() { return average(overallScores()); } /** * @return the average number of matches per player. */ public double averageNumMatches() { return average(numMatchesPerPlayer()); } /** * @return list of scores indicating what average score a role received */ public List<Double> averageRoleScore() { List<Double> result = new LinkedList<Double>(); int numRoles = game.getRoles().size(); for (int i = 0; i < numRoles; i++) { double sum = 0.0; for (Match match: matches) { sum += match.getScores().get(i); } result.add(Double.valueOf(sum / matches.size())); } return result; } public Set<Player> getPlayers() { return players; } /** * @return a list of integers, indicating how many times a player played a * certain role */ private Map<Player, List<Integer>> countRoles() { Map<Player, List<Integer>> roleCounts = new HashMap<Player, List<Integer>>(); for (Match match : matches) { List<Player> players = match.getPlayers(); for (int i = 0; i < players.size(); i++) { Player player = players.get(i); List<Integer> roleCountsThisPlayer = roleCounts.get(player); // if list doesn't exist, create it and fill if with the correct // number of Integers (one Integer for each role) if (roleCountsThisPlayer == null) { roleCountsThisPlayer = new LinkedList<Integer>(); for (int j = 0; j < players.size(); j++) { roleCountsThisPlayer.add(Integer.valueOf(0)); } } Integer roleCount = roleCountsThisPlayer.get(i); roleCount++; roleCountsThisPlayer.set(i, roleCount); roleCounts.put(player, roleCountsThisPlayer); } } return roleCounts; } /** * @param map * @return the average of the numbers in the map. */ private <K, V extends Number> double average(Map<K, V> map) { Set<Entry<K, V>> entries = map.entrySet(); double sum = 0.0; for (Entry<K, V> entry : entries) { sum += entry.getValue().doubleValue(); } return sum / entries.size(); } }