diff options
Diffstat (limited to 'FICS/ratings.c')
-rw-r--r-- | FICS/ratings.c | 1512 |
1 files changed, 1512 insertions, 0 deletions
diff --git a/FICS/ratings.c b/FICS/ratings.c new file mode 100644 index 0000000..007e613 --- /dev/null +++ b/FICS/ratings.c @@ -0,0 +1,1512 @@ +/* + ratings.c + + fics - An internet chess server. + Copyright (C) 1993 Richard V. Nash + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +/* Revision history: + name email yy/mm/dd Change + Richard Nash 93/10/22 Created + vek leeds@math.gatech.edu 95/04/05 Glicko system, with sterr +*/ + +#include "stdinclude.h" + +#include "common.h" +#include "playerdb.h" +#include "ratings.h" +#include "gamedb.h" +#include "command.h" +#include "comproc.h" +#include "lists.h" +#include "ficsmain.h" +#include "config.h" +#include "utils.h" + +/* grimm */ +#if defined(SGI) +#else +/* int system(char *arg); */ +/* int rewind(FILE *stream); */ +#endif + + +PUBLIC double Ratings_B_Average; +PUBLIC double Ratings_B_StdDev; + +PUBLIC double Ratings_S_Average; +PUBLIC double Ratings_S_StdDev; + +PUBLIC double Ratings_L_Average; +PUBLIC double Ratings_L_StdDev; + +PUBLIC double Ratings_W_Average; +PUBLIC double Ratings_W_StdDev; + + +PRIVATE double Rb_M = 0.0, Rb_S = 0.0, Rb_total = 0.0; +PRIVATE int Rb_count = 0; + +PRIVATE double Rs_M = 0.0, Rs_S = 0.0, Rs_total = 0.0; +PRIVATE int Rs_count = 0; + +PRIVATE double Rl_M = 0.0, Rl_S = 0.0, Rl_total = 0.0; +PRIVATE int Rl_count = 0; + +PRIVATE double Rw_M = 0.0, Rw_S = 0.0, Rw_total = 0.0; +PRIVATE int Rw_count = 0; + +/* +PUBLIC rateStruct bestS[MAX_BEST]; +PUBLIC int numS = 0; +PUBLIC rateStruct bestB[MAX_BEST]; +PUBLIC int numB = 0; +PUBLIC rateStruct bestW[MAX_BEST]; +PUBLIC int numW = 0; +*/ + +#define MAXHIST 30 +#define LOWESTHIST 800 +PUBLIC int sHist[MAXHIST]; +PUBLIC int bHist[MAXHIST]; +PUBLIC int wHist[MAXHIST]; +PUBLIC int lHist[MAXHIST]; + +char sdir[] = DEFAULT_STATS; + +PUBLIC int is_active(int Games) +{ + return (Games >= PROVISIONAL); +} + + +PUBLIC void rating_add(int rating, int type) +{ + int which; + + which = (rating - LOWESTHIST) / 100; + if (which < 0) + which = 0; + if (which >= MAXHIST) + which = MAXHIST - 1; + if (type == TYPE_BLITZ) { + bHist[which] += 1; + Rb_count++; + Rb_total += rating; + if (Rb_count == 1) { + Rb_M = rating; + } else { + Rb_S = Rb_S + (rating - Rb_M) * (rating - Rb_M); + Rb_M = Rb_M + (rating - Rb_M) / (Rb_count); + } + Ratings_B_StdDev = sqrt(Rb_S / Rb_count); + Ratings_B_Average = Rb_total / (double) Rb_count; + } else if (type == TYPE_WILD) { /* TYPE_WILD */ + wHist[which] += 1; + Rw_count++; + Rw_total += rating; + if (Rw_count == 1) { + Rw_M = rating; + } else { + Rw_S = Rw_S + (rating - Rw_M) * (rating - Rw_M); + Rw_M = Rw_M + (rating - Rw_M) / (Rw_count); + } + Ratings_W_StdDev = sqrt(Rw_S / Rw_count); + Ratings_W_Average = Rw_total / (double) Rw_count; + } else if (type == TYPE_LIGHT) { /* TYPE_LIGHT */ + lHist[which] += 1; + Rl_count++; + Rl_total += rating; + if (Rl_count == 1) { + Rl_M = rating; + } else { + Rl_S = Rl_S + (rating - Rl_M) * (rating - Rl_M); + Rl_M = Rl_M + (rating - Rl_M) / (Rl_count); + } + Ratings_L_StdDev = sqrt(Rl_S / Rl_count); + Ratings_L_Average = Rl_total / (double) Rl_count; + +/* Insert bughouse stuff */ + } else { /* TYPE_STAND */ + sHist[which] += 1; + Rs_count++; + Rs_total += rating; + if (Rs_count == 1) { + Rs_M = rating; + } else { + Rs_S = Rs_S + (rating - Rs_M) * (rating - Rs_M); + Rs_M = Rs_M + (rating - Rs_M) / (Rs_count); + } + Ratings_S_StdDev = sqrt(Rs_S / Rs_count); + Ratings_S_Average = Rs_total / (double) Rs_count; + } +} + +PUBLIC void rating_remove(int rating, int type) +{ + int which; + + which = (rating - LOWESTHIST) / 100; + if (which < 0) + which = 0; + if (which >= MAXHIST) + which = MAXHIST - 1; + if (type == TYPE_BLITZ) { + bHist[which] = bHist[which] - 1; + if (bHist[which] < 0) + bHist[which] = 0; + if (Rb_count == 0) + return; + Rb_count--; + Rb_total -= rating; + if (Rb_count == 0) { + Rb_M = 0; + Rb_S = 0; + } else { + Rb_M = Rb_M - (rating - Rb_M) / (Rb_count); + Rb_S = Rb_S - (rating - Rb_M) * (rating - Rb_M); + /* added this 3.11.95 foxbat */ if (Rb_S < 0) + Rb_S = 0; + } + if (Rb_count) { + Ratings_B_StdDev = sqrt(Rb_S / Rb_count); + Ratings_B_Average = Rb_total / (double) Rb_count; + } else { + Ratings_B_StdDev = 0; + Ratings_B_Average = 0; + } + } else if (type == TYPE_WILD) { /* TYPE_WILD */ + wHist[which] = wHist[which] - 1; + if (wHist[which] < 0) + wHist[which] = 0; + if (Rw_count == 0) + return; + Rw_count--; + Rw_total -= rating; + if (Rw_count == 0) { + Rw_M = 0; + Rw_S = 0; + } else { + Rw_M = Rw_M - (rating - Rw_M) / (Rw_count); + Rw_S = Rw_S - (rating - Rw_M) * (rating - Rw_M); + /* added this 3.10.95 foxbat */ if (Rw_S < 0) + Rw_S = 0; + } + if (Rw_count) { + Ratings_W_StdDev = sqrt(Rw_S / Rw_count); + Ratings_W_Average = Rw_total / (double) Rw_count; + } else { + Ratings_W_StdDev = 0; + Ratings_W_Average = 0; + } + } else if (type == TYPE_LIGHT) { /* TYPE_LIGHT */ + lHist[which] = lHist[which] - 1; + if (lHist[which] < 0) + lHist[which] = 0; + if (Rl_count == 0) + return; + Rl_count--; + Rl_total -= rating; + if (Rl_count == 0) { + Rl_M = 0; + Rl_S = 0; + } else { + Rl_M = Rl_M - (rating - Rl_M) / (Rl_count); + Rl_S = Rl_S - (rating - Rl_M) * (rating - Rl_M); + /* added this 3.10.95 foxbat */ if (Rl_S < 0) + Rl_S = 0; + } + if (Rl_count) { + Ratings_L_StdDev = sqrt(Rl_S / Rl_count); + Ratings_L_Average = Rl_total / (double) Rl_count; + } else { + Ratings_L_StdDev = 0; + Ratings_L_Average = 0; + } +/* insert bughouse stuff here */ + } else { /* TYPE_STAND */ + sHist[which] = sHist[which] - 1; + if (sHist[which] < 0) + sHist[which] = 0; + if (Rs_count == 0) + return; + Rs_count--; + Rs_total -= rating; + if (Rs_count == 0) { + Rs_M = 0; + Rs_S = 0; + } else { + Rs_M = Rs_M - (rating - Rs_M) / (Rs_count); + Rs_S = Rs_S - (rating - Rs_M) * (rating - Rs_M); + /* added this 3.10.95 foxbat */ if (Rs_S < 0) + Rs_S = 0; + } + if (Rs_count) { + Ratings_S_StdDev = sqrt(Rs_S / Rs_count); + Ratings_S_Average = Rs_total / (double) Rs_count; + } else { + Ratings_S_StdDev = 0; + Ratings_S_Average = 0; + } + } +} + +PRIVATE void load_ratings(void) +{ + FILE *fp; + char fname[MAX_FILENAME_SIZE]; + int i; + + sprintf(fname, "%s/newratingsV%d_data", stats_dir,STATS_VERSION); + fp = fopen(fname, "r"); + if (!fp) { + fprintf(stderr, "FICS: Can't read ratings data!\n"); + return; + } + fscanf(fp, "%lf %lf %lf %d", &Rb_M, &Rb_S, &Rb_total, &Rb_count); + fscanf(fp, "%lf %lf %lf %d", &Rs_M, &Rs_S, &Rs_total, &Rs_count); + fscanf(fp, "%lf %lf %lf %d", &Rw_M, &Rw_S, &Rw_total, &Rw_count); + fscanf(fp, "%lf %lf %lf %d", &Rl_M, &Rl_S, &Rl_total, &Rl_count); + + for (i = 0; i < MAXHIST; i++) { + fscanf(fp, "%d %d %d %d", &sHist[i], &bHist[i], &wHist[i], &lHist[i]); + } + fclose(fp); + if (Rs_count) { + Ratings_S_StdDev = sqrt(Rs_S / Rs_count); + Ratings_S_Average = Rs_total / (double) Rs_count; + } else { + Ratings_S_StdDev = 0; + Ratings_S_Average = 0; + } + if (Rb_count) { + Ratings_B_StdDev = sqrt(Rb_S / Rb_count); + Ratings_B_Average = Rb_total / (double) Rb_count; + } else { + Ratings_B_StdDev = 0; + Ratings_B_Average = 0; + } + if (Rw_count) { + Ratings_W_StdDev = sqrt(Rw_S / Rw_count); + Ratings_W_Average = Rw_total / (double) Rw_count; + } else { + Ratings_W_StdDev = 0; + Ratings_W_Average = 0; + } + if (Rl_count) { + Ratings_L_StdDev = sqrt(Rl_S / Rl_count); + Ratings_L_Average = Rl_total / (double) Rl_count; + } else { + Ratings_L_StdDev = 0; + Ratings_L_Average = 0; + } +} + +PUBLIC void save_ratings(void) +{ + FILE *fp; + char fname[MAX_FILENAME_SIZE]; + int i; + + sprintf(fname, "%s/newratingsV%d_data", stats_dir,STATS_VERSION); + fp = fopen(fname, "w"); + if (!fp) { + fprintf(stderr, "FICS: Can't write ratings data!\n"); + return; + } + fprintf(fp, "%10f %10f %10f %d\n", Rb_M, Rb_S, Rb_total, Rb_count); + fprintf(fp, "%10f %10f %10f %d\n", Rs_M, Rs_S, Rs_total, Rs_count); + fprintf(fp, "%10f %10f %10f %d\n", Rw_M, Rw_S, Rw_total, Rw_count); + fprintf(fp, "%10f %10f %10f %d\n", Rl_M, Rl_S, Rl_total, Rl_count); + + for (i = 0; i < MAXHIST; i++) { + fprintf(fp, "%d %d %d %d\n", sHist[i], bHist[i], wHist[i], lHist[i]); + } + fclose(fp); +} + +/* +PRIVATE void BestRemove(int p) +{ + int i; + + for (i = 0; i < numB; i++) { + if (!strcmp(bestB[i].name, parray[p].name)) + break; + } + if (i < numB) { + for (; i < numB - 1; i++) { + strcpy(bestB[i].name, bestB[i + 1].name); + bestB[i].rating = bestB[i + 1].rating; + } + numB--; + } + for (i = 0; i < numS; i++) { + if (!strcmp(bestS[i].name, parray[p].name)) + break; + } + if (i < numS) { + for (; i < numS - 1; i++) { + strcpy(bestS[i].name, bestS[i + 1].name); + bestS[i].rating = bestS[i + 1].rating; + } + numS--; + } + for (i = 0; i < numW; i++) { + if (!strcmp(bestW[i].name, parray[p].name)) + break; + } + if (i < numW) { + for (; i < numW - 1; i++) { + strcpy(bestW[i].name, bestW[i + 1].name); + bestW[i].rating = bestW[i + 1].rating; + } + numW--; + } +} + +PRIVATE void BestAdd(int p) +{ + int where, j; + + if ((parray[p].b_stats.rating > 0) && (parray[p].b_stats.num > 19)) { + for (where = 0; where < numB; where++) { + if (parray[p].b_stats.rating > bestB[where].rating) + break; + } + if (where < MAX_BEST) { + for (j = numB; j > where; j--) { + if (j == MAX_BEST) + continue; + strcpy(bestB[j].name, bestB[j - 1].name); + bestB[j].rating = bestB[j - 1].rating; + } + strcpy(bestB[where].name, parray[p].name); + bestB[where].rating = parray[p].b_stats.rating; + if (numB < MAX_BEST) + numB++; + } + } + if ((parray[p].s_stats.rating > 0) && (parray[p].s_stats.num > 19)) { + for (where = 0; where < numS; where++) { + if (parray[p].s_stats.rating > bestS[where].rating) + break; + } + if (where < MAX_BEST) { + for (j = numS; j > where; j--) { + if (j == MAX_BEST) + continue; + strcpy(bestS[j].name, bestS[j - 1].name); + bestS[j].rating = bestS[j - 1].rating; + } + strcpy(bestS[where].name, parray[p].name); + bestS[where].rating = parray[p].s_stats.rating; + if (numS < MAX_BEST) + numS++; + } + } + if ((parray[p].w_stats.rating > 0) && (parray[p].w_stats.num > 19)) { + for (where = 0; where < numW; where++) { + if (parray[p].w_stats.rating > bestW[where].rating) + break; + } + if (where < MAX_BEST) { + for (j = numW; j > where; j--) { + if (j == MAX_BEST) + continue; + strcpy(bestW[j].name, bestW[j - 1].name); + bestW[j].rating = bestW[j - 1].rating; + } + strcpy(bestW[where].name, parray[p].name); + bestW[where].rating = parray[p].w_stats.rating; + if (numW < MAX_BEST) + numW++; + } + } +} + +PUBLIC void BestUpdate(int p) +{ + BestRemove(p); + BestAdd(p); +} + +*/ + +PUBLIC void zero_stats(void) +{ + int i; + for (i = 0; i < MAXHIST; i++) { + sHist[i] = 0; + bHist[i] = 0; + wHist[i] = 0; + lHist[i] = 0; + } + Rb_M = 0.0, Rb_S = 0.0, Rb_total = 0.0; + Rb_count = 0; + + Rs_M = 0.0, Rs_S = 0.0, Rs_total = 0.0; + Rs_count = 0; + + Rw_M = 0.0, Rw_S = 0.0, Rw_total = 0.0; + Rw_count = 0; + + Rl_M = 0.0, Rl_S = 0.0, Rl_total = 0.0; + Rl_count = 0; + +/* + numS = 0; + numB = 0; + numW = 0; +*/ +} + +PUBLIC void rating_init(void) +{ + zero_stats(); + load_ratings(); +} + +/* This recalculates the rating info from the player data, it can take + a long time! */ +PUBLIC void rating_recalc(void) +{ + char dname[MAX_FILENAME_SIZE]; + int p1; + int c; + int t = time(0); + DIR *dirp; +#if USE_DIRENT + struct dirent *dp; +#else + struct direct *dp; +#endif + + fprintf(stderr, "FICS: Recalculating ratings at %s\n", strltime(&t)); + zero_stats(); + for (c = 'a'; c <= 'z'; c++) { + /* Never done as ratings server */ + sprintf(dname, "%s/%c", player_dir, c); + dirp = opendir(dname); + if (!dirp) + continue; + for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { + if (dp->d_name[0] != '.') { + p1 = player_new(); + if (player_read(p1, dp->d_name)) { + player_remove(p1); + fprintf(stderr, "FICS: Problem reading player %s.\n", dp->d_name); + continue; + } + if (parray[p1].b_stats.rating > 0) { + rating_add(parray[p1].b_stats.rating, TYPE_BLITZ); + } + if (parray[p1].s_stats.rating > 0) { + rating_add(parray[p1].s_stats.rating, TYPE_STAND); + } + if (parray[p1].l_stats.rating > 0) { + rating_add(parray[p1].l_stats.rating, TYPE_LIGHT); + } +/* insert bughouse stuff here */ + if (parray[p1].w_stats.rating > 0) { + rating_add(parray[p1].w_stats.rating, TYPE_WILD); + } + player_remove(p1); + } + } + closedir(dirp); + } + if (Rs_count) { + Ratings_S_StdDev = sqrt(Rs_S / Rs_count); + Ratings_S_Average = Rs_total / (double) Rs_count; + } else { + Ratings_S_StdDev = 0; + Ratings_S_Average = 0; + } + if (Rb_count) { + Ratings_B_StdDev = sqrt(Rb_S / Rb_count); + Ratings_B_Average = Rb_total / (double) Rb_count; + } else { + Ratings_B_StdDev = 0; + Ratings_B_Average = 0; + } + if (Rl_count) { + Ratings_L_StdDev = sqrt(Rl_S / Rl_count); + Ratings_L_Average = Rl_total / (double) Rl_count; + } else { + Ratings_L_StdDev = 0; + Ratings_L_Average = 0; + } + if (Rw_count) { + Ratings_W_StdDev = sqrt(Rw_S / Rw_count); + Ratings_W_Average = Rw_total / (double) Rw_count; + } else { + Ratings_W_StdDev = 0; + Ratings_W_Average = 0; + } + save_ratings(); + t = time(0); + fprintf(stderr, "FICS: Finished at %s\n", strltime(&t)); +} + +PRIVATE int Round (double x) +{ + return (x < 0 ? (int) (x - 0.5) : (int) (x + 0.5)); +} + +/* Constants for Glicko system */ +#define Gd 3.25 +#define Gr0 1720 +#define Gs0 350 +#define Gq 0.00575646273249 +#define Gp 0.000010072398601964 + +/* End of Glicko system variables */ + +PRIVATE double Gf(double ss) +{ + return (1.0 / sqrt(1.0 + Gp * ss * ss)); +} + +/* Confusing but economical: calculate error and attenuation function together */ +PRIVATE double GE(int r, int rr, double ss, double *fss) +{ + *fss = Gf(ss); + return (1.0 / (1.0 + pow(10.0, (rr - r) * (*fss) / 400.0))); +} + +PUBLIC double current_sterr(double s, int t) +{ + if (t < 0) + t = 0; /* this shouldn't happen */ + return (sqrt(s * s + Gd * Gd * log(1.0 + t / 60.0))); +} + +/* Calculates new rating and standard error. By vek. The person */ +/* who invented the ratings system is Mark E. Glickman, Ph.D. */ +/* His e-mail address is glickman@hustat.harvard.edu as of April '95. */ +/* Postscript copy of the note I coded this from should be available */ +/* for ftp from ics.onenet.net, if not elsewhere. */ + +PUBLIC void rating_sterr_delta(int p1, int p2, int type, int gtime, int result, + int *deltarating, double *newsterr) +{ + statistics *p1_stats; + statistics *p2_stats; + + double s1, s2; + int t1, r1, t2, r2; /* Initial sterrs and ratings */ + double E, fs2, denominator, GK, w; /* Parts of fancy formulas */ + double delta, sigma; /* Results to return */ + + if (type == TYPE_BLITZ) { + p1_stats = &parray[p1].b_stats; + p2_stats = &parray[p2].b_stats; + } else if (type == TYPE_WILD) { + p1_stats = &parray[p1].w_stats; + p2_stats = &parray[p2].w_stats; + } else if (type == TYPE_LIGHT) { + p1_stats = &parray[p1].l_stats; + p2_stats = &parray[p2].l_stats; +/* insert bughouse stuff here */ + } else { + p1_stats = &parray[p1].s_stats; + p2_stats = &parray[p2].s_stats; + } + + /* Calculate effective pre-game sterrs. ltime==0 implies never had sterr. */ + + if (p1_stats->ltime == 0) + s1 = Gs0; + else { + t1 = gtime - p1_stats->ltime; + s1 = current_sterr(p1_stats->sterr, t1); + if (s1 > Gs0) + s1 = Gs0; + } + + if (p2_stats->ltime == 0) + s2 = Gs0; + else { + t2 = gtime - p2_stats->ltime; + s2 = current_sterr(p2_stats->sterr, t2); + if (s2 > Gs0) + s2 = Gs0; + } + + /* pre-game ratings */ + if (p1_stats->rating == 0 && p1_stats->num == 0) + r1 = Gr0; + else + r1 = p1_stats->rating; + + if (p2_stats->rating == 0 && p2_stats->num == 0) + r2 = Gr0; + else + r2 = p2_stats->rating; + + /* now crunch */ + + if (result == RESULT_WIN) { + w = 1.0; + } else if (result == RESULT_DRAW) { + w = 0.5; + } else { + w = 0.0; + } + + E = GE(r1, r2, s2, &fs2); /* side effect: calculate fs2 */ + + denominator = 1.0 / (s1 * s1) + Gq * Gq * fs2 * fs2 * E * (1.0 - E); + GK = Gq * fs2 / denominator; + + delta = GK * (w - E); + if (p1_stats->rating == 0 && p1_stats->num == 0) + *deltarating = Round(Gr0 + delta); + else + *deltarating = Round(delta); /* Returned values: deltarating, + newsterr */ + sigma = 1.0 / sqrt(denominator); + *newsterr = (double) sigma; +} + +/* vek: Next is for when we want just the delta, and not the sigma. */ + +PUBLIC int rating_delta(int p1, int p2, int type, int result, int gtime) +{ + int delta; + double sigma; + + rating_sterr_delta(p1, p2, type, gtime, result, &delta, &sigma); + return (delta); + +} + +PUBLIC int rating_update(int g) +{ + int wDelta, bDelta; + double wSigma, bSigma; /* vek */ + + int wRes, bRes; + statistics *w_stats; + statistics *b_stats; + + int gtime; + + int inprogress = (g == parray[garray[g].black].game); + /* if this is adjudication of stored game, be quiet about ratings change */ + + if (garray[g].type == TYPE_BLITZ) { + w_stats = &parray[garray[g].white].b_stats; + b_stats = &parray[garray[g].black].b_stats; + } else if (garray[g].type == TYPE_STAND) { + w_stats = &parray[garray[g].white].s_stats; + b_stats = &parray[garray[g].black].s_stats; + } else if (garray[g].type == TYPE_WILD) { + w_stats = &parray[garray[g].white].w_stats; + b_stats = &parray[garray[g].black].w_stats; + } else if (garray[g].type == TYPE_LIGHT) { + w_stats = &parray[garray[g].white].l_stats; + b_stats = &parray[garray[g].black].l_stats; + } else { + fprintf(stderr, "FICS: Can't update untimed ratings!\n"); + return -1; + } + + switch (garray[g].result) { + case END_CHECKMATE: + case END_RESIGN: + case END_FLAG: + case END_ADJWIN: + if (garray[g].winner == WHITE) { + wRes = RESULT_WIN; + bRes = RESULT_LOSS; + } else { + bRes = RESULT_WIN; + wRes = RESULT_LOSS; + } + break; + case END_AGREEDDRAW: + case END_REPETITION: + case END_50MOVERULE: + case END_STALEMATE: + case END_NOMATERIAL: + case END_BOTHFLAG: + case END_ADJDRAW: + case END_FLAGNOMATERIAL: + wRes = bRes = RESULT_DRAW; + break; + default: + fprintf(stderr, "FICS: Update undecided game %d?\n", garray[g].result); + return -1; + } + gtime = untenths(garray[g].timeOfStart); + rating_sterr_delta(garray[g].white, garray[g].black, + garray[g].type, gtime, wRes, + &wDelta, &wSigma); + + rating_sterr_delta(garray[g].black, garray[g].white, + garray[g].type, gtime, bRes, + &bDelta, &bSigma); + + /* vek: Update time of last rated game played, for future ratings calcs. */ + /* Kept independently for blitz and standard. */ + w_stats->ltime = gtime; + b_stats->ltime = gtime; + /* end vek add 4/5/95 */ + + if (wRes == RESULT_WIN) { + w_stats->win++; + } else if (wRes == RESULT_LOSS) { + w_stats->los++; + } else { + w_stats->dra++; + } + w_stats->num++; + if (bRes == RESULT_WIN) { + b_stats->win++; + } else if (bRes == RESULT_LOSS) { + b_stats->los++; + } else { + b_stats->dra++; + } + b_stats->num++; + rating_remove(w_stats->rating, garray[g].type); + rating_remove(b_stats->rating, garray[g].type); + + if (inprogress) { + pprintf(garray[g].white, "%s rating adjustment: %d ", + ((garray[g].type == TYPE_BLITZ) ? "Blitz" : ((garray[g].type == TYPE_WILD) ? "Wild" : ((garray[g].type == TYPE_LIGHT) ? "Lightning" : "Standard"))), w_stats->rating); + pprintf(garray[g].black, "%s rating adjustment: %d ", + ((garray[g].type == TYPE_BLITZ) ? "Blitz" : ((garray[g].type == TYPE_WILD) ? "Wild" : ((garray[g].type == TYPE_LIGHT) ? "Lightning" : "Standard"))), b_stats->rating); + } + if (wDelta < -1000) { + pprintf(garray[g].white, "not changed due to bug (way too small)! sorry!\n"); + fprintf(stderr, "FICS: Got too small ratings bug for %s (w) vs. %s\n", + parray[garray[g].white].login, parray[garray[g].black].login); + } else if (wDelta > 3000) { + pprintf(garray[g].white, "not changed due to bug (way too big)! sorry!\n"); + fprintf(stderr, "FICS: Got too big ratings bug for %s (w) vs. %s\n", + parray[garray[g].white].login, parray[garray[g].black].login); + } else { + w_stats->rating += wDelta; + w_stats->sterr = wSigma; + } + + if (bDelta < -1000) { + pprintf(garray[g].black, "not changed due to bug (way too small)! sorry! "); + fprintf(stderr, "FICS: Got too small ratings bug for %s (b) vs. %s\n", + parray[garray[g].black].login, parray[garray[g].white].login); + } else if (bDelta > 3000) { + pprintf(garray[g].black, "not changed due to bug (way too big)! sorry! "); + fprintf(stderr, "FICS: Got too big ratings bug for %s (b) vs. %s\n", + parray[garray[g].black].login, parray[garray[g].white].login); + } else { + b_stats->rating += bDelta; + b_stats->sterr = bSigma; + } /* error messages down to vek */ + + rating_add(w_stats->rating, garray[g].type); + rating_add(b_stats->rating, garray[g].type); + + if ((w_stats->rating > w_stats->best) && (is_active(w_stats->num))) { + w_stats->best = w_stats->rating; + w_stats->whenbest = time(NULL); + } + if ((b_stats->rating > b_stats->best) && (is_active(b_stats->num))) { + b_stats->best = b_stats->rating; + b_stats->whenbest = time(NULL); + } +/* Ratings are now saved to disk after each game */ + player_save(garray[g].white); + player_save(garray[g].black); + +/* foxbat 3.11.95 */ + if (garray[g].type == TYPE_BLITZ) { + Rb_count++; + Rb_total += (w_stats->rating + b_stats->rating) / 2.0; + } else if (garray[g].type == TYPE_STAND) { + Rs_count++; + Rs_total += (w_stats->rating + b_stats->rating) / 2.0; + } else if (garray[g].type == TYPE_LIGHT) { + Rl_count++; + Rl_total += (w_stats->rating + b_stats->rating) / 2.0; + } else if (garray[g].type == TYPE_WILD) { + Rw_count++; + Rw_total += (w_stats->rating + b_stats->rating) / 2.0; + } +/* end add */ + if (inprogress) { + pprintf(garray[g].white, "--> %d\n", w_stats->rating); + pprintf(garray[g].black, "--> %d\n", b_stats->rating); + } + save_ratings(); + UpdateRank(garray[g].type, parray[garray[g].white].name, + w_stats, parray[garray[g].white].name); + UpdateRank(garray[g].type, parray[garray[g].black].name, + b_stats, parray[garray[g].black].name); + return 0; +} + +PUBLIC int com_assess(int p, param_list param) +{ + int p1 = p, p2, nowtime; + int p1_connected = 1, p2_connected = 1; + int win1, draw1, loss1; + double newsterr1; + int win2, draw2, loss2; + double newsterr2; + + nowtime = time(0); + +/* Hawk: Now assess can be used with players not */ +/* logged on -- I wonder if anyone doesn't */ +/* get just a bit confused here :) */ + + if (param[0].type == TYPE_NULL) { + if (parray[p].game < 0) { + pprintf(p, "You are not playing a game.\n"); + return COM_OK; + } else if (garray[parray[p].game].status == GAME_EXAMINE) { + if (!strcmp(garray[parray[p].game].black_name, parray[p].name)) { + pcommand(p, "assess %s\n", garray[parray[p].game].white_name); + } else { + pcommand(p, "assess %s %s\n", + garray[parray[p].game].white_name, + garray[parray[p].game].black_name); + } + return COM_OK; + } else { + p2 = parray[p].opponent; + } + } else { + if (!FindPlayer(p, param[0].val.word, &p2, &p2_connected)) { + pprintf(p, "No user named \"%s\" was found.\n", param[0].val.word); + return COM_OK; + } + if (param[1].type != TYPE_NULL) { + p1 = p2; + p1_connected = p2_connected; + if (!FindPlayer(p, param[1].val.word, &p2, &p2_connected)) { + pprintf(p, "No user named \"%s\" was found.\n", param[1].val.word); + if (!p1_connected) + player_remove(p1); + return COM_OK; + } + } + } + if (p1 == p2) { + pprintf(p, "You can't assess the same players.\n"); + if (!p1_connected) + player_remove(p1); + if (!p2_connected) + player_remove(p2); + return COM_OK; + } + rating_sterr_delta(p1, p2, TYPE_BLITZ, nowtime, RESULT_WIN, &win1, &newsterr1); + rating_sterr_delta(p1, p2, TYPE_BLITZ, nowtime, RESULT_DRAW, &draw1, &newsterr1); + rating_sterr_delta(p1, p2, TYPE_BLITZ, nowtime, RESULT_LOSS, &loss1, &newsterr1); + rating_sterr_delta(p2, p1, TYPE_BLITZ, nowtime, RESULT_WIN, &win2, &newsterr2); + rating_sterr_delta(p2, p1, TYPE_BLITZ, nowtime, RESULT_DRAW, &draw2, &newsterr2); + rating_sterr_delta(p2, p1, TYPE_BLITZ, nowtime, RESULT_LOSS, &loss2, &newsterr2); + + pprintf(p, "\nBlitz\n %10s (%4s, RD: %5.1f) %10s (%4s, RD: %5.1f)\n", + parray[p1].name, ratstrii(parray[p1].b_stats.rating, parray[p1].registered), parray[p1].b_stats.sterr, + parray[p2].name, ratstrii(parray[p2].b_stats.rating, parray[p2].registered), parray[p2].b_stats.sterr); + pprintf(p, "Win : %4d %4d\n", win1, loss2); + pprintf(p, "Draw: %4d %4d\n", draw1, draw2); + pprintf(p, "Loss: %4d %4d\n", loss1, win2); + pprintf(p, "New RD: %5.1f %5.1f\n", newsterr1, newsterr2); + + rating_sterr_delta(p1, p2, TYPE_STAND, nowtime, RESULT_WIN, &win1, &newsterr1); + rating_sterr_delta(p1, p2, TYPE_STAND, nowtime, RESULT_DRAW, &draw1, &newsterr1); + rating_sterr_delta(p1, p2, TYPE_STAND, nowtime, RESULT_LOSS, &loss1, &newsterr1); + rating_sterr_delta(p2, p1, TYPE_STAND, nowtime, RESULT_WIN, &win2, &newsterr2); + rating_sterr_delta(p2, p1, TYPE_STAND, nowtime, RESULT_DRAW, &draw2, &newsterr2); + rating_sterr_delta(p2, p1, TYPE_STAND, nowtime, RESULT_LOSS, &loss2, &newsterr2); + + pprintf(p, "\nStandard\n %10s (%4s, RD: %5.1f) %10s (%4s, RD: %5.1f)\n", + parray[p1].name, ratstrii(parray[p1].s_stats.rating, parray[p1].registered), parray[p1].s_stats.sterr, + parray[p2].name, ratstrii(parray[p2].s_stats.rating, parray[p2].registered), parray[p2].s_stats.sterr); + pprintf(p, "Win : %4d %4d\n", win1, loss2); + pprintf(p, "Draw: %4d %4d\n", draw1, draw2); + pprintf(p, "Loss: %4d %4d\n", loss1, win2); + pprintf(p, "New RD: %5.1f %5.1f\n", newsterr1, newsterr2); + + rating_sterr_delta(p1, p2, TYPE_LIGHT, nowtime, RESULT_WIN, &win1, &newsterr1); rating_sterr_delta(p1, p2, TYPE_LIGHT, nowtime, RESULT_DRAW, &draw1, &newsterr1); + rating_sterr_delta(p1, p2, TYPE_LIGHT, nowtime, RESULT_LOSS, &loss1, &newsterr1); + rating_sterr_delta(p2, p1, TYPE_LIGHT, nowtime, RESULT_WIN, &win2, &newsterr2); rating_sterr_delta(p2, p1, TYPE_LIGHT, nowtime, RESULT_DRAW, &draw2, &newsterr2); + rating_sterr_delta(p2, p1, TYPE_LIGHT, nowtime, RESULT_LOSS, &loss2, &newsterr2); + + pprintf(p, "\nLightning\n %10s (%4s, RD: %5.1f) %10s (%4s, RD: %5.1f)\n", + parray[p1].name, ratstrii(parray[p1].l_stats.rating, parray[p1].registered), parray[p1].l_stats.sterr, + parray[p2].name, ratstrii(parray[p2].l_stats.rating, parray[p2].registered), parray[p2].l_stats.sterr); + pprintf(p, "Win : %4d %4d\n", win1, loss2); + pprintf(p, "Draw: %4d %4d\n", draw1, draw2); + pprintf(p, "Loss: %4d %4d\n", loss1, win2); + pprintf(p, "New RD: %5.1f %5.1f\n", newsterr1, newsterr2); + + rating_sterr_delta(p1, p2, TYPE_WILD, nowtime, RESULT_WIN, &win1, &newsterr1); + rating_sterr_delta(p1, p2, TYPE_WILD, nowtime, RESULT_DRAW, &draw1, &newsterr1); + rating_sterr_delta(p1, p2, TYPE_WILD, nowtime, RESULT_LOSS, &loss1, &newsterr1); + rating_sterr_delta(p2, p1, TYPE_WILD, nowtime, RESULT_WIN, &win2, &newsterr2); + rating_sterr_delta(p2, p1, TYPE_WILD, nowtime, RESULT_DRAW, &draw2, &newsterr2); + rating_sterr_delta(p2, p1, TYPE_WILD, nowtime, RESULT_LOSS, &loss2, &newsterr2); + + pprintf(p, "\nWild\n %10s (%4s, RD: %5.1f) %10s (%4s, RD: %5.1f)\n", + parray[p1].name, ratstrii(parray[p1].w_stats.rating, parray[p1].registered), parray[p1].w_stats.sterr, + parray[p2].name, ratstrii(parray[p2].w_stats.rating, parray[p2].registered), parray[p2].w_stats.sterr); + pprintf(p, "Win : %4d %4d\n", win1, loss2); + pprintf(p, "Draw: %4d %4d\n", draw1, draw2); + pprintf(p, "Loss: %4d %4d\n", loss1, win2); + pprintf(p, "New RD: %5.1f %5.1f\n", newsterr1, newsterr2); + + if (!p1_connected) + player_remove(p1); + if (!p2_connected) + player_remove(p2); + return COM_OK; +} + + +PUBLIC int com_best(int p, param_list param) +{ + return Best(p, param, 1); +} + +PUBLIC int com_hbest(int p, param_list param) +{ + return Best(p, param, 0); +} + +#if 0 +PUBLIC int com_best(int p, param_list param) +{ + int i; + + pprintf(p, "Standard Blitz Wild\n"); + for (i = 0; i < MAX_BEST; i++) { + if ((i >= numS) && (i >= numB)) + break; + if (i < numS) { + pprintf(p, "%4d %-17s ", bestS[i].rating, bestS[i].name); + } else { + pprintf(p, " "); + } + if (i < numB) { + pprintf(p, "%4d %-17s ", bestB[i].rating, bestB[i].name); + } else { + pprintf(p, " "); + } + if (i < numW) { + pprintf(p, "%4d %-17s\n", bestW[i].rating, bestW[i].name); + } else { + pprintf(p, "\n"); + } + } + return COM_OK; +} +#endif + +PUBLIC int com_statistics(int p, param_list param) +{ + pprintf(p, " Standard Blitz Lightning Wild\n"); + pprintf(p, "average: %7.2f %7.2f %7.2f %7.2f\n", Ratings_S_Average, Ratings_B_Average, Ratings_L_Average, Ratings_W_Average); + pprintf(p, "std dev: %7.2f %7.2f %7.2f %7.2f\n", Ratings_S_StdDev, Ratings_B_StdDev, Ratings_L_StdDev, Ratings_W_StdDev); + pprintf(p, "number : %7d %7d %7d %7d\n", Rs_count, Rb_count, Rl_count, Rw_count); + return COM_OK; +} + +PUBLIC int com_fixrank(int p, param_list param) +{ + int p1, connected; + + if (!FindPlayer(p, param[0].val.word, &p1, &connected)) + return COM_OK; + UpdateRank(TYPE_BLITZ, parray[p1].name, &parray[p1].b_stats, + parray[p1].name); + UpdateRank(TYPE_STAND, parray[p1].name, &parray[p1].s_stats, + parray[p1].name); + UpdateRank(TYPE_WILD, parray[p1].name, &parray[p1].w_stats, + parray[p1].name); + if (!connected) + player_remove(p1); + return COM_OK; +} + +PUBLIC int com_rank(int p, param_list param) +{ + return DisplayRank(p, param, 1); +} + +PUBLIC int com_hrank(int p, param_list param) +{ + return DisplayRank(p, param, 0); +} + +PUBLIC int DisplayRank(int p, param_list param, int showComputers) +{ + int start, end, target, connected; + int show = SHOW_BLITZ | SHOW_STANDARD | SHOW_WILD; + + if (param[0].type == TYPE_NULL) { + DisplayTargetRank(p, parray[p].name, show, showComputers); + return COM_OK; + } else if (isdigit(param[0].val.word[0])) { + end = -1; + sscanf(param[0].val.word, "%d-%d", &start, &end); + if (end > 0 && (param[1].type != TYPE_NULL)) + show = ShowFromString(param[1].val.word); + DisplayRankedPlayers(p, start, end, show, showComputers); + return COM_OK; + } else { + target = player_search(p, param[0].val.word); + if (target == 0) { + pprintf(p, "Target %s not found.\n", param[0].val.word); + return COM_OK; + } + connected = (target > 0); + if (!connected) + target = -target - 1; + else + target--; + + if (param[1].type != TYPE_NULL) + show = ShowFromString(param[1].val.word); + DisplayTargetRank(p, parray[target].name, show, showComputers); + if (!connected) + player_remove(target); + return COM_OK; + } +} + +/* CompareStats returns 1 if s1 comes first, -1 if s2 comes first, and 0 + if neither takes precedence. */ +#if 0 +PRIVATE int CompareStats(char *name1, statistics *s1, + char *name2, statistics *s2) +{ + int i, l1; + + if (s1 == NULL) + if (s2 == NULL) + return 0; + else + return -1; + else if (s2 == NULL) + return 1; + + if (s1->rating > s2->rating) + return 1; + if (s1->rating < s2->rating) + return -1; + l1 = strlen(name1); + for (i = 0; i < l1; i++) { + if (name2[i] == '\0') + return -1; + if (tolower(name1[i]) < tolower(name2[i])) + return 1; + if (tolower(name1[i]) > tolower(name2[i])) + return -1; + } + if (name2[i] != '\0') + return 1; +/* if (s1->sterr < s2->sterr) return 1; + if (s1->sterr > s2->sterr) return -1; + if (s1->num > s2->num) return 1; + if (s1->num < s2->num) return -1; +*/ + fprintf(stderr, "Duplicate entries found: %s.\n", name1); + return 0; +} +#endif +PRIVATE int GetRankFileName(char *out, int type) +{ + switch (type) { + case TYPE_BLITZ: + sprintf(out, "%s/rank.blitz", sdir); + return type; + case TYPE_STAND: + sprintf(out, "%s/rank.std", sdir); + return type; + case TYPE_WILD: + sprintf(out, "%s/rank.wild", sdir); + return type; + default: + return -1; + } +} + +/* loon: Turning this off 28 Oct 1995 (temporary:)) since we're lagged + into outer space */ +PUBLIC void UpdateRank(int type, char *addName, + statistics *sNew, char *delName) +{} + +#if 0 +PUBLIC void UpdateRank(int type, char *addName, + statistics *sNew, char *delName) +{ + char RankFile[MAX_FILENAME_SIZE]; + char TmpRankFile[MAX_FILENAME_SIZE]; + char line[MAX_RANK_LINE]; + char login[MAX_LOGIN_NAME]; + char command[MAX_STRING_LENGTH]; + int comp; + statistics sCur; + FILE *fp; + FILE *fptemp; + + if (GetRankFileName(RankFile, type) < 0) + return; + fp = fopen(RankFile, "r"); + if (fp == NULL) { + fprintf(stderr, "Can't open rank file to update.\n"); + return; + } + sprintf(TmpRankFile, "%s/tmpRank", sdir); + fptemp = fopen(TmpRankFile, "w"); + if (fptemp == NULL) { + fprintf (stderr, "Unable to open rank file for updating.\n"); + return; + } + while (fgets(line, MAX_RANK_LINE - 1, fp)) { + sscanf(line, "%s %d %d %d", login, &sCur.rating, + &sCur.num, &comp); + if (delName != NULL && !strcasecmp(delName, login)) { /* Kill name. */ + delName = NULL; + continue; + } + if (addName != NULL && CompareStats(addName, sNew, login, &sCur) > 0) { + int computer = in_list(-1, L_COMPUTER, addName); + fprintf(fptemp, "%s %d %d %d\n", addName, sNew->rating, + sNew->num, computer); + addName = NULL; + } + fprintf(fptemp, "%s %d %d %d\n", login, sCur.rating, sCur.num, comp); + } + fclose(fptemp); + fclose(fp); + + sprintf(command, "mv %s %s", TmpRankFile, RankFile); + system(command); +} +#endif + +PRIVATE void DisplayRankHead(int p, int show) +{ + char Line[MAX_STRING_LENGTH]; + + Line[0] = '\0'; + if (CheckFlag(show, SHOW_BLITZ)) + strcat(Line, " Blitz "); + if (CheckFlag(show, SHOW_STANDARD)) + strcat(Line, " Standard "); + if (CheckFlag(show, SHOW_WILD)) + strcat(Line, " Wild"); + pprintf(p, "%s\n\n", Line); +} + +PRIVATE int CountRankLine(int countComp, char *loginName, + int num, int is_computer) +{ + if (loginName == NULL || loginName[0] == '\0') + return 0; + return (countComp || !is_computer) && (is_active(num)); +} + +PRIVATE int GetRank(FILE * fp, char *target, int countComp) +{ + int count = 0; + int nGames, is_computer; + int playerFound = 0; + char line[MAX_RANK_LINE]; + char login[MAX_LOGIN_NAME]; + + while (fgets(line, MAX_RANK_LINE - 1, fp) && !playerFound) { + sscanf(line, "%s %*d %d %d", login, &nGames, &is_computer); + if ((playerFound = !strcasecmp(login, target)) + || CountRankLine(countComp, login, nGames, is_computer)) + count++; + } + return (playerFound ? count : -1); +} + +PRIVATE void PositionFilePtr(FILE * fp, int count, int *last, + int *nTied, int showComp) +{ + int i, rating, nGames, is_computer; + char login[MAX_LOGIN_NAME]; + char line[MAX_RANK_LINE]; + + if (fp == NULL) + return; + rewind(fp); + for (i = 1; i < count; i++) { + do { + fgets(line, MAX_RANK_LINE - 1, fp); + if (feof(fp)) + break; + sscanf(line, "%s %d %d %d", login, &rating, &nGames, &is_computer); + } while (!CountRankLine(showComp, login, nGames, is_computer)); + if (rating != *last) { + *nTied = 1; + *last = rating; + } else + (*nTied)++; + } +} + +PRIVATE int ShowRankEntry(int p, FILE * fp, int count, int comp, + char *target, int *lastRating, int *nTied) +{ + char newLine[MAX_RANK_LINE]; + char login[MAX_LOGIN_NAME]; + int rating, findable, nGames, is_comp; + + findable = (count > 0) && !feof(fp); + if (findable) { + do { + fgets(newLine, MAX_RANK_LINE - 1, fp); + if (feof(fp)) + findable = 0; + else if (newLine[0] != '\0') + sscanf(newLine, "%s %d %d %d", + login, &rating, &nGames, &is_comp); + else + login[0] = '\0'; + } while (!CountRankLine(comp, login, nGames, is_comp) && findable + && strcasecmp(login, target)); + } + if (findable) { + if (!strcasecmp(login, target) + && !CountRankLine(comp, login, nGames, is_comp)) { + pprintf_highlight(p, "---- %-12.12s %4s", login, ratstr(rating)); + pprintf(p, " "); + return 0; + } else if (*lastRating == rating && *nTied < 1) { + pprintf(p, " "); + if (!strcasecmp(login, target)) + pprintf_highlight(p, "%-12.12s %4s", login, ratstr(rating)); + else + pprintf(p, "%-12.12s %4s", login, ratstr(rating)); + pprintf(p, " "); + return 1; + } else { + if (*nTied >= 1) { + if (*lastRating == rating) + count -= *nTied; + *nTied = -1; + } + if (!strcasecmp(login, target)) + pprintf_highlight(p, "%4d. %-12.12s %4s", + count, login, ratstr(rating)); + else + pprintf(p, "%4d. %-12.12s %4s", + count, login, ratstr(rating)); + pprintf(p, " "); + *lastRating = rating; + return 1; + } + } else { + pprintf(p, "%25s", ""); + return 1; + } +} + +PRIVATE int CountAbove(int num, int blitz, int std, int wild, int which) +{ + int max = blitz; + + if (max < std) + max = std; + if (max < wild) + max = wild; + return (max <= (num + 1) / 2 ? max - 1 : (num + 1) / 2); +} + +PRIVATE int ShowRankLines(int p, FILE * fb, FILE * fs, FILE * fw, int bCount, + int sCount, int wCount, int n, int showComp, int show, char *target) +{ + int lastBlitz = 9999, nTiedBlitz = 0; + int lastStd = 9999, nTiedStd = 0; + int lastWild = 9999, nTiedWild = 0; + int i; + + if (n <= 0) + return 0; + if (CheckFlag(show, SHOW_BLITZ)) { + PositionFilePtr(fb, bCount, &lastBlitz, &nTiedBlitz, showComp); + if (feof(fb)) + ClearFlag(show, SHOW_BLITZ); + } + if (CheckFlag(show, SHOW_STANDARD)) { + PositionFilePtr(fs, sCount, &lastStd, &nTiedStd, showComp); + if (feof(fs)) + ClearFlag(show, SHOW_STANDARD); + } + if (CheckFlag(show, SHOW_WILD)) { + PositionFilePtr(fw, wCount, &lastWild, &nTiedWild, showComp); + if (feof(fw)) + ClearFlag(show, SHOW_WILD); + } + if (!CheckFlag(show, SHOW_BLITZ | SHOW_STANDARD | SHOW_WILD)) + return 0; + DisplayRankHead(p, show); + + for (i = 0; i < n && show; i++) { + if (CheckFlag(show, SHOW_BLITZ)) + bCount += ShowRankEntry(p, fb, bCount, showComp, target, + &lastBlitz, &nTiedBlitz); + if (CheckFlag(show, SHOW_STANDARD)) + sCount += ShowRankEntry(p, fs, sCount, showComp, target, + &lastStd, &nTiedStd); + if (CheckFlag(show, SHOW_WILD)) + wCount += ShowRankEntry(p, fw, wCount, showComp, target, + &lastWild, &nTiedWild); + pprintf(p, "\n"); + } + return 1; +} + +PUBLIC int DisplayTargetRank(int p, char *target, int show, int showComp) +{ + int numToShow = 20; + int blitzRank = -1, blitzCount; + int stdRank = -1, stdCount; + int wildRank = -1, wildCount; + int numAbove; + char Path[MAX_FILENAME_SIZE]; + FILE *fb = NULL, *fs = NULL, *fw = NULL; + + if (CheckFlag(show, SHOW_BLITZ)) { + GetRankFileName(Path, TYPE_BLITZ); + fb = (FILE *) fopen(Path, "r"); + if (fb != NULL) + blitzRank = GetRank(fb, target, showComp); + if (blitzRank < 0) + ClearFlag(show, SHOW_BLITZ); + } + if (CheckFlag(show, SHOW_STANDARD)) { + GetRankFileName(Path, TYPE_STAND); + fs = (FILE *) fopen(Path, "r"); + if (fs != NULL) + stdRank = GetRank(fs, target, showComp); + if (stdRank < 0) + ClearFlag(show, SHOW_STANDARD); + } + if (CheckFlag(show, SHOW_WILD)) { + GetRankFileName(Path, TYPE_WILD); + if (CheckFlag(show, SHOW_WILD)) + fw = (FILE *) fopen(Path, "r"); + if (fw != NULL) + wildRank = GetRank(fw, target, showComp); + if (wildRank < 0) + ClearFlag(show, SHOW_WILD); + } + if (!CheckFlag(show, SHOW_BLITZ | SHOW_STANDARD | SHOW_WILD)) { + pprintf(p, "No ratings to show.\n"); + if (fb != NULL) fclose(fb); + if (fs != NULL) fclose(fs); + if (fw != NULL) fclose(fw); + return (0); + } + numAbove = CountAbove(numToShow, blitzRank, stdRank, wildRank, show); + blitzCount = blitzRank - numAbove; + stdCount = stdRank - numAbove; + wildCount = wildRank - numAbove; + + ShowRankLines(p, fb, fs, fw, blitzCount, stdCount, wildCount, + numToShow, showComp, show, target); + if (fb != NULL) fclose(fb); + if (fs != NULL) fclose(fs); + if (fw != NULL) fclose(fw); + return (1); +} + +PUBLIC int DisplayRankedPlayers(int p, int start, int end, + int show, int showComp) +{ + int num = end - start + 1; + FILE *fb = NULL, *fs = NULL, *fw = NULL; + char Path[MAX_FILENAME_SIZE]; + + if (start <= 0) + start = 1; + if (num <= 0) + return 0; + if (num > 100) + num = 100; + if (CheckFlag(show, SHOW_BLITZ)) { + GetRankFileName(Path, TYPE_BLITZ); + fb = (FILE *) fopen(Path, "r"); + if (fb == NULL) + ClearFlag(show, SHOW_BLITZ); + } + if (CheckFlag(show, SHOW_STANDARD)) { + GetRankFileName(Path, TYPE_STAND); + fs = (FILE *) fopen(Path, "r"); + if (fs == NULL) + ClearFlag(show, SHOW_STANDARD); + } + if (CheckFlag(show, SHOW_WILD)) { + GetRankFileName(Path, TYPE_WILD); + fw = (FILE *) fopen(Path, "r"); + if (fw == NULL) + ClearFlag(show, SHOW_WILD); + } + ShowRankLines(p, fb, fs, fw, start, start, start, + num, showComp, show, ""); + if (fb) + fclose(fb); + if (fs) + fclose(fs); + if (fw) + fclose(fw); + return 1; +} + +PUBLIC int ShowFromString(char *s) +{ + int i, len = strlen(s); + int show = 0; + + if (s == NULL || s[0] == '\0') + return SHOW_BLITZ | SHOW_STANDARD | SHOW_WILD; + for (i = 0; i < len; i++) { + switch (s[i]) { + case 'b': + SetFlag(show, SHOW_BLITZ); + break; + case 's': + SetFlag(show, SHOW_STANDARD); + break; + case 'w': + SetFlag(show, SHOW_WILD); + break; + } + } + return (show); +} + +PUBLIC int Best(int p, param_list param, int ShowComp) +{ + int show = SHOW_BLITZ | SHOW_STANDARD | SHOW_WILD; + + if (param[0].type != TYPE_NULL) + show = ShowFromString(param[0].val.word); + + DisplayRankedPlayers(p, 1, 20, show, ShowComp); + return COM_OK; +} |