/[LeafOK_CVS]/pvpgn-1.7.4/src/bnetd/ladder_calc.c
ViewVC logotype

Contents of /pvpgn-1.7.4/src/bnetd/ladder_calc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (show annotations) (vendor branch)
Tue Jun 6 03:41:37 2006 UTC (19 years, 9 months ago) by sysadm
Branch: GNU, MAIN
CVS Tags: pvpgn_1-7-4-0_MIL, arelease, HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
no message

1 /*
2 * Copyright (C) 1999 Rob Crittenden (rcrit@greyoak.com)
3 * Copyright (C) 1999,2000 Ross Combs (rocombs@cs.nmsu.edu)
4 * Copyright (C) 1999,2000 D.Moreaux (vapula@linuxbe.org)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20 #include "common/setup_before.h"
21 #include <math.h>
22 #ifdef HAVE_STRING_H
23 # include <string.h>
24 #else
25 # ifdef HAVE_STRINGS_H
26 # include <strings.h>
27 # endif
28 #endif
29 #include "account.h"
30 #include "account_wrap.h"
31 #include "common/eventlog.h"
32 #include "game.h"
33 #include "common/tag.h"
34 #include "ladder.h"
35 #include "ladder_calc.h"
36 #include "common/xalloc.h"
37 #include "common/setup_after.h"
38
39
40 static double probability(unsigned int a, unsigned int b) ;
41 static int coefficient(t_account * account, t_clienttag clienttag, t_ladder_id id);
42
43 static double two_player(unsigned int *rating);
44
45 static double three_player(unsigned int *rating);
46
47 static double four_player(unsigned int *rating);
48
49 static double five_player(unsigned int *rating);
50 static double five_f1(int a, int b, int c, int d, int e) ;
51 static double five_f2(int a, int b, int c) ;
52
53 static double six_player(unsigned int *rating);
54 static double six_f1(int a, int b, int c, int d, int e, int f) ;
55 static double six_f2(int a, int b, int c, int d, int e, int f) ;
56 static double six_f3(int a, int b, int c, int d) ;
57
58 static double seven_player(unsigned int *rating);
59 static double seven_f1(int a, int b, int c, int d, int e, int f, int g) ;
60 static double seven_f2(int a, int b, int c, int d, int e, int f, int g) ;
61
62 static double eight_player(unsigned int *rating);
63 static double eight_f1(int a, int b, int c, int d, int e, int f, int g) ;
64 static double eight_f2(int a, int b, int c, int d, int e, int f, int g) ;
65 static double eight_f3(int a, int b, int c, int d, int e) ;
66
67 /*
68 * Compute probability of winning using the Elo system
69 *
70 * The formula is:
71 *
72 * D = rating(player a) - rating(player b)
73 *
74 * 1
75 * Pwin(D) = ------------------
76 * -(D / 400)
77 * 1 + 10
78 */
79 static double probability(unsigned int a, unsigned int b)
80 {
81 double i, j;
82
83 i = (((double)a) - ((double)b)) / 400.0;
84
85 j = pow(10.0,-i);
86
87 return (1.0 / (1.0+j));
88 }
89
90
91 /*
92 * This is the coefficient k which is meant to enhance the
93 * effect of the Elo system where more experienced players
94 * will gain fewer points when playing against newbies, and
95 * newbies will gain massive points if they win against an
96 * experienced player. It also helps stabilize a player's
97 * rating after they have played 30 games or so.
98 *
99 * K=50 for new players
100 * K=30 for players who have played 30 or more ladder games
101 * K=20 for players who have attained a rating of 2400 or higher
102 */
103 static int coefficient(t_account * account, t_clienttag clienttag, t_ladder_id id)
104 {
105 int const total_ladder_games=account_get_ladder_wins(account,clienttag,id) +
106 account_get_ladder_losses(account,clienttag,id) +
107 account_get_ladder_disconnects(account,clienttag,id);
108
109 if (total_ladder_games < 30)
110 return 50;
111
112 if (account_get_ladder_rating(account,clienttag,id) < 2400)
113 return 30;
114
115 return 20;
116 }
117
118
119 /*
120 * The Elo system only handles 2 players, these functions extend
121 * the calculation to different numbers of players as if they were
122 * in a tournament. It turns out the math for this is really ugly,
123 * so we have hardcoded the equations for every number of players.
124 */
125 static double two_player(unsigned int *rating)
126 {
127 unsigned int a,b;
128 double ab;
129
130 a = rating[0];
131 b = rating[1];
132
133 ab = probability(a,b);
134
135 return ab;
136 }
137
138 static double three_player(unsigned int *rating)
139 {
140 unsigned int a,b,c;
141 double ab,ac,bc,cb;
142
143 a = rating[0];
144 b = rating[1];
145 c = rating[2];
146
147 ab = probability(a,b);
148 ac = probability(a,c);
149 bc = probability(b,c);
150 cb = 1.0 - bc;
151
152 return (2*(ab*ac)+(bc*ab)+(cb*ac))/3;
153 }
154
155 static double four_player(unsigned int *rating)
156 {
157 unsigned int a,b,c,d;
158 double ab,ac,ad,bc,bd,cb,cd,db,dc;
159
160 a = rating[0];
161 b = rating[1];
162 c = rating[2];
163 d = rating[3];
164
165
166 ab = probability(a,b);
167 ac = probability(a,c);
168 ad = probability(a,d);
169 bc = probability(b,c);
170 bd = probability(b,d);
171 cd = probability(c,d);
172 cb = 1.0 - bc;
173 db = 1.0 - bd;
174 dc = 1.0 - cd;
175
176 return (ab*ac*(cd+bd)+ac*ad*(db+cb)+ab*ad*(dc+bc))/3;
177 }
178
179
180 /* [Denis MOREAUX <vapula@linuxbe.org>, 10 Apr 2000]
181 *
182 * C D E A D E The winner may be in the
183 * A B C E B C A E 2 players or the 3 players
184 * A C B A group. In either case, a
185 * A A second player must be choosen
186 * to be either the one playing
187 * against A in the 2-players subtree or being the winner
188 * of the 2-player subtree if A is in the 3-players subtree.
189 */
190
191 static double five_player(unsigned int *rating)
192 {
193 unsigned int a,b,c,d,e;
194
195 a = rating[0];
196 b = rating[1];
197 c = rating[2];
198 d = rating[3];
199 e = rating[4];
200
201 return (five_f1(a,b,c,d,e)+five_f1(a,c,d,e,b)+
202 five_f1(a,d,e,b,c)+five_f1(a,e,b,c,d))/30;
203 }
204
205 /* [Denis MOREAUX <vapula@linuxbe.org>, 10 Apr 2000
206 *
207 * Two cases to treat : AB-CDE and BC-ADE.
208 * in both cases, A win against B.
209 * In the first case, A win over the winner of a 3-players game
210 * (3 possible winners).
211 * In the second case, B win over one of the three other and A is in
212 * the 3-players game.
213 */
214
215 static double five_f1(int a, int b, int c, int d, int e)
216 {
217 double ab,ac,ad,ae,bc,bd,be;
218
219 ab = probability(a,b);
220 ac = probability(a,c);
221 ad = probability(a,d);
222 ae = probability(a,e);
223 bc = probability(b,c);
224 bd = probability(b,d);
225 be = probability(b,e);
226
227 return ab*(ac*five_f2(c,d,e)+ad*five_f2(d,e,c)+ae*five_f2(e,c,d)+
228 bc*five_f2(a,d,e)+bd*five_f2(a,c,e)+be*five_f2(a,c,d));
229 }
230
231 static double five_f2(int a, int b, int c)
232 {
233 double ab,ac,bc,cb;
234
235 ab = probability(a,b);
236 ac = probability(a,c);
237 bc = probability(b,c);
238 cb = 1.0 - bc;
239
240 return (2*(ab*ac)+bc*ab+cb*ac);
241 }
242
243
244 static double six_player(unsigned int *rating)
245 {
246 unsigned int a,b,c,d,e,f;
247
248 a = rating[0];
249 b = rating[1];
250 c = rating[2];
251 d = rating[3];
252 e = rating[4];
253 f = rating[5];
254
255 /* A B C D
256 * A C E F
257 * A E
258 * A
259 */
260
261 return (six_f1(a,b,c,d,e,f)+ /* A is in group of 4 */
262 six_f1(a,b,c,e,d,f)+
263 six_f1(a,b,e,d,c,f)+
264 six_f1(a,e,c,d,b,f)+
265 six_f1(a,b,c,f,d,e)+
266 six_f1(a,b,f,d,c,e)+
267 six_f1(a,f,c,d,b,e)+
268 six_f1(a,e,f,b,c,d)+
269 six_f1(a,e,f,c,b,d)+
270 six_f1(a,e,f,d,b,c)+
271 six_f2(a,b,c,d,e,f)+ /* A is in group of 2 */
272 six_f2(a,c,b,d,e,f)+
273 six_f2(a,d,b,c,e,f)+
274 six_f2(a,e,b,c,d,f)+
275 six_f2(a,f,b,c,d,e))/45;
276 }
277
278
279 /* ABCD = group of 4, EF = group of 2, A must win */
280 /* D.Moreaux, 10 Apr 2000: changed double to int for the parameters */
281
282 static double six_f1(int a, int b, int c, int d, int e, int f)
283 {
284 double ab,ac,ad,bc,bd,cb,cd,db,dc,ef,fe,ae,af;
285
286 ab = probability(a,b);
287 ac = probability(a,c);
288 ad = probability(a,d);
289 ae = probability(a,e);
290 af = probability(a,f);
291 bc = probability(b,c);
292 bd = probability(b,d);
293 cd = probability(c,d);
294 ef = probability(e,f);
295 cb = 1.0 - bc;
296 db = 1.0 - bd;
297 dc = 1.0 - cd;
298 fe = 1.0 - ef;
299 return (ab*ac*(cd+bd)+ac*ad*(db+cb)+ab*ad*(dc+bc))*(ef*ae+fe*af);
300 }
301
302
303 /* AB is group of 2, CDEF is group of 4, A must win */
304
305 static double six_f2(int a, int b, int c, int d, int e, int f)
306 {
307 double ab,ac,ad,ae,af;
308
309 ab = probability(a,b);
310 ac = probability(a,c);
311 ad = probability(a,d);
312 ae = probability(a,e);
313 af = probability(a,f);
314
315 return (six_f3(c,d,e,f)*ab*ac+
316 six_f3(d,c,e,f)*ab*ad+
317 six_f3(e,c,d,f)*ab*ae+
318 six_f3(f,c,d,e)*ab*af);
319 }
320
321
322 /* ABCD is group of 4, A win */
323
324 static double six_f3(int a, int b, int c, int d)
325 {
326 double ab,ac,ad,bc,bd,cb,cd,db,dc;
327
328 ab = probability(a,b);
329 ac = probability(a,c);
330 ad = probability(a,d);
331 bc = probability(b,c);
332 bd = probability(b,d);
333 cd = probability(c,d);
334 cb = 1.0 - bc;
335 db = 1.0 - bd;
336 dc = 1.0 - cd;
337
338 return (ab*ac*(cd+bd)+ac*ad*(db+cb)+ab*ad*(dc+bc));
339 }
340
341
342 static double seven_player(unsigned int *rating)
343 {
344 unsigned int a,b,c,d,e,f,g;
345
346 a = rating[0];
347 b = rating[1];
348 c = rating[2];
349 d = rating[3];
350 e = rating[4];
351 f = rating[5];
352 g = rating[6];
353
354 return (seven_f1(a,b,c,d,e,f,g)+seven_f1(a,c,b,d,e,f,g)+
355 seven_f1(a,d,c,b,e,f,g)+seven_f1(a,e,c,d,b,f,g)+
356 seven_f1(a,f,c,d,e,b,g)+seven_f1(a,g,c,d,e,f,b))/45;
357 }
358
359 static double seven_f1(int a, int b, int c, int d, int e, int f, int g)
360 {
361
362 return seven_f2(a,b,c,d,e,f,g)+seven_f2(a,b,d,c,e,f,g)+
363 seven_f2(a,b,e,d,c,f,g)+seven_f2(a,b,f,d,e,c,g)+
364 seven_f2(a,b,g,d,e,f,c);
365 }
366
367 static double seven_f2(int a, int b, int c, int d, int e, int f, int g)
368 {
369 double ab,ac,ad,ae,af,ag,bc,bd,be,bf,bg,cd,ce,cf,cg;
370 double de,df,dg,ed,ef,eg,fd,fe,fg,gd,ge,gf;
371 ab = probability(a,b);
372 ac = probability(a,c);
373 ad = probability(a,d);
374 ae = probability(a,e);
375 af = probability(a,f);
376 ag = probability(a,g);
377 bc = probability(b,c);
378 bd = probability(b,d);
379 be = probability(b,e);
380 bf = probability(b,f);
381 bg = probability(b,g);
382 cd = probability(c,d);
383 ce = probability(c,e);
384 cf = probability(c,f);
385 cg = probability(c,g);
386 de = probability(d,e);
387 df = probability(d,f);
388 dg = probability(d,g);
389 ef = probability(e,f);
390 eg = probability(e,g);
391 fg = probability(f,g);
392 ed = 1.0 - de;
393 fd = 1.0 - df;
394 gd = 1.0 - dg;
395 fe = 1.0 - ef;
396 ge = 1.0 - eg;
397 gf = 1.0 - fg;
398
399 return
400 ab*(
401 (ac+bc)*
402 (ad*(de*df*(fg+eg)+df*dg*(ge+fe)+de*dg*(gf+ef))+ /* 4:d win */
403 ae*(ed*ef*(fg+dg)+ef*eg*(gd+fd)+ed*eg*(gf+df))+ /* 4:e win */
404 af*(fe*fd*(dg+eg)+fd*fg*(ge+de)+fe*fg*(gd+ed))+ /* 4:f win */
405 ag*(ge*gf*(fd+ed)+gf*gd*(de+fe)+ge*gd*(df+ef)))+ /* 4:g win */
406 bc*
407 ((bd+cd)*(ae*af*(fg+eg)+af*ag*(ge+fe)+ae*ag*(gf+ef))+ /* 3:d */
408 (be+ce)*(ad*af*(fg+dg)+af*ag*(ad+ad)+ad*ag*(gf+df))+ /* 3:e */
409 (bf+cf)*(ae*ad*(dg+eg)+ad*ag*(ge+de)+ae*ag*(gd+ed))+ /* 3:f */
410 (bg+cg)*(ae*af*(fd+ed)+af*ad*(de+fe)+ae*ad*(df+ef)))); /* 3:g */
411
412 }
413
414 static double eight_player(unsigned int *rating)
415 {
416 unsigned int a,b,c,d,e,f,g,h;
417 double ab,ac,ad,ae,af,ag,ah;
418
419 a = rating[0];
420 b = rating[1];
421 c = rating[2];
422 d = rating[3];
423 e = rating[4];
424 f = rating[5];
425 g = rating[6];
426 h = rating[7];
427
428 ab = probability(a,b);
429 ac = probability(a,c);
430 ad = probability(a,d);
431 ae = probability(a,e);
432 af = probability(a,f);
433 ag = probability(a,g);
434 ah = probability(a,h);
435
436 /* First against A may be one from seven */
437
438 return (eight_f1(a,c,d,e,f,g,h)*ab+
439 eight_f1(a,b,d,e,f,g,h)*ac+
440 eight_f1(a,b,c,e,f,g,h)*ad+
441 eight_f1(a,b,c,d,f,g,h)*ae+
442 eight_f1(a,b,c,d,e,g,h)*af+
443 eight_f1(a,b,c,d,e,f,h)*ag+
444 eight_f1(a,b,c,d,e,f,g)*ah)/315;
445
446 }
447
448
449 static double eight_f1(int a, int b, int c, int d, int e, int f, int g)
450 {
451 /* The winner of the second group, who'll then play against A, may be one
452 from six possible players */
453
454 return eight_f2(a,b,c,d,e,f,g)+
455 eight_f2(a,c,b,d,e,f,g)+
456 eight_f2(a,d,b,c,e,f,g)+
457 eight_f2(a,e,b,c,d,f,g)+
458 eight_f2(a,f,b,c,d,e,g)+
459 eight_f2(a,g,b,c,d,e,f);
460 }
461
462 static double eight_f2(int a, int b, int c, int d, int e, int f, int g)
463 {
464 double ab,bc,bd,be,bf,bg;
465
466 ab = probability(a,b);
467 bc = probability(b,c);
468 bd = probability(b,d);
469 be = probability(b,e);
470 bf = probability(b,f);
471 bg = probability(b,g);
472
473 /* There are 5 player who may play against the 3rd. The third (b) will win
474 over them and lose against a */
475
476 return ab*(eight_f3(a,d,e,f,g)*bc+
477 eight_f3(a,c,e,f,g)*bd+
478 eight_f3(a,c,d,f,g)*be+
479 eight_f3(a,c,d,e,g)*bf+
480 eight_f3(a,c,d,e,f)*bg);
481
482 }
483
484 /* D.Moreaux, 10 Apr 2000: changed double to int for the parameters */
485
486 static double eight_f3(int a, int b, int c, int d, int e)
487 {
488 double ab,ac,ad,ae,bc,bd,be,cb,cd,ce,db,dc,de,eb,ec,ed;
489
490 ab = probability(a,b);
491 ac = probability(a,c);
492 ad = probability(a,d);
493 ae = probability(a,e);
494 bc = probability(b,c);
495 bd = probability(b,d);
496 be = probability(b,e);
497 cd = probability(c,d);
498 ce = probability(c,e);
499 de = probability(d,e);
500 cb = 1.0 - bc;
501 db = 1.0 - bd;
502 dc = 1.0 - cd;
503 eb = 1.0 - be;
504 ec = 1.0 - ce;
505 ed = 1.0 - de;
506
507 /* expansion then factorisation (this function is called 210 times)
508 * gain 4 func_call
509 * 24 *
510 * 30 probability
511 */
512 return (bc*de+be*dc)*((ab-ad)*bd+ad)+
513 (bd*ce+be*cd)*((ab-ac)*bc+ac)+
514 (cb*de+db*ce)*((ac-ad)*cd+ad)+
515 (cd*eb+cb*ed)*((ac-ae)*ce+ae)+
516 (dc*eb+db*ec)*((ad-ae)*de+ae)+
517 (bd*ec+bc*ed)*((ae-ab)*eb+ab);
518 }
519
520 /* Determine changes in ratings due to game results. */
521 extern int ladder_calc_info(t_clienttag clienttag, t_ladder_id id, unsigned int count, t_account * * players, t_game_result * results, t_ladder_info * info)
522 {
523 unsigned int curr;
524 unsigned int *rating;
525 unsigned int *sorted;
526
527 if (!players)
528 {
529 eventlog(eventlog_level_error,__FUNCTION__,"got NULL players");
530 return -1;
531 }
532 if (!results)
533 {
534 eventlog(eventlog_level_error,__FUNCTION__,"got NULL results");
535 return -1;
536 }
537 if (!clienttag)
538 {
539 eventlog(eventlog_level_error,__FUNCTION__,"got bad clienttag");
540 return -1;
541 }
542 if (!info)
543 {
544 eventlog(eventlog_level_error,__FUNCTION__,"got NULL info");
545 return -1;
546 }
547
548 rating = xmalloc(sizeof(unsigned int)*count);
549 sorted = xmalloc(sizeof(unsigned int)*count);
550
551 for (curr=0; curr<count; curr++)
552 rating[curr] = account_get_ladder_rating(players[curr],clienttag,id);
553
554 for (curr=0; curr<count; curr++)
555 {
556 double k;
557 double prob;
558 double delta;
559 t_game_result myresult;
560 unsigned int opponent_count;
561 unsigned int team_members;
562
563 k = coefficient(players[curr],clienttag,id);
564 opponent_count = 0;
565 myresult = results[curr];
566
567 {
568 unsigned int i,j;
569
570 /* Put the current user into slot 0, his opponents into other slots
571 order is not important for the other players */
572 for (i=0,j=1; i<count; i++)
573 if (i==curr)
574 sorted[0] = rating[i];
575 else
576 {
577 if (results[i]!=myresult)
578 {
579 sorted[j++] = rating[i];
580 opponent_count++;
581 }
582 }
583 }
584
585 team_members = count - opponent_count;
586
587 switch (opponent_count)
588 {
589 case 1:
590 prob = two_player(sorted);
591 break;
592 case 2:
593 prob = three_player(sorted);
594 break;
595 case 3:
596 prob = four_player(sorted);
597 break;
598 case 4:
599 prob = five_player(sorted);
600 break;
601 case 5:
602 prob = six_player(sorted);
603 break;
604 case 6:
605 prob = seven_player(sorted);
606 break;
607 case 7:
608 prob = eight_player(sorted);
609 break;
610 default:
611 eventlog(eventlog_level_error,__FUNCTION__,"sorry, unsupported number of ladder opponents (%u)",opponent_count);
612 xfree((void *)rating);
613 xfree((void *)sorted);
614 return -1;
615 }
616
617 if (results[curr]==game_result_win)
618 delta = fabs(k * (1.0 - prob) / team_members); /* better the chance of winning -> fewer points added */
619 else
620 delta = -fabs(k * prob); /* better the chance of winning -> more points subtracted */
621
622 eventlog(eventlog_level_debug,__FUNCTION__,"computed probability=%g, k=%g, deltar=%+g",prob,k,delta);
623
624 info[curr].prob = prob;
625 info[curr].k = (unsigned int)k;
626 info[curr].adj = (int)delta;
627 info[curr].oldrating = rating[curr];
628 info[curr].oldrank = account_get_ladder_rank(players[curr],clienttag,id);
629 }
630
631 xfree((void *)rating);
632 xfree((void *)sorted);
633
634 return 0;
635 }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1