Reorganized odds structure.
This commit is contained in:
		
							
								
								
									
										21
									
								
								build.xml
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								build.xml
									
									
									
									
									
								
							| @@ -9,6 +9,12 @@ | |||||||
|         </fileset> |         </fileset> | ||||||
|     </path> |     </path> | ||||||
|  |  | ||||||
|  |     <path id="lib.class.path"> | ||||||
|  |         <fileset dir="${lib.dir}"> | ||||||
|  |             <include name="*.jar"/> | ||||||
|  |         </fileset> | ||||||
|  |     </path> | ||||||
|  |  | ||||||
|     <taskdef name="groovyc" |     <taskdef name="groovyc" | ||||||
|         classpathref="groovy.class.path" |         classpathref="groovy.class.path" | ||||||
|         classname="org.codehaus.groovy.ant.Groovyc"/> |         classname="org.codehaus.groovy.ant.Groovyc"/> | ||||||
| @@ -24,8 +30,12 @@ | |||||||
|     <target name="compile" depends="init"> |     <target name="compile" depends="init"> | ||||||
|         <groovyc |         <groovyc | ||||||
|             srcdir="${src.dir}" |             srcdir="${src.dir}" | ||||||
|             destdir="${build.dir}/classes" |             destdir="${build.dir}/classes"> | ||||||
|             classpathref="groovy.class.path"/> |             <classpath> | ||||||
|  |                 <path refid="groovy.class.path"/> | ||||||
|  |                 <path refid="lib.class.path"/> | ||||||
|  |             </classpath> | ||||||
|  |         </groovyc> | ||||||
|     </target> |     </target> | ||||||
|  |  | ||||||
|     <target name="increment-build-number"> |     <target name="increment-build-number"> | ||||||
| @@ -36,12 +46,19 @@ | |||||||
|     </target> |     </target> | ||||||
|  |  | ||||||
|     <target name="build" depends="compile,increment-build-number"> |     <target name="build" depends="compile,increment-build-number"> | ||||||
|  |         <copy todir="${build.dir}/classes" file="log4j.properties"/> | ||||||
|         <unjar dest="${build.dir}/classes"> |         <unjar dest="${build.dir}/classes"> | ||||||
|             <fileset dir="${env.GROOVY_HOME}/embeddable"> |             <fileset dir="${env.GROOVY_HOME}/embeddable"> | ||||||
|                 <include name="*.jar"/> |                 <include name="*.jar"/> | ||||||
|             </fileset> |             </fileset> | ||||||
|         </unjar> |         </unjar> | ||||||
|  |  | ||||||
|  |         <unjar dest="${build.dir}/classes"> | ||||||
|  |             <fileset dir="${lib.dir}"> | ||||||
|  |                 <include name="*.jar"/> | ||||||
|  |             </fileset> | ||||||
|  |         </unjar> | ||||||
|  |  | ||||||
|         <jar |         <jar | ||||||
|             destfile="${build.dir}/${app.name}-${app.version}.${build.number}.jar" |             destfile="${build.dir}/${app.name}-${app.version}.${build.number}.jar" | ||||||
|             basedir="${build.dir}/classes"> |             basedir="${build.dir}/classes"> | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								lib/log4j-1.2.15.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								lib/log4j-1.2.15.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										10
									
								
								log4j.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								log4j.properties
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
| @@ -1,6 +1,8 @@ | |||||||
|  | #Tue, 06 Jul 2010 06:30:26 -0500 | ||||||
| #Mon Jul 05 23:10:39 CDT 2010 | #Mon Jul 05 23:10:39 CDT 2010 | ||||||
| app.version=0.3.0 | app.version=0.3.0 | ||||||
| build.number=47 | build.number=67 | ||||||
| src.dir=src | src.dir=src | ||||||
|  | lib.dir=lib | ||||||
| build.dir=build | build.dir=build | ||||||
| app.name=team-maker | app.name=team-maker | ||||||
|   | |||||||
| @@ -1,14 +1,26 @@ | |||||||
| package com.jdbernard.teammaker | package com.jdbernard.teammaker | ||||||
|  |  | ||||||
|  | import org.apache.log4j.Logger | ||||||
|  |  | ||||||
| public class OddsCalculator { | public class OddsCalculator { | ||||||
|  |  | ||||||
|     Map odds = [:] |     Map odds = [:] | ||||||
|  |  | ||||||
|  |     protected Logger log = Logger.getLogger(getClass()) | ||||||
|  |  | ||||||
|     public void recalculate(List players, int spotsOpen, PlayerChooser chooser) { |     public void recalculate(List players, int spotsOpen, PlayerChooser chooser) { | ||||||
|  |  | ||||||
|  |         if (log.isTraceEnabled()) log.trace("Recalculating odds.") | ||||||
|  |  | ||||||
|         // reset computed player odds |         // reset computed player odds | ||||||
|         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 |         /* this list will contain each possible selection path with | ||||||
|          * the odds at each node. It is a list of lists of lists:: |          * 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 oddsMap is a condensed version of the oddsList, calculating | ||||||
|          * the overall probability of each path:: |          * the overall probability of each path:: | ||||||
| @@ -67,9 +79,12 @@ public class OddsCalculator { | |||||||
|  |  | ||||||
|             odds[(player)] = playerOdds |             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 = [] |         def oddsList = [] | ||||||
|  |  | ||||||
|         if (spotsOpen == 0) return [chosenPath] |         if (spotsOpen == 0) return [chosenPath] | ||||||
| @@ -78,7 +93,8 @@ public class OddsCalculator { | |||||||
|             def odds = chooser.getOdds(players, player) |             def odds = chooser.getOdds(players, player) | ||||||
|             def newPath = chosenPath.clone() |             def newPath = chosenPath.clone() | ||||||
|             newPath << [player, odds] |             newPath << [player, odds] | ||||||
|             oddsList.addAll(buildOdds(newPath, players - [player], spotsOpen - 1)) |             oddsList.addAll(buildOdds(newPath, players - [player], | ||||||
|  |                 spotsOpen - 1, chooser)) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return oddsList |         return oddsList | ||||||
|   | |||||||
| @@ -1,13 +1,29 @@ | |||||||
| package com.jdbernard.teammaker | package com.jdbernard.teammaker | ||||||
|  |  | ||||||
|  | import org.apache.log4j.Logger | ||||||
|  |  | ||||||
| public abstract class PlayerChooser { | public abstract class PlayerChooser { | ||||||
|  |  | ||||||
|  |     // ======== CLASS DATA ======== // | ||||||
|     protected static final Random rand = new Random(System.currentTimeMillis()) |     protected static final Random rand = new Random(System.currentTimeMillis()) | ||||||
|  |  | ||||||
|  |     // ======== PUBLIC METHODS ======== // | ||||||
|     public abstract Player choose (def players) |     public abstract Player choose (def players) | ||||||
|     public abstract float getOdds(def players, Player player) |     public abstract float getOdds(def players, Player player) | ||||||
|  |  | ||||||
|  |     // ======== INSTANCE DATA ======== // | ||||||
|  |     protected Logger log = Logger.getLogger(getClass()) | ||||||
|  |  | ||||||
|  |     // ======== NON-PUBLIC METHODS ======== // | ||||||
|     protected Player chooseRandomly(List choices) { |     protected Player chooseRandomly(List choices) { | ||||||
|  |  | ||||||
|  |         if (log.isTraceEnabled()) | ||||||
|  |             log.trace("Choosing randomly from: ${choices})") | ||||||
|  |  | ||||||
|         choices.sort { rand.nextInt() } |         choices.sort { rand.nextInt() } | ||||||
|  |  | ||||||
|  |         if (log.isTraceEnabled()) log.trace("Chose: ${choices[0]}") | ||||||
|  |  | ||||||
|  |         return choices[0] | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -58,8 +58,8 @@ public class PlayerListCellRenderer extends JPanel implements ListCellRenderer { | |||||||
|         else setBorder(emptyBorder) |         else setBorder(emptyBorder) | ||||||
|          |          | ||||||
|         if (showStats) { |         if (showStats) { | ||||||
|             int odds = Math.round(teamMaker.playerChooser.calculateOdds( |             def odds = teamMaker.oddsCalculator.odds[(value)] | ||||||
|                 list.model, teamMaker.spotsOpen, value) * 100) |             odds = odds ? Math.round(odds * 100) : "?" | ||||||
|             statsLabel.text = "${value.gamesSat} (${odds}%)" |             statsLabel.text = "${value.gamesSat} (${odds}%)" | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package com.jdbernard.teammaker | package com.jdbernard.teammaker | ||||||
|  |  | ||||||
| public class RandomPlayerChooser extends AbstractPlayerChooser { | public class RandomPlayerChooser extends PlayerChooser { | ||||||
|  |  | ||||||
|     public Player choose(def players) {  |     public Player choose(def players) {  | ||||||
|         def choices = [] |         def choices = [] | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ import java.awt.BorderLayout | |||||||
| import javax.swing.DefaultListModel | import javax.swing.DefaultListModel | ||||||
| import javax.swing.JFrame | import javax.swing.JFrame | ||||||
| import javax.swing.JOptionPane | import javax.swing.JOptionPane | ||||||
|  | import org.apache.log4j.Logger | ||||||
|  |  | ||||||
| public class TeamMaker { | public class TeamMaker { | ||||||
|  |  | ||||||
| @@ -24,7 +25,10 @@ public class TeamMaker { | |||||||
|     def newGameButton |     def newGameButton | ||||||
|     def sittingList |     def sittingList | ||||||
|  |  | ||||||
|     AbstractPlayerChooser playerChooser = GameWeightedChooser.getInstance() |     protected Logger log = Logger.getLogger(getClass()) | ||||||
|  |  | ||||||
|  |     PlayerChooser playerChooser = new WeightedChooser(hardLimit: 2) | ||||||
|  |     OddsCalculator oddsCalculator = new OddsCalculator() | ||||||
|  |  | ||||||
|     class Observables { |     class Observables { | ||||||
|         @Bindable boolean inGame = false |         @Bindable boolean inGame = false | ||||||
| @@ -134,6 +138,7 @@ public class TeamMaker { | |||||||
|  |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -147,6 +152,7 @@ public class TeamMaker { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     TeamMaker() { |     TeamMaker() { | ||||||
|  |         log.fatal("Is this thing on?") | ||||||
|         init() |         init() | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -167,6 +173,13 @@ public class TeamMaker { | |||||||
|         player.name = name |         player.name = name | ||||||
|         player.gamesSat = 0 |         player.gamesSat = 0 | ||||||
|         sittingList.model.addElement(player) |         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() { |     private void newGame() { | ||||||
| @@ -177,9 +190,13 @@ public class TeamMaker { | |||||||
|             populate(team2List) |             populate(team2List) | ||||||
|  |  | ||||||
|         model.inGame = true |         model.inGame = true | ||||||
|         //team1WinsButton.enabled = true |  | ||||||
|         //team2WinsButton.enabled = true |         // recalculate odds | ||||||
|         //newGameButton.enabled = false |         def players = sittingList.model.collect { it } | ||||||
|  |         swing.doOutside { | ||||||
|  |             oddsCalculator.recalculate(players, getSpotsOpen(), playerChooser) | ||||||
|  |             swing.edt { sittingList.repaint() } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void declareWinner(def teamList) { |     private void declareWinner(def teamList) { | ||||||
| @@ -188,12 +205,18 @@ public class TeamMaker { | |||||||
|             player.gamesSat = 0 |             player.gamesSat = 0 | ||||||
|             sittingList.model.addElement(player) |             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.model.clear() | ||||||
|         teamList.repaint() |         teamList.repaint() | ||||||
|         sittingList.repaint() |         sittingList.repaint() | ||||||
|         model.inGame = false |         model.inGame = false | ||||||
|         //team1WinsButton.enabled = false |  | ||||||
|         //team2WinsButton.enabled = false |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void populate(def teamList) { |     private void populate(def teamList) { | ||||||
|   | |||||||
| @@ -1,14 +1,20 @@ | |||||||
| package com.jdbernard.teammaker | package com.jdbernard.teammaker | ||||||
|  |  | ||||||
| public abstract class WeightedChooser extends AbstractPlayerChooser { | public class WeightedChooser extends PlayerChooser { | ||||||
|  |  | ||||||
|     int hardLimit = 5 |     int hardLimit = 5 | ||||||
|  |  | ||||||
|     public Player choose(def players) { |     public Player choose(def players) { | ||||||
|  |         // make a proper list | ||||||
|  |         players = players.collect { it } | ||||||
|         def choices = [] |         def choices = [] | ||||||
|  |         def threshold = getThreshold(players) | ||||||
|  |  | ||||||
|         // find sitting threshold (longest sat - hard limit) |         if (log.isTraceEnabled()) { | ||||||
|         int threshold = (player.max { it.gamesSat }) - hardLimit |             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 |         // add players, ignoring those past the hard limit | ||||||
|         players.each { player -> |         players.each { player -> | ||||||
| @@ -17,12 +23,28 @@ public abstract class WeightedChooser extends AbstractPlayerChooser { | |||||||
|                 player.gamesSat.times { choices << player } |                 player.gamesSat.times { choices << player } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return chooseRandomly(choices) |         return chooseRandomly(choices) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public float getOdds(def players, Player player) { |     public float getOdds(def players, Player player) { | ||||||
|         def playerGames = player.gamesSat + 1 |         def threshold = getThreshold(players) | ||||||
|         def totalGames = players.sum { it.gamesSat + 1 } |  | ||||||
|  |         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 |         return (float) playerGames / (float) totalGames | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     protected int getThreshold(def players) { | ||||||
|  |         return (players.max { it.gamesSat }).gamesSat - hardLimit | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user