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 }