diff --git a/build.xml b/build.xml index da22126..0013d84 100644 --- a/build.xml +++ b/build.xml @@ -9,6 +9,12 @@ + + + + + + @@ -24,8 +30,12 @@ + destdir="${build.dir}/classes"> + + + + + @@ -36,12 +46,19 @@ + + + + + + + diff --git a/lib/groovy-all-1.7.2.jar b/lib/groovy-all-1.7.2.jar deleted file mode 100644 index 7b50f70..0000000 Binary files a/lib/groovy-all-1.7.2.jar and /dev/null differ diff --git a/lib/log4j-1.2.15.jar b/lib/log4j-1.2.15.jar new file mode 100644 index 0000000..c930a6a Binary files /dev/null and b/lib/log4j-1.2.15.jar differ diff --git a/lib/miglayout-3.7.1-swing.jar b/lib/miglayout-3.7.1-swing.jar deleted file mode 100644 index 5a762c8..0000000 Binary files a/lib/miglayout-3.7.1-swing.jar and /dev/null differ diff --git a/log4j.properties b/log4j.properties new file mode 100644 index 0000000..aff155b --- /dev/null +++ b/log4j.properties @@ -0,0 +1,10 @@ +log4j.rootLogger=TRACE,stdout +log4j.com.jdbernard.teammaker=TRACE,file + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout + +log4j.appender.file=org.apache.log4j.FileAppender +log4j.appender.file.file=teammaker.log +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.pattern=%-5p (%c)[%t]: %m%n diff --git a/project.properties b/project.properties index 7b97afb..e53b4ae 100644 --- a/project.properties +++ b/project.properties @@ -1,6 +1,8 @@ +#Tue, 06 Jul 2010 06:30:26 -0500 #Mon Jul 05 23:10:39 CDT 2010 app.version=0.3.0 -build.number=47 +build.number=67 src.dir=src +lib.dir=lib build.dir=build app.name=team-maker diff --git a/src/com/jdbernard/teammaker/OddsCalculator.groovy b/src/com/jdbernard/teammaker/OddsCalculator.groovy index 84bb4f5..4043f2a 100644 --- a/src/com/jdbernard/teammaker/OddsCalculator.groovy +++ b/src/com/jdbernard/teammaker/OddsCalculator.groovy @@ -1,14 +1,26 @@ package com.jdbernard.teammaker +import org.apache.log4j.Logger + public class OddsCalculator { Map odds = [:] + protected Logger log = Logger.getLogger(getClass()) + public void recalculate(List players, int spotsOpen, PlayerChooser chooser) { + if (log.isTraceEnabled()) log.trace("Recalculating odds.") + // reset computed player odds odds = [:] + // first check the trivial case: more spots than players + if (spotsOpen >= players.size()) { + players.each { odds[(it)] = 1f } + return + } + /* this list will contain each possible selection path with * the odds at each node. It is a list of lists of lists:: * @@ -24,7 +36,7 @@ public class OddsCalculator { * ] */ - def oddsList = buildOdds([], players, spotsOpen) + def oddsList = buildOdds([], players, spotsOpen, chooser) /* The oddsMap is a condensed version of the oddsList, calculating * the overall probability of each path:: @@ -67,9 +79,12 @@ public class OddsCalculator { odds[(player)] = playerOdds } + + if (log.isTraceEnabled()) log.trace("Finished recalculating odds.") } - protected List buildOdds(List chosenPath, List players, int spotsOpen) { + protected List buildOdds(List chosenPath, List players, int spotsOpen, + PlayerChooser chooser) { def oddsList = [] if (spotsOpen == 0) return [chosenPath] @@ -78,7 +93,8 @@ public class OddsCalculator { def odds = chooser.getOdds(players, player) def newPath = chosenPath.clone() newPath << [player, odds] - oddsList.addAll(buildOdds(newPath, players - [player], spotsOpen - 1)) + oddsList.addAll(buildOdds(newPath, players - [player], + spotsOpen - 1, chooser)) } return oddsList diff --git a/src/com/jdbernard/teammaker/PlayerChooser.groovy b/src/com/jdbernard/teammaker/PlayerChooser.groovy index b040be9..ddddba6 100644 --- a/src/com/jdbernard/teammaker/PlayerChooser.groovy +++ b/src/com/jdbernard/teammaker/PlayerChooser.groovy @@ -1,13 +1,29 @@ package com.jdbernard.teammaker +import org.apache.log4j.Logger + public abstract class PlayerChooser { + // ======== CLASS DATA ======== // protected static final Random rand = new Random(System.currentTimeMillis()) + // ======== PUBLIC METHODS ======== // public abstract Player choose (def players) public abstract float getOdds(def players, Player player) + // ======== INSTANCE DATA ======== // + protected Logger log = Logger.getLogger(getClass()) + + // ======== NON-PUBLIC METHODS ======== // protected Player chooseRandomly(List choices) { + + if (log.isTraceEnabled()) + log.trace("Choosing randomly from: ${choices})") + choices.sort { rand.nextInt() } + + if (log.isTraceEnabled()) log.trace("Chose: ${choices[0]}") + + return choices[0] } } diff --git a/src/com/jdbernard/teammaker/PlayerListCellRenderer.groovy b/src/com/jdbernard/teammaker/PlayerListCellRenderer.groovy index 75b65e8..5c860c4 100644 --- a/src/com/jdbernard/teammaker/PlayerListCellRenderer.groovy +++ b/src/com/jdbernard/teammaker/PlayerListCellRenderer.groovy @@ -58,8 +58,8 @@ public class PlayerListCellRenderer extends JPanel implements ListCellRenderer { else setBorder(emptyBorder) if (showStats) { - int odds = Math.round(teamMaker.playerChooser.calculateOdds( - list.model, teamMaker.spotsOpen, value) * 100) + def odds = teamMaker.oddsCalculator.odds[(value)] + odds = odds ? Math.round(odds * 100) : "?" statsLabel.text = "${value.gamesSat} (${odds}%)" } diff --git a/src/com/jdbernard/teammaker/RandomPlayerChooser.groovy b/src/com/jdbernard/teammaker/RandomPlayerChooser.groovy index ba40877..5e03182 100644 --- a/src/com/jdbernard/teammaker/RandomPlayerChooser.groovy +++ b/src/com/jdbernard/teammaker/RandomPlayerChooser.groovy @@ -1,6 +1,6 @@ package com.jdbernard.teammaker -public class RandomPlayerChooser extends AbstractPlayerChooser { +public class RandomPlayerChooser extends PlayerChooser { public Player choose(def players) { def choices = [] diff --git a/src/com/jdbernard/teammaker/TeamMaker.groovy b/src/com/jdbernard/teammaker/TeamMaker.groovy index 540c3d4..eea7e04 100644 --- a/src/com/jdbernard/teammaker/TeamMaker.groovy +++ b/src/com/jdbernard/teammaker/TeamMaker.groovy @@ -8,6 +8,7 @@ import java.awt.BorderLayout import javax.swing.DefaultListModel import javax.swing.JFrame import javax.swing.JOptionPane +import org.apache.log4j.Logger public class TeamMaker { @@ -24,7 +25,10 @@ public class TeamMaker { def newGameButton def sittingList - AbstractPlayerChooser playerChooser = GameWeightedChooser.getInstance() + protected Logger log = Logger.getLogger(getClass()) + + PlayerChooser playerChooser = new WeightedChooser(hardLimit: 2) + OddsCalculator oddsCalculator = new OddsCalculator() class Observables { @Bindable boolean inGame = false @@ -134,6 +138,7 @@ public class TeamMaker { } } + } @@ -147,6 +152,7 @@ public class TeamMaker { } TeamMaker() { + log.fatal("Is this thing on?") init() } @@ -167,6 +173,13 @@ public class TeamMaker { player.name = name player.gamesSat = 0 sittingList.model.addElement(player) + + // recalculate odds + def players = sittingList.model.collect { it } + swing.doOutside { + oddsCalculator.recalculate(players, getSpotsOpen(), playerChooser) + swing.edt { sittingList.repaint() } + } } private void newGame() { @@ -177,9 +190,13 @@ public class TeamMaker { populate(team2List) model.inGame = true - //team1WinsButton.enabled = true - //team2WinsButton.enabled = true - //newGameButton.enabled = false + + // recalculate odds + def players = sittingList.model.collect { it } + swing.doOutside { + oddsCalculator.recalculate(players, getSpotsOpen(), playerChooser) + swing.edt { sittingList.repaint() } + } } private void declareWinner(def teamList) { @@ -188,12 +205,18 @@ public class TeamMaker { player.gamesSat = 0 sittingList.model.addElement(player) } + + //recalculate odds + def players = sittingList.model.collect { it } + swing.doOutside { + oddsCalculator.recalculate(players, getSpotsOpen(), playerChooser) + swing.edt { sittingList.repaint() } + } + teamList.model.clear() teamList.repaint() sittingList.repaint() model.inGame = false - //team1WinsButton.enabled = false - //team2WinsButton.enabled = false } private void populate(def teamList) { diff --git a/src/com/jdbernard/teammaker/WeightedChooser.groovy b/src/com/jdbernard/teammaker/WeightedChooser.groovy index 15f4fbd..5b80149 100644 --- a/src/com/jdbernard/teammaker/WeightedChooser.groovy +++ b/src/com/jdbernard/teammaker/WeightedChooser.groovy @@ -1,14 +1,20 @@ package com.jdbernard.teammaker -public abstract class WeightedChooser extends AbstractPlayerChooser { +public class WeightedChooser extends PlayerChooser { int hardLimit = 5 public Player choose(def players) { + // make a proper list + players = players.collect { it } def choices = [] + def threshold = getThreshold(players) - // find sitting threshold (longest sat - hard limit) - int threshold = (player.max { it.gamesSat }) - hardLimit + if (log.isTraceEnabled()) { + log.trace("Choosing a player weighted by games sat.") + log.trace("Players: $players") + log.trace("Threshold: $threshold") + } // add players, ignoring those past the hard limit players.each { player -> @@ -17,12 +23,28 @@ public abstract class WeightedChooser extends AbstractPlayerChooser { player.gamesSat.times { choices << player } } } + return chooseRandomly(choices) } public float getOdds(def players, Player player) { - def playerGames = player.gamesSat + 1 - def totalGames = players.sum { it.gamesSat + 1 } + def threshold = getThreshold(players) + + def playerGames = player.gamesSat >= threshold ? + player.gamesSat + 1 : 0 + + def totalGames = players.sum { + it.gamesSat >= threshold ? it.gamesSat + 1 : 0 + } + + if (log.isTraceEnabled()) + log.trace("Odds for $player: $playerGames / $totalGames = " + + ((float) playerGames / (float) totalGames)) + return (float) playerGames / (float) totalGames } + + protected int getThreshold(def players) { + return (players.max { it.gamesSat }).gamesSat - hardLimit + } }