1 /* players.c
2 
3    GNU Chess frontend
4 
5    Copyright (C) 2001-2011 Free Software Foundation, Inc.
6 
7    GNU Chess is based on the two research programs
8    Cobalt by Chua Kong-Sian and Gazebo by Stuart Cracraft.
9 
10    This program is free software: you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation, either version 3 of the License, or
13    (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 
23    Contact Info:
24      bug-gnu-chess@gnu.org
25      cracraft@ai.mit.edu, cracraft@stanfordalumni.org, cracraft@earthlink.net
26 */
27 
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 
32 #include "common.h"
33 
34 #define PLAYERFILE "players.dat"
35 
36 int totalplayers = 0;
37 
38 #define MAXPLAYERS 500
39 
40 typedef struct {
41   char player[MAXNAMESZ];
42   int wins;
43   int losses;
44   int draws;
45 } playerentry;
46 
47 playerentry playerdb[MAXPLAYERS];
48 static char lname[MAXNAMESZ];
49 
rscorecompare(const void * aa,const void * bb)50 static int rscorecompare(const void *aa, const void *bb)
51 {
52     const playerentry *a = (const playerentry *)aa;
53     const playerentry *b = (const playerentry *)bb;
54     float ascore, bscore;
55     ascore = (a->wins+(a->draws/2))/(a->wins+a->draws+a->losses);
56     bscore = (b->wins+(b->draws/2))/(b->wins+b->draws+b->losses);
57     if (ascore > bscore) return(-1);
58     else if (bscore > ascore) return(1);
59     else return(0);
60 }
61 
scorecompare(const void * aa,const void * bb)62 static int scorecompare(const void *aa, const void *bb)
63 {
64     const playerentry *a = (const playerentry *)aa;
65     const playerentry *b = (const playerentry *)bb;
66     int ascore, bscore;
67     ascore = 100*(a->wins+(a->draws/2))/(a->wins+a->draws+a->losses);
68     bscore = 100*(b->wins+(b->draws/2))/(b->wins+b->draws+b->losses);
69     if (bscore > ascore) return(1);
70     else if (bscore < ascore) return(-1);
71     else return(0);
72 }
73 
namecompare(const void * aa,const void * bb)74 static int namecompare(const void *aa, const void *bb)
75 {
76     const playerentry *a = (const playerentry *)aa;
77     const playerentry *b = (const playerentry *)bb;
78     if (strcmp(a->player,b->player) > 0) return(1);
79     else if (strcmp(a->player,b->player) < 0) return(-1);
80     else return(0);
81 }
82 
DBSortPlayer(const char * style)83 void DBSortPlayer (const char *style)
84 {
85   if (strncmp(style,"score",5) == 0) {
86     qsort(&playerdb,totalplayers,sizeof(playerentry),scorecompare);
87   } else if (strncmp(style,"name",4) == 0) {
88     qsort(&playerdb,totalplayers,sizeof(playerentry),namecompare);
89   } else if (strncmp(style,"reverse",7) == 0) {
90     qsort(&playerdb,totalplayers,sizeof(playerentry),rscorecompare);
91   }
92 }
93 
DBListPlayer(const char * style)94 void DBListPlayer (const char *style)
95 {
96   int i;
97 
98   DBReadPlayer ();
99   DBSortPlayer (style);
100   for (i = 0; i < totalplayers; i++) {
101     printf("%s %2.0f%% %d %d %d\n",
102 	playerdb[i].player,
103 	100.0*(playerdb[i].wins+((float)playerdb[i].draws/2))/
104 	 (playerdb[i].wins+playerdb[i].draws+playerdb[i].losses),
105 	playerdb[i].wins,
106 	playerdb[i].losses,
107 	playerdb[i].draws);
108     if ((i+1) % 10 == 0) {printf("[Type a character to continue.]\n"); getchar();}
109   }
110 }
111 
DBWritePlayer(void)112 void DBWritePlayer (void)
113 {
114    int i;
115    FILE *wfp;
116    DBSortPlayer ("reverse");
117    if ((wfp = fopen(PLAYERFILE,"w")) != NULL) {
118      for (i = 0; i < totalplayers; i++) {
119         fprintf(wfp,"%s %d %d %d\n",
120           playerdb[i].player,
121           playerdb[i].wins,
122           playerdb[i].losses,
123           playerdb[i].draws);
124      }
125    }
126    fclose(wfp);
127 }
128 
DBReadPlayer(void)129 void DBReadPlayer (void)
130 {
131    FILE *rfp;
132    int n;
133    totalplayers = 0;
134    if ((rfp = fopen(PLAYERFILE,"r")) != NULL) {
135     while (!feof(rfp)) {
136      n = fscanf(rfp,"%49s %d %d %d\n",  /* 49 MAXNAMESZ-1 */
137 	playerdb[totalplayers].player,
138         &playerdb[totalplayers].wins,
139         &playerdb[totalplayers].losses,
140         &playerdb[totalplayers].draws);
141      if (n == 4) totalplayers++;
142     }
143     fclose(rfp);
144    }
145 }
146 
DBSearchPlayer(const char * player)147 int DBSearchPlayer (const char *player)
148 {
149   int index = -1;
150   int i;
151 
152   for (i = 0; i < totalplayers; i++)
153     if (strncmp(playerdb[i].player,player,strlen(playerdb[i].player)) == 0)
154     {
155       index = i;
156       break;
157     }
158   return (index);
159 }
160 
DBUpdatePlayer(const char * player,const char * resultstr)161 void DBUpdatePlayer (const char *player, const char *resultstr)
162 {
163   const char *p;
164   char *x;
165   int index;
166   int result = R_NORESULT;
167 
168   p = player;
169   x = lname;
170   strcpy(lname,player);
171   do {
172     if (*p != ' ')
173       *x++ = *p++;
174     else
175 	p++;
176   } while (*p != '\0');
177   *x = '\000';
178   memset(playerdb,0,sizeof(playerdb));
179   DBReadPlayer ();
180   index = DBSearchPlayer (lname);
181   if (index == -1) {
182     strcpy(playerdb[totalplayers].player,lname);
183     playerdb[totalplayers].wins = 0;
184     playerdb[totalplayers].losses = 0;
185     playerdb[totalplayers].draws = 0;
186     index = totalplayers;
187     totalplayers++;
188   }
189   if (strncmp(resultstr,"1-0",3) == 0)
190      result = R_WHITE_WINS;
191   else if (strncmp(resultstr,"0-1",3) == 0)
192      result = R_BLACK_WINS;
193   else if (strncmp(resultstr,"1/2-1/2",7) == 0)
194      result = R_DRAW;
195 
196   if ((computerplays == white && result == R_WHITE_WINS)||
197       (computerplays == black && result == R_BLACK_WINS))
198     playerdb[index].wins++;
199   else if ((computerplays == white && result == R_BLACK_WINS)||
200       (computerplays == black && result == R_WHITE_WINS))
201     playerdb[index].losses++;
202   else
203     /* Shouln't one check for draw here? Broken PGN files surely exist */
204     playerdb[index].draws++;
205   DBWritePlayer ();
206 }
207