Reorganized odds structure.
This commit is contained in:
parent
242fbf2e56
commit
5d6f5882de
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user