User:Nfwu/ELO Sim
Jump to navigation
Jump to search
Used RR@H server code as reference. No licence - use and abuse.
Running the code as-is outputs ratings of bots A, B and C for this scenario:
A vs B = 25/75
A vs C = 75/25
B vs C = 25/75
Code:
package roborumble;
import java.util.*;
// There are faster ways of doing this,
// but I wanted to replicate the RR@H server as close as possible.
//
// So, here's an inefficent ELO simulator.
class EnemyStat {
double wins;
int benemy; //Looks like "Number of Battles agains this enemy"
}
class RobotStats {
RobotStats(String n){
this(n, 1600);
}
RobotStats(String n, double r){
scoremap = new HashMap<String, EnemyStat>();
post = false;
name = n;
battles = 0;
rating = r;
}
String name;
int battles;
double rating;
boolean post;
HashMap<String, EnemyStat> scoremap;
}
public class Test {
private static final double min_score = 0.0;
private static final double max_score = 1.0;
private static final double rating_change = 3.0;
static RobotStats[] stats;
public static void main(String[] args){
//stats = new RobotStats[4];
stats = new RobotStats[3];
stats[0] = new RobotStats("BotA 1.0");
stats[1] = new RobotStats("BotB 1.0");
stats[2] = new RobotStats("BotC 1.0");
//POST EXPERIMENT
//stats[3] = new RobotStats("Post", 2000);
//stats[3].post = true;
//A/B=25/75, A/C=75/25, BC=25/75
int rand;
for (int i=0;i<1000;i++){
rand = (int)(Math.random() * 6.0);
if (rand == 1){
//battleResults(0, 24.5+Math.random(), 1, 74.5+Math.random());
battleResults(0, 25, 1, 75);
} else if (rand == 2){
//battleResults(1, 74.5+Math.random(), 0, 24.5+Math.random());
battleResults(1, 75, 0, 25);
} else if (rand == 3){
//battleResults(0, 74.5+Math.random(), 2, 24.5+Math.random());
battleResults(0, 75, 2, 25);
} else if (rand == 4){
//battleResults(2, 24.5+Math.random(), 0, 74.5+Math.random());
battleResults(2, 25, 0, 75);
} else if (rand == 5){
//battleResults(1, 49.5+Math.random(), 2, 49.5+Math.random());
battleResults(1, 25, 2, 75);
} else {
//battleResults(2, 49.5+Math.random(), 1, 49.5+Math.random());
battleResults(2, 75, 1, 25);
}
//battleResults((int)(Math.random()*3), 50, 3, 50); //FROM POST EXPERIMENT
}
for (int i=0;i<stats.length;i++){
System.out.println(stats[i].name+" - Battles "+stats[i].battles+" - Rating "+stats[i].rating);
}
}
static void battleResults(int fid, double fscore, int sid, double sscore){
//Get stuff for first
double real1 = fscore / (fscore + sscore);
if (real1 == 1.0 || real1 == 0.0) return; //RR@H server does this
EnemyStat es1 = null;
es1 = stats[fid].scoremap.get(stats[sid].name); //First's enemy data of second
double wins1 = real1; if (es1 != null) wins1 = es1.wins;
int benemy1 = 0; if (es1 != null) benemy1 = es1.benemy;
//Get stuff for second
double real2 = 1.0 - real1;
EnemyStat es2 = null;
es2 = stats[sid].scoremap.get(stats[sid].name); //Second's enemy data of first
double wins2 = real1; if (es2 != null) wins2 = es2.wins;
int benemy2 = 0; if (es2 != null) benemy2 = es2.benemy;
//Calculate EnemyStat differences
wins1 = 0.7 * wins1 + 0.3 * real1;
wins2 = 0.7 * wins2 + 0.3 * real2;
benemy1++;
benemy2++;
//Store the EnemyStats away
if (es1 == null) {
es1 = new EnemyStat();
}
es1.wins = wins1;
es1.benemy = benemy1;
stats[fid].scoremap.put(stats[sid].name, es1); //First's enemy data of second
if (es2 == null) {
es2 = new EnemyStat();
}
es2.wins = wins2;
es2.benemy = benemy2;
stats[sid].scoremap.put(stats[fid].name, es2); //Second's enemy data of first
//Calculate rating change, anchored to all the other bots.
double change1 = 0;
double change2 = 0;
for (int i=0;i<stats.length;i++) {
//selectedrating = stats[i].rating;
//Do stuff for first
if (fid != i){
double expected = 1.0 / (1+Math.pow(20,(stats[i].rating-stats[fid].rating)/800));
expected = Math.max(Math.min(expected,max_score),min_score);
if (stats[fid].scoremap.get(stats[i].name) != null){
double selectedwins = stats[fid].scoremap.get(stats[i].name).wins;
selectedwins = Math.max(Math.min(selectedwins,max_score),min_score);
change1 += rating_change * (selectedwins - expected);
}
}
//Do stuff for second
if (sid != i){
double expected = 1.0 / (1+Math.pow(20,(stats[i].rating-stats[sid].rating)/800));
expected = Math.max(Math.min(expected,max_score),min_score);
if (stats[sid].scoremap.get(stats[i].name) != null){
double selectedwins = stats[sid].scoremap.get(stats[i].name).wins;
selectedwins = Math.max(Math.min(selectedwins,max_score),min_score);
change2 += rating_change * (selectedwins - expected);
}
}
}
if (!stats[fid].post) stats[fid].rating += change1;
if (!stats[sid].post) stats[sid].rating += change2;
stats[fid].battles++;
stats[sid].battles++;
}
}