Skip to content

Instantly share code, notes, and snippets.

@Noxville
Created July 4, 2014 21:12
Show Gist options
  • Save Noxville/a001569ab3499e3a3d02 to your computer and use it in GitHub Desktop.
Save Noxville/a001569ab3499e3a3d02 to your computer and use it in GitHub Desktop.
Monte Carlo Simulation
package twopee
import grails.transaction.Transactional
@Transactional
class HeadToHeadService {
def eloService
List<Double> headToHead(Team team1, Team team2) {
double t1_num = 0.0, t2_num = 0.0, t1_den =0.0, t2_den = 0.0
// Results from multivariate linear regression
// 6 month history = log(n) / e
// 1 month history = log(n) / 2
// monthly elo = 0.50 weighting
// current elo = 0.20 weighting
// 6 month history
Date sixMonths = new Date(System.currentTimeMillis() - (6L * 30 * 24 * 60 * 60 * 1000))
def matches = Mtch.findAllByRadiantTeamInListAndDireTeamInListAndDateGreaterThan(
[team1.teamName, team2.teamName], [team1.teamName, team2.teamName], sixMonths).sort { it.date.time }
if (matches.size()) {
double team1Winrate = (
matches.findAll { (it.winner == "Radiant") && (it.radiantTeam.toLowerCase() == team1.teamName.toLowerCase()) }.size() +
matches.findAll { (it.winner == "Dire") && (it.direTeam.toLowerCase() == team1.teamName.toLowerCase()) }.size() ) /
matches.size()
double team2Winrate = (
matches.findAll { (it.winner == "Radiant") && (it.radiantTeam.toLowerCase() == team2.teamName.toLowerCase()) }.size() +
matches.findAll { (it.winner == "Dire") && (it.direTeam.toLowerCase() == team2.teamName.toLowerCase()) }.size() ) /
matches.size()
double coefficient = (Math.log(matches.size())/ Math.exp(1))
t1_num += (coefficient * team1Winrate)
t2_num += (coefficient * team2Winrate)
t1_den += coefficient
t2_den += coefficient
}
// last month
Date lastMonth = new Date(System.currentTimeMillis() - (1L * 30 * 24 * 60 * 60 * 1000))
matches = Mtch.findAllByRadiantTeamInListAndDireTeamInListAndDateGreaterThan(
[team1.teamName, team2.teamName], [team1.teamName, team2.teamName], lastMonth).sort { it.date.time }
if (matches.size()) {
double team1Winrate = (
matches.findAll { (it.winner == "Radiant") && (it.radiantTeam.toLowerCase() == team1.teamName.toLowerCase()) }.size() +
matches.findAll { (it.winner == "Dire") && (it.direTeam.toLowerCase() == team1.teamName.toLowerCase()) }.size() ) /
matches.size()
double team2Winrate = (
matches.findAll { (it.winner == "Radiant") && (it.radiantTeam.toLowerCase() == team2.teamName.toLowerCase()) }.size() +
matches.findAll { (it.winner == "Dire") && (it.direTeam.toLowerCase() == team2.teamName.toLowerCase()) }.size() ) /
matches.size()
double coefficient = (Math.log(matches.size())/ 2.0)
t1_num += (coefficient * team1Winrate)
t2_num += (coefficient * team2Winrate)
t1_den += coefficient
t2_den += coefficient
}
// monthly elo
def averageLastMonth = eloService.averagesLastNPoints(new Date(), 30, [team1, team2])
if (averageLastMonth) {
def t1elo = averageLastMonth[team1.teamName]
def t2elo = averageLastMonth[team2.teamName]
def team1Winrate = 1.0 / ( 1.0 + Math.pow(10.0, ((t2elo-t1elo)/400.0)))
def team2Winrate = 1.0 - team1Winrate
def coefficient = 0.5
t1_num += (coefficient * team1Winrate)
t2_num += (coefficient * team2Winrate)
t1_den += coefficient
t2_den += coefficient
}
// monthly elo
if (true) { // just done to encapsulate calculations
def t1elo = team1.rating
def t2elo = team2.rating
def team1Winrate = 1.0 / ( 1.0 + Math.pow(10.0, ((t2elo-t1elo)/400.0)))
def team2Winrate = 1.0 - team1Winrate
def coefficient = 0.2
t1_num += (coefficient * team1Winrate)
t2_num += (coefficient * team2Winrate)
t1_den += coefficient
t2_den += coefficient
}
// team 1 winrate, team 2 winrate, confidence value
return [(t1_num/t1_den), (t2_num/t2_den), t1_den]
}
}
package twopee
class InternationalController {
def teamService
def eloService
def headToHeadService
class StatsEntity {
long teamId
String teamName
String prettyName
int wins
int loses
double rating
double averageWeekRating
double averageMonthRating
int groupWins = 0
int groupLoses = 0
}
class WLGroupEntity {
int wins = 0
int loses = 0
}
static Team boX(HashMap lookupMap, Team team1, Team team2, int gamesToWin, int advantage) {
int t1W = advantage, t2W = 0
while ((t1W != gamesToWin) && (t2W != gamesToWin)) {
if (Math.random() < lookupMap[team1][team2]) {
t1W++
}
else {
t2W++
}
}
return (t1W == gamesToWin) ? team1 : team2
}
static List<Team> boXOrder(HashMap lookupMap, Team team1, Team team2, int gamesToWin, int advantage) {
def winner = boX(lookupMap, team1, team2, gamesToWin, advantage)
def loser = (team1 == winner) ? team2 : team1
return [winner, loser]
}
def ti4() {
List<String> teamStr = ["Alliance", "Titan", "EG", "Fnatic.EU", "Nb", "VG", "NaVi", "DK", "iG", "C9",
"Empire", "Navi.US", "Arrow", "LGD.cn", "mouz", "Liquid"]
Map<Team, Map<Team, Double>> lookupMap = new HashMap<>()
List<Team> teams = []
HashMap<Team, Integer> groupWinners = new HashMap<>()
HashMap<Team, Integer> winnerCount = new HashMap<>()
HashMap<Team, Integer> runnerUpCount = new HashMap<>()
HashMap<Team, Integer> top4 = new HashMap<>()
HashMap<Team, Integer> top6 = new HashMap<>()
HashMap<Team, Integer> top10 = new HashMap<>()
HashMap<String, Integer> permutationKey = new HashMap<>()
for (String ts1: teamStr) {
Team t = Team.findByTeamName(ts1)
teams.add(t)
groupWinners[t] = 0, winnerCount[t] = 0, runnerUpCount[t] = 0
top4[t] = 0, top6[t] = 0, top10[t] = 0
}
for (Team t1: teams) {
lookupMap[t1] = new HashMap<Team, Double>()
for (Team t2: teams) {
if (t1 != t2) {
lookupMap[t1].put(t2, headToHeadService.headToHead(t1, t2)[0])
}
}
}
long N = 1000000L
for (int i = 0; i < N; ++i) {
Map<Team, Integer> groupWins = new HashMap<>()
teams.each { groupWins[it] = 0 }
// phase 2 - bo1 rr
for (Team t1: teams) {
for (Team t2: teams) {
if (t1.id != t2.id) {
groupWins[boX(lookupMap, t1, t2, 1, 0)]++
}
}
}
List<Team> topTen = groupWins.keySet().toList().sort { -groupWins[it] }.take(10)
groupWinners[topTen[0]] = groupWinners[topTen[0]] + 1
groupWinners[topTen[1]] = groupWinners[topTen[1]] + 1
topTen.each {
top10[it]++
}
// phase 3
def matchA = boXOrder(lookupMap, topTen[6], topTen[9], 3, 0)
def matchB = boXOrder(lookupMap, topTen[5], matchA[0], 3, 0)
def matchC = boXOrder(lookupMap, topTen[2], matchB[0], 3, 0)
def matchD = boXOrder(lookupMap, topTen[7], topTen[8], 3, 0)
def matchE = boXOrder(lookupMap, topTen[4], matchD[0], 3, 0)
def matchF = boXOrder(lookupMap, topTen[3], matchE[0], 3, 0)
// wb
def wb1 = boXOrder(lookupMap, topTen[0], matchF[0], 3, 0)
def wb2 = boXOrder(lookupMap, topTen[1], matchC[0], 3, 0)
def wbf = boXOrder(lookupMap, wb1[0], wb2[0], 3, 0)
// lb
def lb1 = boXOrder(lookupMap, matchE[1], matchC[1], 3, 0)
def lb2 = boXOrder(lookupMap, matchF[1], matchB[1], 3, 0)
def lb3 = boXOrder(lookupMap, lb1[0], wb2[1] , 3, 0)
def lb4 = boXOrder(lookupMap, lb2[0], wb1[1] , 3, 0)
def lb5 = boXOrder(lookupMap, lb3[0], lb4[0] , 3, 0)
def lbf = boXOrder(lookupMap, lb5[0], wbf[1] , 3, 0)
// gf
def gf = boXOrder(lookupMap, wbf[0], lbf[0] , 5, 0)
winnerCount[gf[0]]++
runnerUpCount[gf[1]]++
[gf[0], gf[1], lbf[1], lb5[1]].each {
top4[it]++
}
[gf[0], gf[1], lbf[1], lb5[1], lb4[1], lb3[1]].each {
top6[it]++
}
def m = [gf[0], gf[1], lbf[1], lb5[1]]
[lb4[1], lb3[1]].sort { it.teamName }.each {
m.add(it)
}
def key = [gf[0], gf[1], lbf[1], lb5[1]].collect { it.teamName }.join("|")
permutationKey[key] = 1 + (permutationKey[key] ?: 0)
}
print "\n --------------------\n"
print "Group Winners\n"
groupWinners.keySet().toList().sort { -groupWinners[it] }.each { t ->
print t.teamName + " :: " + (((double) groupWinners[t]) / N) + "\n"
}
print "\n --------------------\n"
print "First place\n"
winnerCount.keySet().toList().sort { -winnerCount[it] }.each { t ->
print t.teamName + " :: " + (((double) winnerCount[t]) / N) + "\n"
}
print "\n --------------------\n"
print "Runner up\n"
runnerUpCount.keySet().toList().sort { -runnerUpCount[it] }.each { t ->
print t.teamName + " :: " + (((double) runnerUpCount[t]) / N) + "\n"
}
print "\n --------------------\n"
print "Top 4\n"
top4.keySet().toList().sort { -top4[it] }.each { t ->
print t.teamName + " :: " + (((double) top4[t]) / N) + "\n"
}
print "\n --------------------\n"
print "Top 10\n"
top10.keySet().toList().sort { -top10[it] }.each { t ->
print t.teamName + " :: " + (((double) top10[t]) / N) + "\n"
}
print "\n --------------------\n"
print "Most likely permutations\n"
permutationKey.keySet().toList().sort { -permutationKey[it] }.each { t ->
double value = (((double) permutationKey[t]) / N)
if (value > 0.001) {
print t + " :: " + value + "\n"
}
}
[]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment