Rev 17885 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
10 | reyssat | 1 | /* Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis |
2 | * |
||
3 | * This program is free software; you can redistribute it and/or modify |
||
4 | * it under the terms of the GNU General Public License as published by |
||
5 | * the Free Software Foundation; either version 2 of the License, or |
||
6 | * (at your option) any later version. |
||
7 | * |
||
8 | * This program is distributed in the hope that it will be useful, |
||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
11 | * GNU General Public License for more details. |
||
12 | * |
||
13 | * You should have received a copy of the GNU General Public License |
||
14 | * along with this program; if not, write to the Free Software |
||
15 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||
16 | */ |
||
17 | |||
8185 | bpr | 18 | /* student score management */ |
10 | reyssat | 19 | |
8185 | bpr | 20 | #include "wimslogd.h" |
8253 | bpr | 21 | #define MAX_TRY 60000 |
10 | reyssat | 22 | double oldfactor=0.85; /* quality factor, should remain stable. */ |
23 | |||
8339 | bpr | 24 | /* User score information of an exercise. |
12273 | bpr | 25 | * size in bytes : 32 +4*MAX_REQUIRE/10 + MAX_SCORESEED*(SEEDSIZE+4) |
8339 | bpr | 26 | * information to change if struct scoredata changes |
27 | */ |
||
10 | reyssat | 28 | typedef struct scoredata { |
15847 | bpr | 29 | unsigned short int new, allnew, try, hint, seed_scorecnt, seedlastcnt; |
12221 | bpr | 30 | float user, user2, last, best, level, high[MAX_REQUIRE/10]; |
12273 | bpr | 31 | struct{ |
32 | char seed[SEEDSIZE]; |
||
33 | float score; |
||
34 | } seed_score[MAX_SCORESEED]; |
||
10 | reyssat | 35 | } scoredata; |
36 | |||
12273 | bpr | 37 | struct scoredata uscore[MAX_CLASSEXOS]; |
38 | |||
8339 | bpr | 39 | /* size in bytes: 200 |
40 | * information to change if scoreheader changes |
||
41 | */ |
||
10 | reyssat | 42 | struct scoreheader { |
12221 | bpr | 43 | char raf[8][20]; |
44 | int sheet, exo; |
||
45 | char session[32]; |
||
10 | reyssat | 46 | } scoreheader; |
47 | |||
12273 | bpr | 48 | |
10 | reyssat | 49 | #define oldraf scoreheader.raf |
50 | #define oldsheet scoreheader.sheet |
||
51 | #define oldexo scoreheader.exo |
||
52 | #define oldsession scoreheader.session |
||
53 | |||
12224 | bpr | 54 | /* one line of score: |
55 | format (see log.c): |
||
56 | exnowstr sess sh exo cc\tip\tse\tallow |
||
57 | allow contains information about noscore |
||
58 | noscore must be at the end to be taken in account |
||
12471 | bpr | 59 | noscore can be preceded by an explaining word for the moment maxtry |
12224 | bpr | 60 | se is the seed |
61 | tabulation is useful in adm/class/userscore/getraw.sh |
||
62 | */ |
||
10 | reyssat | 63 | void scoreline(struct classdata *cd, char *l) |
64 | { |
||
15847 | bpr | 65 | int i,sheet,exo,num,indnum; |
12221 | bpr | 66 | char *pm[16]; |
67 | struct scoredata *thiscore; |
||
15847 | bpr | 68 | struct sheetdata *ts; |
12221 | bpr | 69 | float score; |
10 | reyssat | 70 | |
12221 | bpr | 71 | i=cutwords(l,pm,12); if(i<6) return; |
12231 | bpr | 72 | sheet=atoi(pm[2]); exo=atoi(pm[3]); |
16727 | guerimand | 73 | if(sheet<=0 || sheet>MAX_SHEETS || exo<=0 || exo>MAX_EXOS) return; |
15847 | bpr | 74 | ts=cd->sheets+sheet-1; |
75 | num=ts->start+exo-1; |
||
76 | indnum=ts->indstart + exo-1 + ts->exocnt*ts->techval; |
||
12231 | bpr | 77 | if(num<0) return; |
12230 | bpr | 78 | if(strcmp(pm[i-1],"noscore")==0 || strcmp(pm[i-1],"erased")==0) { |
79 | if(strcmp(pm[1],oldsession)!=0) |
||
80 | mystrncpy(oldsession,pm[1],sizeof(oldsession)); |
||
12231 | bpr | 81 | if(strcmp(pm[4],"new")==0 || strcmp(pm[4],"renew")==0) { |
82 | thiscore=uscore+num; |
||
83 | thiscore->allnew ++; |
||
12471 | bpr | 84 | if(i>8) { |
12507 | bpr | 85 | /* copy-paste: seeds are kept even if the last word of the line |
12471 | bpr | 86 | contains noscore |
87 | */ |
||
12418 | bpr | 88 | if(thiscore->seed_scorecnt==MAX_SCORESEED) { |
89 | int k; |
||
12446 | bpr | 90 | /* when one reaches the limit one kept at the end only what is necessary to |
91 | test if the seed should be changed so MAX_SEEDSCORE |
||
12471 | bpr | 92 | one wants to keep the first ones (for exotrymax test) |
93 | */ |
||
12446 | bpr | 94 | for(k=MAX_SCORESEED-MAX_SEEDSCORE; k<MAX_SCORESEED; ++k) |
12418 | bpr | 95 | thiscore->seed_score[k-1]=thiscore->seed_score[k]; |
96 | thiscore->seed_scorecnt--; |
||
97 | } |
||
98 | mystrncpy(thiscore->seed_score[thiscore->seed_scorecnt].seed,pm[6],SEEDSIZE); |
||
99 | thiscore->seed_score[thiscore->seed_scorecnt++].score=-2; |
||
100 | thiscore->seedlastcnt=1; |
||
101 | {int k; |
||
102 | for(k=thiscore->seed_scorecnt-1; k>=1 && |
||
103 | strcmp(thiscore->seed_score[k].seed,thiscore->seed_score[k-1].seed)==0;k--) |
||
104 | thiscore->seedlastcnt++; |
||
105 | } |
||
106 | } |
||
12231 | bpr | 107 | } |
12230 | bpr | 108 | return; |
109 | } |
||
12224 | bpr | 110 | thiscore=uscore+num; |
12471 | bpr | 111 | /* line with score in word number 5*/ |
12221 | bpr | 112 | if(strcmp(pm[4],"score")==0) { |
113 | score=atof(pm[5]); |
||
114 | if(!isfinite(score)) score=0; |
||
115 | if(score>10) score=10; |
||
116 | if(score<-10) score=-10; |
||
7149 | bpr | 117 | |
12221 | bpr | 118 | if(strcmp(pm[1],oldsession)==0 && /* measure to prohibit simultaneous scoring. */ |
7149 | bpr | 119 | sheet==oldsheet && exo==oldexo && |
7407 | bpr | 120 | strncmp(pm[0],oldraf[6],13)!=0 /* prohibit scores immediately after rafale */ |
7149 | bpr | 121 | ) { |
12221 | bpr | 122 | thiscore->user+=score; |
123 | thiscore->user2*=oldfactor; |
||
124 | thiscore->user2+=score; |
||
125 | thiscore->last=score; |
||
126 | if (thiscore->high[0] < score) |
||
127 | { |
||
128 | int k; |
||
129 | thiscore->best += (score - thiscore->high[0]); |
||
15847 | bpr | 130 | for (k = 1; 10*k < cd->exos[indnum].require && thiscore->high[k] < score; k++) |
12221 | bpr | 131 | thiscore->high[k-1] = thiscore->high[k]; |
132 | thiscore->high[k-1] = score; |
||
133 | thiscore->level=thiscore->high[0]; |
||
134 | } |
||
135 | if(thiscore->try<MAX_TRY) thiscore->try++; |
||
136 | oldsheet=oldexo=0; |
||
12273 | bpr | 137 | thiscore->seed_score[thiscore->seed_scorecnt-1].score=score; |
10 | reyssat | 138 | } |
12221 | bpr | 139 | } |
12471 | bpr | 140 | /* end of line with score */ |
12221 | bpr | 141 | else { |
142 | if(strcmp(pm[4],"rafale")==0) { /* rafale punishment */ |
||
12231 | bpr | 143 | if(strncmp(pm[0],oldraf[3],13)==0 && thiscore->new<MAX_TRY) |
144 | { thiscore->new++; thiscore->allnew++; } |
||
12221 | bpr | 145 | memmove(oldraf[1],oldraf[0],sizeof(oldraf[0])*7); |
146 | mystrncpy(oldraf[0],pm[0],sizeof(oldraf[0])); |
||
10 | reyssat | 147 | } |
12221 | bpr | 148 | if(strcmp(pm[4],"resume")!=0 && strcmp(pm[4],"rafale")!=0) { |
149 | if(strcmp(pm[4],"hint")==0) thiscore->hint++; |
||
12231 | bpr | 150 | else if(thiscore->new<MAX_TRY) { |
151 | thiscore->new++; |
||
152 | if(thiscore->allnew<MAX_TRY) thiscore->allnew++; |
||
153 | } |
||
12471 | bpr | 154 | /* what about resume ? */ |
12273 | bpr | 155 | if((strcmp(pm[4],"new")==0 || strcmp(pm[4],"renew")==0) && i>6){ |
156 | /* the first seed is forgotten if there is already MAX_SCORESEED */ |
||
157 | if(thiscore->seed_scorecnt==MAX_SCORESEED) { |
||
158 | int k; |
||
159 | for(k=1; k<MAX_SCORESEED; ++k) |
||
160 | thiscore->seed_score[k-1]=thiscore->seed_score[k]; |
||
161 | thiscore->seed_scorecnt--; |
||
162 | } |
||
163 | mystrncpy(thiscore->seed_score[thiscore->seed_scorecnt].seed,pm[6],SEEDSIZE); |
||
12295 | bpr | 164 | thiscore->seed_score[thiscore->seed_scorecnt++].score=-1; |
165 | thiscore->seedlastcnt=1; |
||
166 | {int k; |
||
167 | for(k=thiscore->seed_scorecnt-1; k>=1 && |
||
168 | strcmp(thiscore->seed_score[k].seed,thiscore->seed_score[k-1].seed)==0;k--) |
||
169 | thiscore->seedlastcnt++; |
||
170 | } |
||
171 | } |
||
12221 | bpr | 172 | } |
173 | mystrncpy(oldsession,pm[1],sizeof(oldsession)); |
||
174 | oldsheet=sheet; oldexo=exo; |
||
175 | } |
||
10 | reyssat | 176 | } |
177 | |||
178 | unsigned int _cuttime(char ends[], char starts[], unsigned int startn) |
||
179 | { |
||
12221 | bpr | 180 | int h1,h2,m1,m2,s2, t; |
181 | if(ends[0]==0) return 0; |
||
182 | if(strncmp(ends,starts,14)<0) return 10; |
||
183 | if(strncmp(ends,starts,8)>0) return 0; |
||
184 | h1=atoi(ends+9); m1=atoi(ends+12); |
||
185 | h2=atoi(starts+9); m2=atoi(starts+12); s2=atoi(starts+15); |
||
186 | t=((h1-h2)*60+(m1-m2))*60-s2; |
||
187 | return startn+t; |
||
10 | reyssat | 188 | } |
189 | |||
8155 | bpr | 190 | /* Gather exam score. */ |
10 | reyssat | 191 | void examscorecalc(struct classdata *cd, char *uname) |
192 | { |
||
12221 | bpr | 193 | struct scoredata *thiscore; |
194 | char nbuf[MAX_FNAME+1]; |
||
16704 | guerimand | 195 | char cuttimes[MAX_EXAMS][16]; |
12221 | bpr | 196 | char rbuf[MAX_FILELEN+1]; |
197 | char *wlist[8]; |
||
198 | char *p1, *p2; |
||
199 | int i, k, ecnt, num; |
||
16704 | guerimand | 200 | double ss, sc[MAX_EXAMS], sc2[MAX_EXAMS], scb[MAX_EXAMS], scb2[MAX_EXAMS]; |
201 | int ind[MAX_EXAMS]; |
||
202 | unsigned int tr[MAX_EXAMS], all[MAX_EXAMS], ver[MAX_EXAMS], start[MAX_EXAMS], dure[MAX_EXAMS]; |
||
203 | char *ip[MAX_EXAMS], *ses[MAX_EXAMS]; |
||
204 | unsigned int start1, endtime[MAX_EXAMS]; |
||
12221 | bpr | 205 | signed int dure1; |
10 | reyssat | 206 | |
15847 | bpr | 207 | ecnt=cd->examcnt; |
16081 | bpr | 208 | if(ecnt<=0) return; |
16704 | guerimand | 209 | if(ecnt>MAX_EXAMS) ecnt=MAX_EXAMS; |
12221 | bpr | 210 | memset(all,0,sizeof(all)), memset(ver,0,sizeof(ver)); |
211 | for(i=0;i<ecnt;i++) { |
||
15847 | bpr | 212 | ind[i]=i+cd->exam.indstart; |
213 | all[i]=cd->exos[ind[i]].require; |
||
12221 | bpr | 214 | } |
215 | memset(sc,0,sizeof(sc)); memset(sc2,0,sizeof(sc2)); |
||
216 | memset(scb,0,sizeof(scb)); memset(scb2,0,sizeof(scb2)); |
||
217 | memset(tr,0,sizeof(tr)); memset(cuttimes,0,sizeof(cuttimes)); |
||
218 | memset(dure,0,sizeof(dure)); memset(start,0,sizeof(start)); |
||
219 | memset(endtime,0,sizeof(endtime)); |
||
220 | memset(ip,0,sizeof(ip)); memset(ses,0,sizeof(ses)); |
||
221 | snprintf(nbuf,sizeof(nbuf),"score/%s.exam",uname); |
||
222 | readfile(nbuf,rbuf,sizeof(rbuf)); |
||
223 | if(rbuf[0]==0) goto end; |
||
224 | for(p1=rbuf; p1!=NULL && *p1; p1=p2) { |
||
225 | p2=strchr(p1,'\n'); if(p2!=NULL) *p2++=0; |
||
226 | i=cutwords(find_word_start(p1),wlist,7); |
||
227 | if(i<6) continue; |
||
228 | i=atoi(wlist[0])-1; if(i<0 || i>=ecnt) continue; |
||
229 | dure1=atoi(wlist[2]); start1=atoi(wlist[3]); |
||
230 | if(strcmp(wlist[1],"--")==0) { /* session closure */ |
||
231 | start[i]=dure[i]=0; ip[i]=ses[i]=""; |
||
232 | continue; |
||
10 | reyssat | 233 | } |
12221 | bpr | 234 | if(strcmp(wlist[1],"00")==0) { |
235 | if(sc2[i]<sc[i]) sc2[i]=sc[i]; |
||
236 | if(scb2[i]<scb[i]) scb2[i]=scb[i]; |
||
237 | ver[i]=1; tr[i]++; start[i]=start1; dure[i]=dure1; sc[i]=0; scb[i]=0; |
||
238 | ip[i]=wlist[4]; ses[i]=wlist[5]; |
||
239 | if(tr[i]==1 && wlist[6]!=NULL) { |
||
240 | char *pp1, *pp2, lbuf[CTBUFLEN]; |
||
241 | if(cd->ctptr[ind[i]]>=0) |
||
242 | mystrncpy(lbuf,cd->ctbuf+cd->ctptr[ind[i]],sizeof(lbuf)); |
||
243 | else lbuf[0]=0; |
||
244 | if(lbuf[0]) { |
||
245 | for(pp1=find_word_start(lbuf); *pp1; pp1=find_word_start(pp2)) { |
||
246 | pp2=find_word_end(pp1); if(pp2-pp1!=14) continue; |
||
247 | if(*pp2) *pp2++=0; |
||
248 | pp1[8]='.'; pp1[11]=':'; |
||
249 | if(strcmp(pp1,wlist[6])<0) continue; |
||
250 | memmove(cuttimes[i],pp1,15); break; |
||
7149 | bpr | 251 | } |
12221 | bpr | 252 | } |
253 | } |
||
254 | endtime[i]=_cuttime(cuttimes[i],wlist[6],start1); |
||
255 | } |
||
256 | else if(ver[i]==0) tr[i]++; |
||
257 | if(tr[i]>all[i]) continue; |
||
258 | ss=atof(wlist[1]); if(ss<=0) continue; if(ss>10) ss=10; |
||
12471 | bpr | 259 | /* checking conditions with ip checking*/ |
260 | if(ss!=sc[i] && (dure1>=0 || ( |
||
261 | start1-start[i]<dure[i]*60 && |
||
262 | dure[i]>0 && dure[i]<4096 && |
||
263 | *ses[i]!=0 && *ip[i]!=0 && |
||
264 | start[i]!=0 && start1>start[i] && |
||
265 | (endtime[i]==0 || endtime[i]>=start1) && |
||
266 | strcmp(ip[i],wlist[4])==0 && |
||
267 | strcmp(ses[i],wlist[5])==0))) |
||
12221 | bpr | 268 | sc[i]=ss; |
12471 | bpr | 269 | /* checking conditions without ip checking -- will be in structure best */ |
9692 | bpr | 270 | if(ss!=scb[i] && (dure1>=0 || |
12471 | bpr | 271 | (start1-start[i]<dure[i]*60 && |
272 | dure[i]>0 && dure[i]<4096 && |
||
273 | *ses[i]!=0 && *ip[i]!=0 && |
||
274 | start[i]!=0 && start1>start[i] && |
||
275 | (endtime[i]==0 || endtime[i]>=start1) && |
||
276 | strcmp(ses[i],wlist[5])==0))) |
||
12221 | bpr | 277 | scb[i]=ss; |
278 | } |
||
279 | end: |
||
280 | for(i=0; i<ecnt; i++) { |
||
281 | if(sc2[i]<sc[i]) sc2[i]=sc[i]; |
||
282 | if(scb2[i]<scb[i]) scb2[i]=scb[i]; |
||
15847 | bpr | 283 | num=cd->exocnt - cd->examcnt+i; |
12221 | bpr | 284 | if(num<0) continue; |
285 | thiscore=uscore+num; |
||
286 | thiscore->user=sc2[i]; |
||
287 | thiscore->best=scb2[i]; |
||
288 | thiscore->try=tr[i]; |
||
289 | if(cuttimes[i][0] && strncmp(cuttimes[i],nowstr,14)<0) k=0; else k=1; |
||
290 | thiscore->hint=k; |
||
291 | } |
||
10 | reyssat | 292 | } |
293 | |||
8155 | bpr | 294 | /* calculate score from raw data, core routine. */ |
10 | reyssat | 295 | void rawscorecalc(struct classdata *cd, char *uname) |
296 | { |
||
12221 | bpr | 297 | char fbuf[MAX_FILELEN+1]; |
298 | char *p1, *p2; |
||
299 | char namebuf[MAX_FNAME+1]; |
||
12471 | bpr | 300 | /* initialize everything to zero */ |
12221 | bpr | 301 | memset(uscore,0,sizeof(uscore[0])*cd->exocnt); |
302 | memset(&scoreheader,0,sizeof(scoreheader)); |
||
303 | snprintf(namebuf,sizeof(namebuf),"score/%s",uname); |
||
304 | readfile(namebuf,fbuf,sizeof(fbuf)); |
||
305 | if(fbuf[0]!=0) { |
||
306 | oldsession[0]=oldsheet=oldexo=0; |
||
307 | for(p1=fbuf; *p1; p1=p2) { |
||
308 | p2=strchr(p1,'\n'); if(p2) *p2++=0; else p2=p1+strlen(p1); |
||
309 | if(myisdigit(*p1)) scoreline(cd,p1); |
||
10 | reyssat | 310 | } |
12221 | bpr | 311 | } |
312 | examscorecalc(cd,uname); |
||
10 | reyssat | 313 | } |
314 | |||
8339 | bpr | 315 | /* size of the file *.bin: |
316 | * 200 + (28+4*MAX_REQUIRE/10)*(number_exos_in_sheets + number_exams) |
||
317 | * information to change if struct scoredata or scoreheader change |
||
318 | */ |
||
10 | reyssat | 319 | void savescorebin(struct classdata *cd, char *uname) |
320 | { |
||
12221 | bpr | 321 | int fd, cnt; |
322 | char fname[MAX_FNAME+1]; |
||
323 | snprintf(fname,sizeof(fname),"score/%s.bin",uname); |
||
324 | cnt=cd->exocnt; |
||
325 | fd=creat(fname,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); |
||
326 | if(fd==-1) return; |
||
327 | (void)write(fd,&scoreheader,sizeof(scoreheader)); |
||
328 | (void)write(fd,uscore,sizeof(uscore[0])*cnt); |
||
329 | close(fd); |
||
10 | reyssat | 330 | } |
331 | |||
332 | void readscorebin(char *fname,int cnt) |
||
333 | { |
||
12221 | bpr | 334 | int fd; |
335 | fd=open(fname,O_RDONLY); |
||
336 | if(fd==-1) return; |
||
337 | (void)read(fd,&scoreheader,sizeof(scoreheader)); |
||
338 | (void)read(fd,uscore,sizeof(uscore[0])*cnt); |
||
339 | close(fd); |
||
10 | reyssat | 340 | } |
15847 | bpr | 341 | /* copie provisoire dans wimslogd venant de wims */ |
342 | /* Get variable definition from a file. |
||
343 | * Result stored in buffer value of length MAX_LINELEN. |
||
344 | */ |
||
345 | void _getdef(char buf[], char *name, char value[]) |
||
346 | { |
||
347 | char *p1, *p2, *p3, *p4; |
||
10 | reyssat | 348 | |
15847 | bpr | 349 | if(*name==0) goto nothing; /* this would create segfault. */ |
350 | for(p1=strstr(buf,name); p1!=NULL; p1=strstr(p1+1,name)) { |
||
351 | p2=find_word_start(p1+strlen(name)); |
||
352 | if((p1>buf && !isspace(*(p1-1))) || *p2!='=') continue; |
||
353 | p3=p1; while(p3>buf && *(p3-1)!='\n') p3--; |
||
354 | p3=find_word_start(p3); |
||
355 | if(p3<p1 && *p3!='!') continue; |
||
356 | if(p3<p1) { |
||
357 | p3++; p4=find_word_end(p3); |
||
358 | if(find_word_start(p4)!=p1) continue; |
||
359 | if(p4-p3!=3 || (strncmp(p3,"set",3)!=0 && |
||
360 | strncmp(p3,"let",3)!=0 && |
||
361 | strncmp(p3,"def",3)!=0)) { |
||
362 | if(p4-p3!=6 || strncmp(p3,"define",6)!=0) continue; |
||
363 | } |
||
364 | } |
||
365 | p2++;p3=strchr(p2,'\n'); if(p3==NULL) p3=p2+strlen(p2); |
||
366 | p2=find_word_start(p2); |
||
367 | if(p2>p3) goto nothing; |
||
368 | /*if(p3-p2>=MAX_LINELEN) user_error("cmd_output_too_long");*/ |
||
369 | memmove(value,p2,p3-p2); value[p3-p2]=0; |
||
370 | strip_trailing_spaces(value); return; |
||
371 | } |
||
372 | nothing: |
||
373 | value[0]=0; |
||
374 | } |
||
375 | |||
376 | void getdef(char *fname, char *name, char value[]) |
||
377 | { |
||
378 | FILE *f; |
||
379 | char *buf; |
||
380 | int l; |
||
381 | |||
382 | value[0]=0; |
||
383 | f=fopen(fname,"r"); if(f==NULL) return; |
||
384 | fseek(f,0,SEEK_END); l=ftell(f); fseek(f,0,SEEK_SET); |
||
385 | buf=xmalloc(l+256); l=fread(buf,1,l,f); |
||
386 | fclose(f); |
||
387 | if(l<=0) return; else buf[l]=0; |
||
388 | _getdef(buf,name,value); |
||
389 | free(buf); |
||
390 | } |
||
391 | /* define number of the technical variable associated to user by sheet */ |
||
392 | void techvals (struct classdata *cd, char *user) |
||
393 | { |
||
394 | char fname[MAX_FNAME+1]; |
||
395 | char techname[MAX_FNAME+1], techval[MAX_FNAME+1]; |
||
396 | char *p1; |
||
397 | int i, j; |
||
398 | |||
18421 | czzmrn | 399 | // snprintf(fname,sizeof(fname),".users/%s",user); |
400 | if(cd->sclass[0] != 0 ){ |
||
401 | snprintf(fname,sizeof(fname),"%s/%s/%s/.users/%s",cwd,classd,cd->sclass,user); |
||
402 | } else { |
||
403 | snprintf(fname,sizeof(fname),"%s/%s/%s/.users/%s",cwd,classd,cd->name,user); |
||
404 | } |
||
15847 | bpr | 405 | for (i = 0; i < cd->sheetcnt; ++i){ |
406 | cd->sheets[i].techval=0; |
||
407 | if (cd->sheets[i].techcnt>1) { |
||
408 | p1 = cd->techs + cd->sheets[i].techoffset; |
||
409 | snprintf(techname,sizeof(techname),"user_techvar_%s", p1); |
||
410 | getdef (fname, techname, techval); |
||
411 | if (techval[0]) |
||
412 | for (j = 0; j < cd->sheets[i].techcnt; j++){ |
||
413 | p1 += strlen(p1); p1++; |
||
414 | if (!strcmp(techval, p1)) {cd->sheets[i].techval=j; break;} |
||
415 | } |
||
416 | } |
||
417 | } |
||
418 | } |
||
419 | |||
10 | reyssat | 420 | void getscore(struct classdata *cd, char *user) |
421 | { |
||
12221 | bpr | 422 | struct stat st[3]; |
423 | int i, cnt, non[3]; |
||
424 | char buf[3][MAX_FNAME+1]; |
||
7407 | bpr | 425 | |
12221 | bpr | 426 | snprintf(buf[0],sizeof(buf[0]),"score/%s",user); |
427 | snprintf(buf[1],sizeof(buf[1]),"score/%s.exam",user); |
||
428 | snprintf(buf[2],sizeof(buf[2]),"score/%s.bin",user); |
||
429 | cnt=cd->exocnt; if(cnt<=0) return; |
||
430 | for(i=0;i<3;i++) non[i]=stat(buf[i],st+i); |
||
431 | if(non[0] && non[1]) { |
||
432 | memset(uscore,0,sizeof(uscore[0])*cnt); |
||
433 | memset(&scoreheader,0,sizeof(scoreheader)); |
||
434 | return; |
||
435 | } |
||
436 | if(!non[2] && |
||
437 | st[2].st_size==sizeof(scoreheader)+sizeof(uscore[0])*cnt && |
||
438 | (non[0] || st[2].st_mtime>=st[0].st_mtime) && |
||
439 | st[2].st_mtime>=cd->modif) { |
||
440 | readscorebin(buf[2],cnt); |
||
441 | if(!non[1] && st[2].st_mtime<st[1].st_mtime) { |
||
442 | examscorecalc(cd,user); |
||
443 | savescorebin(cd,user); |
||
10 | reyssat | 444 | } |
12221 | bpr | 445 | return; |
446 | } |
||
447 | rawscorecalc(cd,user); |
||
448 | savescorebin(cd,user); |
||
10 | reyssat | 449 | } |
450 | |||
451 | void cmd_getscore(char *p) |
||
452 | { |
||
12221 | bpr | 453 | struct classdata *cd; |
454 | struct scoreresult tscore[MAX_CLASSEXOS]; |
||
455 | char *cut[4]; |
||
12471 | bpr | 456 | int i, j, sheet, exo, snew, stry, thissheet, thisexo; |
457 | double score, score2, quality, tt, ts, thisscore, sbest; |
||
458 | float slevel=0; |
||
7638 | bpr | 459 | |
12221 | bpr | 460 | if(cwdtype!=dir_class) { |
461 | sockerror(2,"getscore_no_class"); return; |
||
462 | } |
||
463 | if(*opt_user==0) { |
||
464 | sockerror(2,"getscore_no_user"); return; |
||
465 | } |
||
466 | cd=getclasscache(opt_class); |
||
467 | if(cd==NULL) { |
||
468 | sockerror(2,"getscore_bad_class"); return; |
||
469 | } |
||
470 | if(cutwords(p,cut,3)==3) { |
||
15855 | bpr | 471 | thissheet=atoi(cut[0])-1; thisexo=atoi(cut[1])-1; thisscore=atof(cut[2]); |
12221 | bpr | 472 | if(!isfinite(thisscore)) thisscore=0; |
473 | if(thisscore<-10) thisscore=-10; |
||
474 | if(thisscore>10) thisscore=10; |
||
475 | } |
||
15855 | bpr | 476 | else {thissheet=thisexo=-1;thisscore=0;} |
15847 | bpr | 477 | techvals(cd,opt_user); |
12221 | bpr | 478 | getscore(cd,opt_user); |
15847 | bpr | 479 | for(i=sheet=0;sheet<=cd->sheetcnt;sheet++){ |
480 | for(exo=0;exo<cd->sheets[sheet].exocnt;exo++,i++) { |
||
481 | /* j <-> i is the correspondance between the numerotation of |
||
482 | exercises with all versions and with one version */ |
||
483 | j=cd->sheets[sheet].indstart+cd->sheets[sheet].techval*cd->sheets[sheet].exocnt+exo; |
||
484 | tscore[i].require=cd->exos[j].require; |
||
17885 | bpr | 485 | if(cd->exos[j].require==0) {tscore[i].weight=0;} |
486 | else {tscore[i].weight=cd->exos[j].weight;} |
||
15847 | bpr | 487 | tscore[i].active=cd->exos[j].active; |
488 | tscore[i].sh=sheet; |
||
489 | tscore[i].exo=exo; |
||
490 | score=uscore[i].user; |
||
491 | stry=uscore[i].try; |
||
492 | score2=uscore[i].user2; |
||
493 | sbest=uscore[i].best; |
||
494 | slevel=uscore[i].level; |
||
495 | /* case of one exo in a sheet */ |
||
496 | if(sheet==thissheet && exo==thisexo) { |
||
497 | score+=thisscore; |
||
498 | stry++; |
||
499 | score2*=oldfactor; score2+=thisscore; |
||
500 | /* one compute the new sbest and slevel */ |
||
501 | if (uscore[i].high[0] < thisscore) { |
||
502 | sbest += (thisscore - uscore[i].high[0]); |
||
503 | int k; |
||
504 | for (k = 1; 10*k < tscore[i].require && uscore[i].high[k] < thisscore; k++) |
||
505 | uscore[i].high[k-1] = uscore[i].high[k]; |
||
506 | uscore[i].high[k-1] = thisscore; |
||
507 | slevel=uscore[i].high[0]; |
||
508 | } |
||
12221 | bpr | 509 | } |
15852 | bpr | 510 | if(sheet==cd->sheetcnt) { /* examens */ |
15847 | bpr | 511 | tscore[i].score=score; |
512 | tscore[i].mean=stry*2+uscore[i].hint; |
||
513 | tscore[i].try=stry; |
||
514 | tscore[i].best=sbest; |
||
515 | tscore[i].level=slevel; |
||
516 | tscore[i].sh=MAX_SHEETS; |
||
517 | continue; |
||
518 | } |
||
519 | if(score>tscore[i].require) score=tscore[i].require; |
||
520 | if(stry>0) { |
||
15852 | bpr | 521 | snew=uscore[i].new; if(uscore[i].hint>0) snew++; |
15847 | bpr | 522 | /* here we give up to 1 time unsuccessful tries. |
523 | * Together with a premium of 5 uncounted tries. |
||
524 | */ |
||
525 | if(snew<stry*2+5) tt=1; |
||
526 | else tt=(double) (snew-4)/(2*stry); /* tt>=1 */ |
||
527 | ts=(1-pow(oldfactor,stry))/(1-oldfactor); |
||
528 | quality=score2/(ts*tt); |
||
529 | } |
||
530 | else { |
||
531 | score=quality=stry=sbest=slevel=0; |
||
532 | } |
||
12221 | bpr | 533 | tscore[i].score=score; |
15847 | bpr | 534 | tscore[i].mean=quality; |
12221 | bpr | 535 | tscore[i].try=stry; |
536 | tscore[i].best=sbest; |
||
537 | tscore[i].level=slevel; |
||
15847 | bpr | 538 | tscore[i].last=uscore[i].last; |
539 | tscore[i].new=uscore[i].allnew; |
||
540 | mystrncpy(tscore[i].seedlast, |
||
541 | uscore[i].seed_score[uscore[i].seed_scorecnt-1].seed,SEEDSIZE); |
||
542 | tscore[i].seedscorelast=uscore[i].seed_score[uscore[i].seed_scorecnt-1].score; |
||
543 | p=tscore[i].seedscores; |
||
544 | *p++ = '['; |
||
545 | for(j=0;j<uscore[i].seed_scorecnt;j++){ |
||
546 | if (j) *p++=';'; |
||
547 | mystrncpy(p,uscore[i].seed_score[j].seed,SEEDSIZE); |
||
548 | p+=strlen(p); *p++=','; |
||
549 | p=moneyprint(p,uscore[i].seed_score[j].score); |
||
550 | } |
||
551 | *p++ = ']'; *p=0; |
||
552 | tscore[i].seedlastcnt=uscore[i].seedlastcnt; |
||
10 | reyssat | 553 | } |
12221 | bpr | 554 | } |
555 | answerlen=cd->exocnt*sizeof(tscore[0]); |
||
556 | memmove(textbuf+3,tscore,answerlen); |
||
557 | answerlen+=3; |
||
10 | reyssat | 558 | } |
559 | |||
560 | void cmd_scorelog(char *p) |
||
561 | { |
||
12221 | bpr | 562 | struct classdata *cd; |
563 | char buf[MAX_LINELEN+1]; |
||
7407 | bpr | 564 | |
12221 | bpr | 565 | if(cwdtype!=dir_class) { |
566 | sockerror(2,"scorelog_no_class"); return; |
||
567 | } |
||
568 | if(*opt_user==0) { |
||
569 | sockerror(2,"scorelog_no_user"); return; |
||
570 | } |
||
571 | cd=getclasscache(opt_class); |
||
572 | if(cd==NULL) { |
||
573 | sockerror(2,"scorelog_bad_class"); return; |
||
574 | } |
||
575 | getscore(cd,opt_user); |
||
576 | p=find_word_start(p); strip_trailing_spaces(p); |
||
577 | snprintf(buf,sizeof(buf),"%s\n",p); |
||
578 | wlogdaccessfile(buf,"a","score/%s",opt_user); |
||
579 | if(myisdigit(*p)) scoreline(cd,p); |
||
580 | savescorebin(cd,opt_user); |
||
10 | reyssat | 581 | } |