From b0e94bd4cdc0653999c8af17d83ad4258831a485 Mon Sep 17 00:00:00 2001 From: "marcins78@gmail.com" Date: Wed, 25 Jan 2012 15:47:43 +0000 Subject: [PATCH] More accurate league results calculation. --- .../com/gempukku/lotro/db/LeagueMatchDAO.java | 63 ++++++++ .../gempukku/lotro/db/LeaguePointsDAO.java | 69 ++------ .../gempukku/lotro/league/LeagueService.java | 150 ++++++++++++++++++ .../gempukku/lotro/league/LeagueStanding.java | 43 +++++ .../gempukku/lotro/server/LeagueResource.java | 33 ++-- .../src/main/webapp/js/leagueResultsUi.js | 24 +-- 6 files changed, 298 insertions(+), 84 deletions(-) create mode 100644 gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/LeagueStanding.java diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/db/LeagueMatchDAO.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/db/LeagueMatchDAO.java index 96e9cfb39..6e545a9e3 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/db/LeagueMatchDAO.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/db/LeagueMatchDAO.java @@ -17,6 +17,69 @@ public class LeagueMatchDAO { _dbAccess = dbAccess; } + public Collection getLeagueMatches(League league) { + try { + Connection conn = _dbAccess.getDataSource().getConnection(); + try { + PreparedStatement statement = conn.prepareStatement("select winner, loser from league_match where league_type=?"); + try { + statement.setString(1, league.getType()); + ResultSet rs = statement.executeQuery(); + try { + Set result = new HashSet(); + while (rs.next()) { + String winner = rs.getString(1); + String loser = rs.getString(2); + + result.add(new LeagueMatch(winner, loser)); + } + return result; + } finally { + rs.close(); + } + } finally { + statement.close(); + } + } finally { + conn.close(); + } + } catch (SQLException exp) { + throw new RuntimeException(exp); + } + } + + public Collection getLeagueSerieMatches(League league, LeagueSerie leagueSerie) { + try { + Connection conn = _dbAccess.getDataSource().getConnection(); + try { + PreparedStatement statement = conn.prepareStatement("select winner, loser from league_match where league_type=? and season_type=?"); + try { + statement.setString(1, league.getType()); + statement.setString(2, leagueSerie.getType()); + ResultSet rs = statement.executeQuery(); + try { + Set result = new HashSet(); + while (rs.next()) { + String winner = rs.getString(1); + String loser = rs.getString(2); + + result.add(new LeagueMatch(winner, loser)); + } + return result; + } finally { + rs.close(); + } + } finally { + statement.close(); + } + } finally { + conn.close(); + } + } catch (SQLException exp) { + throw new RuntimeException(exp); + } + } + public Collection getPlayerMatchesPlayedOn(League league, LeagueSerie leagueSeason, String player) { try { Connection conn = _dbAccess.getDataSource().getConnection(); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/db/LeaguePointsDAO.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/db/LeaguePointsDAO.java index e338d70f8..4275098d2 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/db/LeaguePointsDAO.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/db/LeaguePointsDAO.java @@ -7,17 +7,12 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.LinkedList; -import java.util.List; +import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; public class LeaguePointsDAO { private DbAccess _dbAccess; - private Map> _leagueStandings = new ConcurrentHashMap>(); - private Map> _serieStandings = new ConcurrentHashMap>(); - public LeaguePointsDAO(DbAccess dbAccess) { _dbAccess = dbAccess; } @@ -42,23 +37,9 @@ public class LeaguePointsDAO { } catch (SQLException exp) { throw new RuntimeException(exp); } - - _leagueStandings.remove(league); - _serieStandings.remove(serie); } - public List getLeagueStandings(League league) { - List standings = _leagueStandings.get(league); - if (standings == null) { - synchronized (this) { - standings = loadLeagueStandings(league); - _leagueStandings.put(league, standings); - } - } - return standings; - } - - private List loadLeagueStandings(League league) { + public Map getLeaguePoints(League league) { try { Connection conn = _dbAccess.getDataSource().getConnection(); try { @@ -67,14 +48,7 @@ public class LeaguePointsDAO { statement.setString(1, league.getType()); ResultSet rs = statement.executeQuery(); try { - List result = new LinkedList(); - while (rs.next()) { - String playerName = rs.getString(1); - int sumPoints = rs.getInt(2); - int gamesPlayed = rs.getInt(3); - result.add(new Standing(playerName, sumPoints, gamesPlayed)); - } - return result; + return createPoints(rs); } finally { rs.close(); } @@ -89,18 +63,18 @@ public class LeaguePointsDAO { } } - public List getSerieStandings(League league, LeagueSerie serie) { - List standings = _serieStandings.get(serie); - if (standings == null) { - synchronized (this) { - standings = loadSerieStandings(league, serie); - _serieStandings.put(serie, standings); - } + private Map createPoints(ResultSet rs) throws SQLException { + Map result = new HashMap(); + while (rs.next()) { + String playerName = rs.getString(1); + int sumPoints = rs.getInt(2); + int gamesPlayed = rs.getInt(3); + result.put(playerName, new Points(sumPoints, gamesPlayed)); } - return standings; + return result; } - private List loadSerieStandings(League league, LeagueSerie serie) { + public Map getLeagueSeriePoints(League league, LeagueSerie serie) { try { Connection conn = _dbAccess.getDataSource().getConnection(); try { @@ -110,14 +84,7 @@ public class LeaguePointsDAO { statement.setString(2, serie.getType()); ResultSet rs = statement.executeQuery(); try { - List result = new LinkedList(); - while (rs.next()) { - String playerName = rs.getString(1); - int sumPoints = rs.getInt(2); - int gamesPlayed = rs.getInt(3); - result.add(new Standing(playerName, sumPoints, gamesPlayed)); - } - return result; + return createPoints(rs); } finally { rs.close(); } @@ -132,13 +99,11 @@ public class LeaguePointsDAO { } } - public static class Standing { - private String _player; + public static class Points { private int _points; private int _gamesPlayed; - public Standing(String player, int points, int gamesPlayed) { - _player = player; + public Points(int points, int gamesPlayed) { _points = points; _gamesPlayed = gamesPlayed; } @@ -147,10 +112,6 @@ public class LeaguePointsDAO { return _gamesPlayed; } - public String getPlayer() { - return _player; - } - public int getPoints() { return _points; } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/LeagueService.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/LeagueService.java index 11f18d5e6..688724421 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/LeagueService.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/LeagueService.java @@ -11,13 +11,23 @@ import com.gempukku.lotro.game.LotroGameMediator; import com.gempukku.lotro.logic.timing.GameResultListener; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; public class LeagueService { + private Comparator LEAGUE_STANDING_COMPARATOR = + new MultipleComparator( + new DescComparator(new PointsComparator()), + new GamesPlayedComparator(), + new DescComparator(new OpponentsWinComparator())); + private LeagueDAO _leagueDao; private LeagueSerieDAO _leagueSeasonDao; private LeaguePointsDAO _leaguePointsDao; private LeagueMatchDAO _leagueMatchDao; + private Map> _leagueStandings = new ConcurrentHashMap>(); + private Map> _leagueSerieStandings = new ConcurrentHashMap>(); + public LeagueService(LeagueDAO leagueDao, LeagueSerieDAO leagueSeasonDao, LeaguePointsDAO leaguePointsDao, LeagueMatchDAO leagueMatchDao) { _leagueDao = leagueDao; _leagueSeasonDao = leagueSeasonDao; @@ -53,6 +63,7 @@ public class LeagueService { _leagueMatchDao.addPlayedMatch(league, serie, winnerPlayerId, loser); _leaguePointsDao.addPoints(league, serie, winnerPlayerId, 2); _leaguePointsDao.addPoints(league, serie, loser, 1); + _leagueStandings.remove(league); } }); gameMediator.sendMessageToPlayers("This is a ranked game in " + league.getName()); @@ -61,6 +72,88 @@ public class LeagueService { } } + public List getLeagueStandings(League league) { + List leagueStandings = _leagueStandings.get(league); + if (leagueStandings == null) { + synchronized (this) { + leagueStandings = createLeagueStandings(league); + _leagueStandings.put(league, leagueStandings); + } + } + return leagueStandings; + } + + public List getLeagueSerieStandings(League league, LeagueSerie leagueSerie) { + List serieStandings = _leagueSerieStandings.get(leagueSerie); + if (serieStandings == null) { + synchronized (this) { + serieStandings = createLeagueStandings(league); + _leagueSerieStandings.put(leagueSerie, serieStandings); + } + } + return serieStandings; + } + + private List createLeagueSerieStandings(League league, LeagueSerie leagueSerie) { + final Map points = _leaguePointsDao.getLeagueSeriePoints(league, leagueSerie); + final Collection matches = _leagueMatchDao.getLeagueSerieMatches(league, leagueSerie); + + return createStandingsForMatchesAndPoints(points, matches); + } + + private List createLeagueStandings(League league) { + final Map points = _leaguePointsDao.getLeaguePoints(league); + final Collection matches = _leagueMatchDao.getLeagueMatches(league); + + return createStandingsForMatchesAndPoints(points, matches); + } + + private List createStandingsForMatchesAndPoints(Map points, Collection matches) { + Map> playerOpponents = new HashMap>(); + for (LeagueMatch leagueMatch : matches) { + appendPlayer(playerOpponents, leagueMatch.getWinner(), leagueMatch.getLoser()); + appendPlayer(playerOpponents, leagueMatch.getLoser(), leagueMatch.getWinner()); + } + + List leagueStandings = new LinkedList(); + for (Map.Entry playerPoints : points.entrySet()) { + LeagueStanding standing = new LeagueStanding(playerPoints.getKey(), playerPoints.getValue().getPoints(), playerPoints.getValue().getGamesPlayed()); + List opponents = playerOpponents.get(playerPoints.getKey()); + int opponentWins = 0; + int opponentGames = 0; + for (String opponent : opponents) { + final LeaguePointsDAO.Points opponentPoints = points.get(opponent); + opponentWins += opponentPoints.getPoints() - opponentPoints.getGamesPlayed(); + opponentGames += opponentPoints.getGamesPlayed(); + } + standing.setOpponentWin(opponentWins * 1f / opponentGames); + leagueStandings.add(standing); + } + + Collections.sort(leagueStandings, LEAGUE_STANDING_COMPARATOR); + + int standing = 0; + int position = 1; + LeagueStanding lastStanding = null; + for (LeagueStanding leagueStanding : leagueStandings) { + if (lastStanding == null || LEAGUE_STANDING_COMPARATOR.compare(lastStanding, lastStanding) != 0) + standing = position; + leagueStanding.setStanding(standing); + position++; + lastStanding = leagueStanding; + } + return leagueStandings; + } + + private void appendPlayer(Map> playerOpponents, String player, String opponent) { + List opponents = playerOpponents.get(player); + if (opponents == null) { + opponents = new LinkedList(); + playerOpponents.put(player, opponents); + } + opponents.add(opponent); + } + public boolean canPlayRankedGame(League league, LeagueSerie season, String player) { int maxMatches = season.getMaxMatches(); Collection playedInSeason = _leagueMatchDao.getPlayerMatchesPlayedOn(league, season, player); @@ -97,4 +190,61 @@ public class LeagueService { } return true; } + + private class MultipleComparator implements Comparator { + private Comparator[] _comparators; + + public MultipleComparator(Comparator... comparators) { + _comparators = comparators; + } + + @Override + public int compare(T o1, T o2) { + for (Comparator comparator : _comparators) { + int result = comparator.compare(o1, o2); + if (result != 0) + return result; + } + return 0; + } + } + + private class DescComparator implements Comparator { + private Comparator _comparator; + + private DescComparator(Comparator comparator) { + _comparator = comparator; + } + + @Override + public int compare(T o1, T o2) { + return _comparator.compare(o2, o1); + } + } + + private class PointsComparator implements Comparator { + @Override + public int compare(LeagueStanding o1, LeagueStanding o2) { + return o1.getPoints() - o2.getPoints(); + } + } + + private class GamesPlayedComparator implements Comparator { + @Override + public int compare(LeagueStanding o1, LeagueStanding o2) { + return o1.getGamesPlayed() - o2.getGamesPlayed(); + } + } + + private class OpponentsWinComparator implements Comparator { + @Override + public int compare(LeagueStanding o1, LeagueStanding o2) { + final float diff = o1.getOpponentWin() - o2.getOpponentWin(); + if (diff < 0) + return -1; + if (diff > 0) + return 1; + return 0; + } + } } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/LeagueStanding.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/LeagueStanding.java new file mode 100644 index 000000000..ab01e1484 --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/league/LeagueStanding.java @@ -0,0 +1,43 @@ +package com.gempukku.lotro.league; + +public class LeagueStanding { + private String _playerName; + private int _points; + private int _gamesPlayed; + private float _opponentWin; + private int _standing; + + public LeagueStanding(String playerName, int points, int gamesPlayed) { + _playerName = playerName; + _points = points; + _gamesPlayed = gamesPlayed; + } + + public int getGamesPlayed() { + return _gamesPlayed; + } + + public float getOpponentWin() { + return _opponentWin; + } + + public String getPlayerName() { + return _playerName; + } + + public int getPoints() { + return _points; + } + + public int getStanding() { + return _standing; + } + + public void setOpponentWin(float opponentWin) { + _opponentWin = opponentWin; + } + + public void setStanding(int standing) { + _standing = standing; + } +} diff --git a/gemp-lotr/gemp-lotr-web/src/main/java/com/gempukku/lotro/server/LeagueResource.java b/gemp-lotr/gemp-lotr-web/src/main/java/com/gempukku/lotro/server/LeagueResource.java index 2c3bfc57e..00d48383e 100644 --- a/gemp-lotr/gemp-lotr-web/src/main/java/com/gempukku/lotro/server/LeagueResource.java +++ b/gemp-lotr/gemp-lotr-web/src/main/java/com/gempukku/lotro/server/LeagueResource.java @@ -1,10 +1,11 @@ package com.gempukku.lotro.server; import com.gempukku.lotro.db.LeagueDAO; -import com.gempukku.lotro.db.LeaguePointsDAO; import com.gempukku.lotro.db.LeagueSerieDAO; import com.gempukku.lotro.db.vo.League; import com.gempukku.lotro.db.vo.LeagueSerie; +import com.gempukku.lotro.league.LeagueService; +import com.gempukku.lotro.league.LeagueStanding; import com.sun.jersey.spi.resource.Singleton; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -15,6 +16,7 @@ import javax.ws.rs.core.Context; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import java.text.DecimalFormat; import java.util.List; @Singleton @@ -23,9 +25,9 @@ public class LeagueResource extends AbstractResource { @Context private LeagueDAO _leagueDao; @Context - private LeagueSerieDAO _leagueSerieDao; + private LeagueService _leagueService; @Context - private LeaguePointsDAO _leaguePointsDao; + private LeagueSerieDAO _leagueSerieDao; @GET public Document getLeagueInformation() throws ParserConfigurationException { @@ -50,24 +52,20 @@ public class LeagueResource extends AbstractResource { serieElem.setAttribute("start", String.valueOf(serie.getStart())); serieElem.setAttribute("end", String.valueOf(serie.getEnd())); - final List standings = _leaguePointsDao.getSerieStandings(league, serie); - for (LeaguePointsDAO.Standing standing : standings) { + final List standings = _leagueService.getLeagueSerieStandings(league, serie); + for (LeagueStanding standing : standings) { Element standingElem = doc.createElement("standing"); - standingElem.setAttribute("player", standing.getPlayer()); - standingElem.setAttribute("points", String.valueOf(standing.getPoints())); - standingElem.setAttribute("gamesPlayed", String.valueOf(standing.getGamesPlayed())); + setStandingAttributes(standing, standingElem); serieElem.appendChild(standingElem); } leagueElem.appendChild(serieElem); } - List leagueStandings = _leaguePointsDao.getLeagueStandings(league); - for (LeaguePointsDAO.Standing standing : leagueStandings) { + List leagueStandings = _leagueService.getLeagueStandings(league); + for (LeagueStanding standing : leagueStandings) { Element standingElem = doc.createElement("leagueStanding"); - standingElem.setAttribute("player", standing.getPlayer()); - standingElem.setAttribute("points", String.valueOf(standing.getPoints())); - standingElem.setAttribute("gamesPlayed", String.valueOf(standing.getGamesPlayed())); + setStandingAttributes(standing, standingElem); leagueElem.appendChild(standingElem); } @@ -78,4 +76,13 @@ public class LeagueResource extends AbstractResource { return doc; } + + private void setStandingAttributes(LeagueStanding standing, Element standingElem) { + standingElem.setAttribute("player", standing.getPlayerName()); + standingElem.setAttribute("standing", String.valueOf(standing.getStanding())); + standingElem.setAttribute("points", String.valueOf(standing.getPoints())); + standingElem.setAttribute("gamesPlayed", String.valueOf(standing.getGamesPlayed())); + DecimalFormat format = new DecimalFormat("##0.00%"); + standingElem.setAttribute("opponentWin", format.format(standing.getOpponentWin())); + } } diff --git a/gemp-lotr/gemp-lotr-web/src/main/webapp/js/leagueResultsUi.js b/gemp-lotr/gemp-lotr-web/src/main/webapp/js/leagueResultsUi.js index 1790315a6..4c6199ce8 100644 --- a/gemp-lotr/gemp-lotr-web/src/main/webapp/js/leagueResultsUi.js +++ b/gemp-lotr/gemp-lotr-web/src/main/webapp/js/leagueResultsUi.js @@ -83,40 +83,30 @@ var LeagueResultsUI = Class.extend({ createStandingsTable: function(standings) { var standingsTable = $("
"); - standingsTable.append("StandingPlayerPointsGames playedStandingPlayerPointsGames played"); - - var lastPoints = -1; - var lastGamesPlayed = -1; - var currentStanding = -1; + standingsTable.append("StandingPlayerPointsGames playedOpp. Win %StandingPlayerPointsGames playedOpp. Win %"); var secondColumnBaseIndex = Math.ceil(standings.length / 2); for (var k = 0; k < secondColumnBaseIndex; k++) { var standing = standings[k]; + var currentStanding = standing.getAttribute("standing"); var player = standing.getAttribute("player"); var points = parseInt(standing.getAttribute("points")); var gamesPlayed = parseInt(standing.getAttribute("gamesPlayed")); - if (points != lastPoints || gamesPlayed != lastGamesPlayed) { - lastPoints = points; - lastGamesPlayed = gamesPlayed; - currentStanding = k + 1; - } + var opponentWinPerc = standing.getAttribute("opponentWin"); - standingsTable.append("" + currentStanding + "" + player + "" + points + "" + gamesPlayed + ""); + standingsTable.append("" + currentStanding + "" + player + "" + points + "" + gamesPlayed + "" + opponentWinPerc + ""); } for (var k = secondColumnBaseIndex; k < standings.length; k++) { var standing = standings[k]; + var currentStanding = standing.getAttribute("standing"); var player = standing.getAttribute("player"); var points = parseInt(standing.getAttribute("points")); var gamesPlayed = parseInt(standing.getAttribute("gamesPlayed")); - if (points != lastPoints || gamesPlayed != lastGamesPlayed) { - lastPoints = points; - lastGamesPlayed = gamesPlayed; - currentStanding = k + 1; - } + var opponentWinPerc = standing.getAttribute("opponentWin"); - $("tr:eq(" + (k - secondColumnBaseIndex + 1) + ")", standingsTable).append("" + currentStanding + "" + player + "" + points + "" + gamesPlayed + ""); + $("tr:eq(" + (k - secondColumnBaseIndex + 1) + ")", standingsTable).append("" + currentStanding + "" + player + "" + points + "" + gamesPlayed + "" + opponentWinPerc + ""); } return standingsTable;