Subversion Repositories wimsdev

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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.  
  18.                 /* student score management */
  19.  
  20. double oldfactor=0.85;  /* quality factor, should remain stable. */
  21.  
  22.         /* User score information of an exercise. Size: 16 bytes. */
  23. typedef struct scoredata {
  24.     unsigned short int num, new, try, hint;
  25.     float user, user2;
  26. } scoredata;
  27.  
  28. struct scoreheader {
  29.     char raf[8][20];
  30.     int sheet, exo;
  31.     char session[32];
  32. } scoreheader;
  33. struct scoredata uscore[MAX_CLASSEXOS];
  34.  
  35. struct scoreresult tscore[MAX_CLASSEXOS];
  36.  
  37. #define oldraf scoreheader.raf
  38. #define oldsheet scoreheader.sheet
  39. #define oldexo scoreheader.exo
  40. #define oldsession scoreheader.session
  41.  
  42.         /* one line of score. */
  43. void scoreline(struct classdata *cd, char *l)
  44. {
  45.     int i,sheet,exo,num;
  46.     char *pm[16];
  47.     struct scoredata *thiscore;
  48.     float score;
  49.  
  50.     i=cutwords(l,pm,8); if(i<6) return;
  51.     if(strcmp(pm[i-1],"noscore")==0 || strcmp(pm[i-1],"erased")==0) {
  52.         if(strcmp(pm[1],oldsession)!=0)
  53.           mystrncpy(oldsession,pm[1],sizeof(oldsession));
  54.         return;
  55.     }
  56.     sheet=atoi(pm[2]); exo=atoi(pm[3]);
  57.     if(sheet<=0 || sheet>MAX_SHEETS || exo<=0 || exo>MAX_EXOS) return;
  58.     num=search_data(cd->exos,cd->exocnt,sizeof(exodata),((sheet-1)<<8)+(exo-1));
  59.     if(num<0) return;
  60.     thiscore=uscore+num;
  61.     if(strcmp(pm[4],"score")==0) {
  62.         score=atof(pm[5]); if(!finite(score)) score=0;
  63.         if(score>10) score=10; if(score<-10) score=-10;
  64.        
  65.         if(strcmp(pm[1],oldsession)==0 &&   /* measure to prohibit simultaneous scoring. */
  66.            sheet==oldsheet && exo==oldexo &&
  67.            strncmp(pm[0],oldraf[6],13)!=0   /* prohit scores immediately after rafale */
  68.            ) {
  69.             thiscore->user+=score;
  70.             thiscore->user2*=oldfactor;
  71.             thiscore->user2+=score;
  72.             if(thiscore->try<60000) thiscore->try++;
  73.             oldsheet=oldexo=0;
  74.         }
  75.     }
  76.     else {
  77.         if(strcmp(pm[4],"rafale")==0) { /* rafale punishment */
  78.             if(strncmp(pm[0],oldraf[3],13)==0 && thiscore->new<60000) thiscore->new++;
  79.             memmove(oldraf[1],oldraf[0],sizeof(oldraf[0])*7);
  80.             mystrncpy(oldraf[0],pm[0],sizeof(oldraf[0]));
  81.         }
  82.         if(strcmp(pm[4],"resume")!=0 && strcmp(pm[4],"rafale")!=0) {
  83.             if(strcmp(pm[4],"hint")==0) thiscore->hint++;
  84.             else if(thiscore->new<60000) thiscore->new++;
  85.         }
  86.         mystrncpy(oldsession,pm[1],sizeof(oldsession));
  87.         oldsheet=sheet; oldexo=exo;
  88.     }
  89. }
  90.  
  91. unsigned int _cuttime(char ends[], char starts[], unsigned int startn)
  92. {
  93.     int h1,h2,m1,m2,s2, t;
  94.     if(ends[0]==0) return 0;
  95.     if(strncmp(ends,starts,14)<0) return 10;
  96.     if(strncmp(ends,starts,8)>0) return 0;
  97.     h1=atoi(ends+9);   m1=atoi(ends+12);
  98.     h2=atoi(starts+9); m2=atoi(starts+12); s2=atoi(starts+15);
  99.     t=((h1-h2)*60+(m1-m2))*60-s2;
  100.     return startn+t;
  101. }
  102.  
  103.         /* Gather exam score. */
  104. void examscorecalc(struct classdata *cd, char *uname)
  105. {
  106.     struct scoredata *thiscore;
  107.     char nbuf[MAX_FNAME+1];
  108.     char cuttimes[MAX_EXOS][16];
  109.     char rbuf[MAX_FILELEN+1];
  110.     char *wlist[8];
  111.     char *p1, *p2;
  112.     int i, k, ecnt, num;
  113.     double ss, sc[MAX_EXOS], sc2[MAX_EXOS];
  114.     int ind[MAX_EXOS];
  115.     unsigned int tr[MAX_EXOS], all[MAX_EXOS], ver[MAX_EXOS], start[MAX_EXOS], dure[MAX_EXOS];
  116.     char *ip[MAX_EXOS], *ses[MAX_EXOS];
  117.     unsigned int start1, endtime[MAX_EXOS];
  118.     signed int dure1;
  119.  
  120.     ecnt=cd->examcnt; if(ecnt<=0) return; if(ecnt>MAX_EXOS) ecnt=MAX_EXOS;
  121.     memset(all,0,sizeof(all)), memset(ver,0,sizeof(ver));
  122.     for(i=0;i<MAX_EXOS;i++) ind[i]=-1;
  123.     for(i=0;i<ecnt;i++) {
  124.         k=((cd->exos[i+cd->examstart].num)&255);
  125.         all[k]=cd->exos[i+cd->examstart].require;
  126.         ind[k]=i+cd->examstart;
  127.     }
  128.     memset(sc,0,sizeof(sc)); memset(sc2,0,sizeof(sc2));
  129.     memset(tr,0,sizeof(tr)); memset(cuttimes,0,sizeof(cuttimes));
  130.     memset(dure,0,sizeof(dure)); memset(start,0,sizeof(start));
  131.     memset(endtime,0,sizeof(endtime));
  132.     memset(ip,0,sizeof(ip)); memset(ses,0,sizeof(ses));
  133.     snprintf(nbuf,sizeof(nbuf),"score/%s.exam",uname);
  134.     readfile(nbuf,rbuf,sizeof(rbuf));
  135.     if(rbuf[0]==0) goto end;
  136.     for(p1=rbuf; p1!=NULL && *p1; p1=p2) {
  137.         p2=strchr(p1,'\n'); if(p2!=NULL) *p2++=0;
  138.         i=cutwords(find_word_start(p1),wlist,7);
  139.         if(i<6) continue;
  140.         i=atoi(wlist[0])-1; if(i<0 || i>=ecnt) continue;
  141.         dure1=atoi(wlist[2]); start1=atoi(wlist[3]);
  142.         if(strcmp(wlist[1],"--")==0) {  /* session closure */
  143.             start[i]=dure[i]=0; ip[i]=ses[i]="";
  144.             continue;
  145.         }
  146.         if(strcmp(wlist[1],"00")==0) {
  147.             if(sc2[i]<sc[i]) sc2[i]=sc[i];
  148.             ver[i]=1; tr[i]++; start[i]=start1; dure[i]=dure1; sc[i]=0;
  149.             ip[i]=wlist[4]; ses[i]=wlist[5];
  150.             if(tr[i]==1 && wlist[6]!=NULL) {
  151.                 char *pp1, *pp2, lbuf[CTBUFLEN];
  152.                 if(cd->ctptr[ind[i]]>=0)
  153.                   mystrncpy(lbuf,cd->ctbuf+cd->ctptr[ind[i]],sizeof(lbuf));
  154.                 else lbuf[0]=0;
  155.                 if(lbuf[0]) {
  156.                     for(pp1=find_word_start(lbuf); *pp1; pp1=find_word_start(pp2)) {
  157.                         pp2=find_word_end(pp1); if(pp2-pp1!=14) continue;
  158.                         if(*pp2) *pp2++=0;
  159.                         pp1[8]='.'; pp1[11]=':';
  160.                         if(strcmp(pp1,wlist[6])<0) continue;
  161.                         memmove(cuttimes[i],pp1,15); break;
  162.                     }
  163.                 }
  164.             }
  165.             endtime[i]=_cuttime(cuttimes[i],wlist[6],start1);
  166.         }
  167.         else if(ver[i]==0) tr[i]++;
  168.         if(tr[i]>all[i]) continue;
  169.         ss=atof(wlist[1]); if(ss<=0) continue; if(ss>10) ss=10;
  170.         if(ss!=sc[i] && (dure1>=0 ||    /* checking conditions */
  171.                         (start1-start[i]<dure[i]*60 &&
  172.                          dure[i]>0 && dure[i]<4096 &&
  173.                          *ses[i]!=0 && *ip[i]!=0 &&
  174.                          start[i]!=0 && start1>start[i] &&
  175.                          (endtime[i]==0 || endtime[i]>=start1) &&
  176.                          strcmp(ip[i],wlist[4])==0 &&
  177.                          strcmp(ses[i],wlist[5])==0)))
  178.           sc[i]=ss;
  179.     }
  180.     end:
  181.     for(i=0; i<ecnt; i++) {
  182.         if(sc2[i]<sc[i]) sc2[i]=sc[i];
  183.         num=search_data(cd->exos,cd->exocnt,sizeof(exodata),0xFF00+i);
  184.         if(num<0) continue;
  185.         thiscore=uscore+num;
  186.         thiscore->user=sc2[i];
  187.         thiscore->try=tr[i];
  188.         if(cuttimes[i][0] && strncmp(cuttimes[i],nowstr,14)<0) k=0; else k=1;
  189.         thiscore->hint=k;
  190.     }
  191. }
  192.  
  193.         /* calculate score from raw data, core routine. */
  194. void rawscorecalc(struct classdata *cd, char *uname)
  195. {
  196.     int i;
  197.     char fbuf[MAX_FILELEN+1];
  198.     char *p1, *p2;
  199.     char namebuf[MAX_FNAME+1];
  200.  
  201.     memset(uscore,0,sizeof(uscore[0])*cd->exocnt);
  202.     memset(&scoreheader,0,sizeof(scoreheader));
  203.     for(i=0;i<cd->exocnt;i++) uscore[i].num=cd->exos[i].num;
  204.     snprintf(namebuf,sizeof(namebuf),"score/%s",uname);
  205.     readfile(namebuf,fbuf,sizeof(fbuf));
  206.     if(fbuf[0]!=0) {
  207.         oldsession[0]=oldsheet=oldexo=0;
  208.         for(p1=fbuf; *p1; p1=p2) {
  209.             p2=strchr(p1,'\n'); if(p2) *p2++=0; else p2=p1+strlen(p1);
  210.             if(myisdigit(*p1)) scoreline(cd,p1);
  211.         }
  212.     }
  213.     examscorecalc(cd,uname);
  214. }
  215.  
  216. void savescorebin(struct classdata *cd, char *uname)
  217. {
  218.     int fd, cnt;
  219.     char fname[MAX_FNAME+1];
  220.     snprintf(fname,sizeof(fname),"score/%s.bin",uname);
  221.     cnt=cd->exocnt;
  222.     fd=creat(fname,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
  223.     if(fd==-1) return;
  224.     write(fd,&scoreheader,sizeof(scoreheader));
  225.     write(fd,uscore,sizeof(uscore[0])*cnt);
  226.     close(fd);
  227. }
  228.  
  229. void readscorebin(char *fname,int cnt)
  230. {
  231.     int fd;
  232.     fd=open(fname,O_RDONLY);
  233.     if(fd==-1) return;
  234.     read(fd,&scoreheader,sizeof(scoreheader));
  235.     read(fd,uscore,sizeof(uscore[0])*cnt);
  236.     close(fd);
  237. }
  238.  
  239. void getscore(struct classdata *cd, char *user)
  240. {
  241.     struct stat st[3];
  242.     int i, cnt, non[3];
  243.     char buf[3][MAX_FNAME+1];
  244.    
  245.     snprintf(buf[0],sizeof(buf[0]),"score/%s",user);
  246.     snprintf(buf[1],sizeof(buf[1]),"score/%s.exam",user);
  247.     snprintf(buf[2],sizeof(buf[2]),"score/%s.bin",user);
  248.     cnt=cd->exocnt; if(cnt<=0) return;
  249.     for(i=0;i<3;i++) non[i]=stat(buf[i],st+i);
  250.     if(non[0] && non[1]) {
  251.         memset(uscore,0,sizeof(uscore[0])*cnt);
  252.         memset(&scoreheader,0,sizeof(scoreheader));
  253.         return;
  254.     }
  255.     if(!non[2] &&
  256.        st[2].st_size==sizeof(scoreheader)+sizeof(uscore[0])*cnt &&
  257.        (non[0] || st[2].st_mtime>=st[0].st_mtime) &&
  258.        st[2].st_mtime>=cd->modif) {
  259.         readscorebin(buf[2],cnt);
  260.         if(!non[1] && st[2].st_mtime<st[1].st_mtime) {
  261.             examscorecalc(cd,user);
  262.             savescorebin(cd,user);
  263.         }
  264.         return;
  265.     }
  266.     rawscorecalc(cd,user);
  267.     savescorebin(cd,user);
  268. }
  269.  
  270. void cmd_getscore(char *p)
  271. {
  272.     struct classdata *cd;
  273.     char *cut[4];
  274.     int i, sheet, exo, snew, stry, lastsheet, thissheet, thisexo;
  275.     double score, score2, quality, tt, ts, thisscore;
  276.     if(cwdtype!=dir_class) {
  277.         sockerror(2,"getscore_no_class"); return;
  278.     }
  279.     if(*opt_user==0) {
  280.         sockerror(2,"getscore_no_user"); return;
  281.     }
  282.     cd=getclasscache(opt_class);
  283.     if(cd==NULL) {
  284.         sockerror(2,"getscore_bad_class"); return;
  285.     }
  286.     if(cutwords(p,cut,3)==3) {
  287.         thissheet=atoi(cut[0]); thisexo=atoi(cut[1]); thisscore=atof(cut[2]);
  288.         if(!finite(thisscore)) thisscore=0;
  289.         if(thisscore<-10) thisscore=-10;
  290.         if(thisscore>10) thisscore=10;
  291.     }
  292.     else {thissheet=thisexo=thisscore=0;}
  293.     getscore(cd,opt_user);
  294.     lastsheet=0;
  295.     for(i=0;i<cd->exocnt;i++) {
  296.         tscore[i].num=cd->exos[i].num;
  297.         tscore[i].require=cd->exos[i].require;
  298.         tscore[i].weight=cd->exos[i].weight;
  299.         sheet=(cd->exos[i].num>>8)+1;
  300.         exo=((cd->exos[i].num)&255)+1;
  301.         score=uscore[i].user; stry=uscore[i].try; score2=uscore[i].user2;
  302.         if(sheet==thissheet && exo==thisexo) {
  303.             score+=thisscore; stry++;
  304.             score2*=oldfactor; score2+=thisscore;
  305.         }
  306.         if(sheet==256) {
  307.             tscore[i].score=score;
  308.             tscore[i].mean=stry*2+uscore[i].hint;
  309.             continue;
  310.         }
  311.         if(score>cd->exos[i].require) score=cd->exos[i].require;
  312.         if(score>0 && stry>0) {
  313.             snew=uscore[i].new; if(uscore[i].hint>0) snew++;
  314.                 /* here we give up to 1 time unsuccessful tries.
  315.                  * Together with a premium of 5 uncounted tries. */
  316.             if(snew<stry*2+5) tt=1;
  317.             else tt=(double) (snew-4)/(2*stry); /* tt>=1 */
  318.             ts=(1-pow(oldfactor,stry))/(1-oldfactor);
  319.             quality=score2/(ts*tt);
  320.         }
  321.         else score=quality=0;
  322.         tscore[i].score=score; tscore[i].mean=quality;
  323.     }
  324.     answerlen=cd->exocnt*sizeof(tscore[0]);
  325.     memmove(textbuf+3,tscore,answerlen);
  326.     answerlen+=3;
  327. }
  328.  
  329. void cmd_scorelog(char *p)
  330. {
  331.     struct classdata *cd;
  332.     char buf[MAX_LINELEN+1];
  333.    
  334.     if(cwdtype!=dir_class) {
  335.         sockerror(2,"scorelog_no_class"); return;
  336.     }
  337.     if(*opt_user==0) {
  338.         sockerror(2,"scorelog_no_user"); return;
  339.     }
  340.     cd=getclasscache(opt_class);
  341.     if(cd==NULL) {
  342.         sockerror(2,"scorelog_bad_class"); return;
  343.     }
  344.     getscore(cd,opt_user);
  345.     p=find_word_start(p); strip_trailing_spaces(p);
  346.     snprintf(buf,sizeof(buf),"%s\n",p);
  347.     accessfile(buf,"a","score/%s",opt_user);
  348.     if(myisdigit(*p)) scoreline(cd,p);
  349.     savescorebin(cd,opt_user);
  350. }
  351.  
  352.