Elo rating system 模拟
1 package org.cc.foo_008; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.Random; 6 7 public class Main_006 { 8 9 public static void main(String[] args) { 10 11 EloRatingSystemDemo e=new EloRatingSystemDemo(); 12 13 e.show(); 14 15 // User u=e.gamer.get(new User().level).get(0); 16 // 17 // for(int i=0;i<999;i++){ 18 // e.play(u); 19 // } 20 // 21 // e.show(); 22 // 23 // System.out.println(u.rating); 24 25 //大部分情况下总能选出一个或少数几个等级比较高的(或比较低的...) 是这个算法比较神奇还是我的程序有问题呢... 26 for(int i=0;i<99999;i++){ 27 User u=e.randGetUser(); 28 e.play(u); 29 } 30 31 e.show(); 32 33 } 34 35 } 36 37 class EloRatingSystemDemo { 38 39 public List<List<User>> gamer=new ArrayList<>(); 40 //k值越大,升级就越快,绝大部分都处于越高位置 41 public double k=100; 42 43 public EloRatingSystemDemo() { 44 //十个级别 45 for(int i=0;i<10;i++){ 46 gamer.add(new ArrayList<>()); 47 } 48 49 //十个玩家 50 for(int i=0;i<1000;i++){ 51 User u=new User(); 52 gamer.get(u.level).add(u); 53 } 54 } 55 56 //为传入的玩家找到一个对手并开玩一局 57 public void play(User user){ 58 User river=user; 59 while(river==user){ 60 river=findRival(user); 61 } 62 fightAndRating(user,river); 63 } 64 65 //战斗并且评分(Elo Rating System) 66 public void fightAndRating(User u1,User u2){ 67 68 //暂时移除 69 gamer.get(u1.level).remove(u1); 70 gamer.get(u2.level).remove(u2); 71 72 //期望得分 73 double ea=1.0/(1+Math.pow(10,(u1.rating-u2.rating)/400.0)); 74 double eb=1.0/(1+Math.pow(10,(u2.rating-u1.rating)/400.0)); 75 76 //发生战斗...结果未知 77 int t=new Random().nextInt(3); 78 79 double t2=0; 80 if(t==0){ 81 //A赢 82 t2=u1.rating+k*(1-ea); 83 u1.rating=t2>0?t2:0; 84 t2=u2.rating+k*(0.5-eb); 85 u2.rating=t2>0?t2:0; 86 }else if(t==1){ 87 //B赢 88 t2=u1.rating+k*(0.5-ea); 89 u1.rating=t2>0?t2:0; 90 t2=u2.rating+k*(1-eb); 91 u2.rating=t2>0?t2:0; 92 }else if(t==2){ 93 //战平 94 t2=u1.rating+k*(0-ea);; 95 u1.rating=t2>0?t2:0; 96 t2=u2.rating+k*(0-eb); 97 u2.rating=t2>0?t2:0; 98 } 99 100 //放入 101 int level=(int) (u1.rating/500); 102 level=level<10?level:9; 103 u1.level=level; 104 gamer.get(u1.level).add(u1); 105 106 level=(int) (u2.rating/500); 107 level=level<10?level:9; 108 u2.level=level; 109 gamer.get(u2.level).add(u2); 110 111 } 112 113 //找到一个级别相当(左右偏移,实力最接近)的对手 114 public User findRival(User user){ 115 //如果当前级别只有自己一个人的话就偏移,否则的话说明可以找到同级别的玩家 116 int shift=gamer.get(user.level).size()==1?1:0; 117 while(true){ 118 119 boolean exit=true; 120 121 //优先匹配弱一些的对手 122 if(user.level-shift>=0){ 123 User u=findRival0(user.level-shift); 124 if(u!=null) return u; 125 exit=false; 126 } 127 if(user.level+shift<10){ 128 User u=findRival0(user.level+shift); 129 if(u!=null) return u; 130 exit=false; 131 } 132 133 if(exit) return null; 134 135 shift++; 136 } 137 } 138 139 //500分为一个级别,找在某个级别的对手 140 private User findRival0(int level){ 141 //检测这个级别是否有人 142 List<User> list=gamer.get(level); 143 if(list.isEmpty()) return null; 144 //随机选取一个对手 145 return list.get(new Random().nextInt(list.size())); 146 } 147 148 //随机获得一个用户 149 public User randGetUser(){ 150 while(true){ 151 List<User> list=gamer.get(new Random().nextInt(gamer.size())); 152 if(!list.isEmpty()) return list.get(new Random().nextInt(list.size())); 153 } 154 } 155 156 //打印所有玩家的信息: 157 public void show(){ 158 for(int i=0;i<gamer.size();i++){ 159 List<User> list=gamer.get(i); 160 System.out.printf("Level %d: ",i+1); 161 for(int j=0;j<list.size();j++){ 162 System.out.printf("%.2f ",list.get(j).rating); 163 } 164 System.out.println(); 165 } 166 System.out.println(); 167 } 168 169 } 170 171 //代表一个玩家,初始分数为1500 172 class User { 173 double rating=1500; 174 int level=(int) (rating/500); 175 }