1: #include <stdio.h>
2: #include <string.h>
3: #include <math.h>
4: #include <ctype.h>
5: #ifdef __sun
6: #include <unistd.h>
7: #endif
8: #ifdef NeXT
9: #include <sys/file.h>
10: #endif
11: #include <stdlib.h>
12:
13: /*--------------------------------------------------------------*/
14: /* Constant Values for "hgr*.out". */
15: /*--------------------------------------------------------------*/
16: #define MAX_SECTION_NUMBER 3 /* maximum number of char for section number */
17: #define MAX_STUDENT_NUMBER 9 /* maximum number of char for student number */
18: #define MAX_STUDENT_NAME 30 /* maximum number of char for student name */
19: #define MAX_PROBLEM_NUMBER 150 /* maximum number of problems in a set */
20: #define FILE_NAME_LENGTH 256 /* maximum length of file name */
21: #define MAX_CLASS_SIZE 1024 /* maximum number of students in a class */
22:
23:
24: /*--------------------------------------------------------------*/
25: /* Constant Values for "set*.db". */
26: /*--------------------------------------------------------------*/
27: #define MAX_TRIES 100 /* tries 0..99 */
28:
29:
30: /*--------------------------------------------------------------*/
31: /* One line of record in "hgr*.out". */
32: /*--------------------------------------------------------------*/
33: typedef struct{
34: char section[MAX_SECTION_NUMBER+1];
35: char s_number[MAX_STUDENT_NUMBER+1];
36: char s_name[MAX_STUDENT_NAME+1];
37: char problem_number[MAX_PROBLEM_NUMBER];
38: char problem_score[MAX_PROBLEM_NUMBER];
39: } HGR_record;
40:
41: int GradedProblems=0; /* The number of problems in a HG'd record */
42: int NumberOfUpdates=0; /* The number of records need updated in hgr*.db */
43: int NumberOfProblems=0;
44: char *progname;
45: HGR_record hgr_record[MAX_CLASS_SIZE];
46:
47:
48: /*--------------------------------------------------------------*/
49: /* One line of record in "set*.out". */
50: /*--------------------------------------------------------------*/
51: typedef struct{
52: int valid; /* if a registered student */
53: char s_number[MAX_STUDENT_NUMBER+1]; /* student number */
54: char answer[MAX_PROBLEM_NUMBER]; /* a string of answers */
55: char tries[3*MAX_PROBLEM_NUMBER];
56: } SET_record;
57:
58: char line1[512],line2[512],line3[512]; /* The first three lines in set*.db */
59: int NumberOfStudents=0; /* Number of students in set*.db */
60: int ValidStudents=0; /* No. of Valid students in set*.db */
61: SET_record set_record[MAX_CLASS_SIZE];
62:
63:
64: /*--------------------------------------------------------------*/
65: /* */
66: /* Statistics for the number of tries in "set*.db". */
67: /* */
68: /*--------------------------------------------------------------*/
69: int s[MAX_PROBLEM_NUMBER][MAX_TRIES];
70: int t[MAX_CLASS_SIZE][MAX_PROBLEM_NUMBER];
71: int YesCnt[MAX_PROBLEM_NUMBER];
72: int yesCnt[MAX_PROBLEM_NUMBER];
73: int correct[MAX_PROBLEM_NUMBER];
74: int Weight[MAX_PROBLEM_NUMBER];
75: int TotalTries[MAX_PROBLEM_NUMBER];
76:
77: typedef struct{
78: int total;
79: int score[MAX_PROBLEM_NUMBER];
80: }Student;
81:
82: int GuyNumberOfStudents;
83: Student student[MAX_CLASS_SIZE];
84: #define PARTIAL 0
85: #define NOPARTIAL 1
86: /*--------------------------------------------------------------*/
87: /* */
88: /* */
89: /*--------------------------------------------------------------*/
90: void usage()
91: {
92: printf("USAGE: %s [-s set] [-t LargeTry] [-n NumberLargeTry]\n", progname);
93: }
94:
95:
96:
97: /*--------------------------------------------------------------*/
98: /* */
99: /* Return the maximum score of a problem. */
100: /* */
101: /*--------------------------------------------------------------*/
102: int Problem_Score(score_ptr,problem_number)
103: char *score_ptr;
104: char problem_number;
105: {
106: char *tmp_ptr;
107: char score;
108:
109: tmp_ptr=strchr(score_ptr,problem_number);
110: tmp_ptr=tmp_ptr+2;
111: sscanf(tmp_ptr, "%c", &score);
112: return(score-'0');
113: }
114:
115:
116: /*--------------------------------------------------------------*/
117: /* */
118: /* Check if the list of scores is valid */
119: /* */
120: /*--------------------------------------------------------------*/
121: int Valid_Score(scorelist,score_ptr)
122: char *scorelist;
123: char *score_ptr;
124: {
125: char *problem;
126: int score=-1;
127: int value=1;
128:
129: GradedProblems=0;
130: problem = scorelist;
131: while (*problem == '('){
132: GradedProblems++;
133: problem++;
134: score=Problem_Score(score_ptr,*problem);
135: problem=problem+2;
136: if (*problem != '*'&&((*problem-'0')>score)){
137: value=0;
138: }
139: problem=problem+3;
140: }
141: return(value);
142: }
143:
144: /*--------------------------------------------------------------*/
145: /* */
146: /* Open the hand graded file "./record/set`set`.out", */
147: /* and return the file pointer. */
148: /* */
149: /*--------------------------------------------------------------*/
150: FILE *Open_Read(filename)
151: char filename[FILE_NAME_LENGTH];
152: {
153: FILE *fp;
154:
155: if ((fp=fopen(filename,"r"))==NULL) {
156: printf("Error: can't open %s\n",filename);
157: exit(1);
158: }
159: return(fp);
160: }
161:
162: /*--------------------------------------------------------------*/
163: /* */
164: /* Open the hand graded file "./record/set`set`.out", */
165: /* and return the file pointer. */
166: /* */
167: /*--------------------------------------------------------------*/
168: FILE *Open_Write(filename)
169: char filename[FILE_NAME_LENGTH];
170: {
171: FILE *fp;
172:
173: if ((fp=fopen(filename,"w"))==NULL) {
174: printf("Error: can't open %s\n",filename);
175: exit(1);
176: }
177: return(fp);
178: }
179:
180:
181: int studentCompare(const void *a,const void *b)
182: {
183: Student *voida,*voidb;
184: voida=(Student *)a;
185: voidb=(Student *)b;
186: if (voida->total < voidb->total)
187: return 1;
188: if (voida->total > voidb->total)
189: return -1;
190: return 0;
191: }
192:
193: /*--------------------------------------------------------------*/
194: /* */
195: /* */
196: /*--------------------------------------------------------------*/
197: void Read_Record(fp_set)
198: FILE *fp_set;
199: {
200: int count,i,j;
201: int done,len;
202: int problem;
203: int problem_cnt;
204: char fmtbuf[128];
205: char nextline[512];
206: char temp;
207:
208: fgets(line1,511,fp_set);
209: sscanf(line1,"%d",&problem_cnt);
210:
211: fgets(line2,511,fp_set);
212: len=strlen(line2); /* weight line */
213: for(i=0;i<problem_cnt;i++) {
214: Weight[i] = line2[i] - '0'; /* put weight into a global array */
215: }
216:
217: fgets(line3,511,fp_set); /* get rid of hand grading line */
218: /* here problem_cnt should be the same as NumberOfProblems */
219: NumberOfProblems=strlen(line2)-1;
220: sprintf(fmtbuf,"%%%dc %%%dc%%%dc",
221: MAX_STUDENT_NUMBER, NumberOfProblems+1, 3*NumberOfProblems);
222:
223: done=0;
224: count=0;
225: while (!done){
226: done=!fgets(nextline,511,fp_set);
227: len=strlen(nextline);
228: if (!done){
229: count++;
230: sscanf(nextline, fmtbuf,
231: set_record[count].s_number,
232: set_record[count].answer,
233: set_record[count].tries);
234: /* printf("(%s) (%s) (%s)\n",
235: set_record[count].s_number,
236: set_record[count].answer,
237: set_record[count].tries); */
238: set_record[count].valid=0;
239: for (i=0;i<NumberOfProblems;i++){
240: if (set_record[count].answer[i]!='-')
241: set_record[count].valid=1;
242: }
243: }
244: }
245: NumberOfStudents=count;
246: printf("%d",NumberOfStudents);
247: fclose(fp_set);
248:
249: for(j=0,i=0;i<NumberOfStudents;j++,i++)
250: {
251: for(problem=0;problem<NumberOfProblems;problem++)
252: {
253: temp=set_record[i].answer[problem];
254: switch (temp)
255: {
256: case 'y':
257: case 'Y':
258: student[j].score[problem]=Weight[problem];
259: student[j].total+=Weight[problem];
260: break;
261: case 'n':
262: case 'N':
263: student[j].score[problem]=0;
264: break;
265: default:
266: if (isdigit(temp))
267: {
268: student[j].score[problem]=temp-'0';
269: student[j].total+=student[j].score[problem];
270: }
271: else
272: {
273: student[j].score[problem]=0;
274: student[j].total+=student[j].score[problem];
275: fprintf(stderr,"Invalid score for student ");
276: fprintf(stderr,"%s, problem",set_record[i].s_number);
277: fprintf(stderr,"%d, score == ",problem);
278: fprintf(stderr,"%c skipping them\n",temp);
279: j--;
280: goto skip_student;
281: }
282: }
283: }
284: skip_student: j=j;
285: }
286: GuyNumberOfStudents=j;
287: qsort((char *)student,GuyNumberOfStudents,sizeof(Student),studentCompare);
288: }
289:
290:
291:
292: /*--------------------------------------------------------------*/
293: /* */
294: /* t[i][j]: the number of tries for the `i`th student, the */
295: /* `j`th problem in set*.db file. */
296: /* t[i][*]=set_record[i].tries */
297: /* s[i][j]: the number of students who work on the `i`th */
298: /* problem for `j` tries. */
299: /* */
300: /*--------------------------------------------------------------*/
301: void Sort_By_Tries()
302: {
303: int i,j,try;
304: char *tmp;
305:
306: /* initialization */
307: for (i=0;i<MAX_PROBLEM_NUMBER;i++){
308: YesCnt[i] = 0;
309: yesCnt[i] = 0;
310: correct[i] = 0;
311: TotalTries[i]=0;
312: for (j=0; j<MAX_TRIES; j++){
313: s[i][j]=0;
314: }
315: for (j=0;j<MAX_CLASS_SIZE;j++){
316: t[j][i]=0;
317: }
318: }
319:
320: for (i=0;i<NumberOfStudents;i++){
321: tmp=set_record[i].tries;
322: for (j=0; j<NumberOfProblems; j++){
323: sscanf(tmp+3*j,"%d,",&try);
324: if ((try>=0) && (try <=99)){
325: s[j][try]++;
326: t[i][j]=try;
327: TotalTries[j]=TotalTries[j]+try;
328: }
329: }
330: }
331:
332: }
333:
334:
335: double GetDegreeOfDiscrim(int problem,int mode)
336: {
337: int i,numTopRight=0,numBottomRight=0,twentySevenPercent;
338: double dd;
339:
340: twentySevenPercent=(int)ceil(.27*(double)GuyNumberOfStudents);
341: for(i=0;i<twentySevenPercent;i++)
342: {
343: switch (mode)
344: {
345: case PARTIAL:
346: if (student[i].score[problem] > 0) { numTopRight++; }
347: if (student[GuyNumberOfStudents-i].score[problem]>0){numBottomRight++;}
348: break;
349: case NOPARTIAL:
350: if (student[i].score[problem] == Weight[problem]) { numTopRight++; }
351: if (student[GuyNumberOfStudents-i].score[problem] == Weight[problem])
352: { numBottomRight++; }
353: break;
354: }
355: }
356: dd=(((((double)numTopRight)/((double)twentySevenPercent))-
357: (((double)numBottomRight)/((double)twentySevenPercent))));
358: return 100.0*dd;
359: }
360:
361: double GetDifficulty(int problem, int mode)
362: {
363: int i,numWrong=0;
364: for(i=0;i<GuyNumberOfStudents;i++)
365: {
366: switch(mode)
367: {
368: case PARTIAL:
369: if (student[i].score[problem] == 0) { numWrong++; }
370: break;
371: case NOPARTIAL:
372: if (student[i].score[problem] < Weight[problem]) { numWrong++; }
373: break;
374: }
375: }
376: return (100.0*((double)numWrong/(double)GuyNumberOfStudents));
377: }
378:
379: #define MAXSCORE 58
380: void doScoreHistogram(void)
381: {
382: int hist[MAXSCORE],i,numGoneBy=0;
383: for(i=0;i<MAXSCORE;i++)
384: hist[i]=0;
385: for(i=0;i<GuyNumberOfStudents;i++)
386: {
387: hist[student[i].total]++;
388: }
389: printf("Scr Num Tot\n");
390: for(i=0;i<MAXSCORE;i++)
391: {
392: numGoneBy+=hist[i];
393: printf("%3d %3d %3d\n",i,hist[i],numGoneBy);
394: }
395: }
396:
397: /*--------------------------------------------------------------*/
398: /* */
399: /* This is only used to print out the statistics in s[][], */
400: /* which stores the number of occurences in a form of */
401: /* s[problem_number-1][tries]. This is not normally used. */
402: /* For a global view only. */
403: /* */
404: /*--------------------------------------------------------------*/
405: void Print_moment(avg,sd,sd3,m,students)
406: float avg[MAX_PROBLEM_NUMBER];
407: float sd[MAX_PROBLEM_NUMBER];
408: float sd3[MAX_PROBLEM_NUMBER];
409: int m[MAX_PROBLEM_NUMBER];
410: int students[MAX_PROBLEM_NUMBER];
411: {
412: int i;
413: float dod,disP,disNP,difP,difNP;
414:
415: printf("\nThis is the statistics for each problem:\n");
416: printf("Prob# MxTries avg. s.d. s.k. #Stdnts ");
417: printf(" #Yes #yes Tries DoDiff Dis(P) Dif(P) Dis(NP) Dif(NP)\n");
418: for (i=0;i<NumberOfProblems;i++){
419: dod=1.0-((float)(YesCnt[i]+yesCnt[i]+correct[i])/(float)TotalTries[i]);
420: disP=GetDegreeOfDiscrim(i,PARTIAL);
421: difP=GetDifficulty(i,PARTIAL);
422: disNP=GetDegreeOfDiscrim(i,NOPARTIAL);
423: difNP=GetDifficulty(i,NOPARTIAL);
424: printf("P %2d:",i+1);
425: printf("%7d %8.2f %7.2f %6.2f %5d %5d %5d %5d %5.2f %5.2f %5.2f %6.2f %6.2f",
426: m[i],avg[i],sd[i],sd3[i],students[i],YesCnt[i],yesCnt[i],
427: TotalTries[i],dod,disP,difP,disNP,difNP);
428: printf("\n");
429: }
430: doScoreHistogram();
431: }
432:
433:
434: /*--------------------------------------------------------------*/
435: /* */
436: /* This is only used to print out the statistics in s[][], */
437: /* which stores the number of occurences in a form of */
438: /* s[problem_number-1][tries]. This is not normally used. */
439: /* For a global view only. */
440: /* */
441: /*--------------------------------------------------------------*/
442: void Print_Tries()
443: {
444: int i,j;
445:
446: printf("\nThis is the sumary of tries:\n");
447: for (i=0;i<NumberOfProblems;i++){
448: printf("P %d:",i+1);
449: for (j=0; j<MAX_TRIES; j++)
450: if (s[i][j]!=0)
451: printf("%d( %d) ",j,s[i][j]);
452: printf("\n");
453: }
454: }
455:
456: /*--------------------------------------------------------------*/
457: /* */
458: /* This is only used to print out the statistics in s[][], */
459: /* which stores the number of occurences in a form of */
460: /* s[problem_number-1][tries]. This is not normally used. */
461: /* For a global view only. */
462: /* */
463: /*--------------------------------------------------------------*/
464:
465: void Average_Tries()
466: {
467: float avg[MAX_PROBLEM_NUMBER];
468: float sd[MAX_PROBLEM_NUMBER];
469: float sd3[MAX_PROBLEM_NUMBER];
470: int students[MAX_PROBLEM_NUMBER];
471: int m[MAX_PROBLEM_NUMBER];
472: int i,j;
473: float tmp1,tmp2;
474: float sum;
475:
476: /* max tries for each problem */
477: for (i=0;i<NumberOfProblems;i++){
478: m[i]=0;
479: for (j=0;j<NumberOfStudents;j++){
480: if (t[j][i]>m[i]){
481: m[i]=t[j][i];
482: }
483: }
484: }
485: for (i=0;i<NumberOfStudents;i++){
486: if (set_record[j].valid){
487: ValidStudents++;
488: }
489: }
490:
491: /* first moment */
492: for (i=0;i<NumberOfProblems;i++){
493: avg[i]=0.0; /* initialization */
494: students[i]=0;
495: for (j=1;j<NumberOfStudents;j++){
496: if (set_record[j].valid){
497: avg[i]=avg[i]+t[j][i]; /* sumation actually */
498: students[i]=students[i]+1;
499: }
500: }
501: avg[i]=avg[i]/students[i]; /* real average */
502: }
503:
504: /* second moment */
505: for (i=0;i<NumberOfProblems;i++){
506: sd[i]=0.0;
507: sum=0.0;
508: for (j=0;j<NumberOfStudents;j++){
509: if (set_record[j].valid){
510: tmp1=(float)t[j][i];
511: tmp2=(tmp1-avg[i])*(tmp1-avg[i]);
512: sum=sum+tmp2;
513: }
514: sd[i]=sum/(float)(students[i]-1);
515: sd[i]=sqrt((double) sd[i]);
516: }
517: }
518:
519: /* third moment, skewness */
520: for (i=0;i<NumberOfProblems;i++){
521: sd3[i]=0.0;
522: sum=0.0;
523: for (j=0;j<NumberOfStudents;j++){
524: if (set_record[j].valid){
525: tmp1=(float)t[j][i];
526: tmp2=(tmp1-avg[i])*(tmp1-avg[i])*(tmp1-avg[i]);
527: sum=sum+tmp2;
528: }
529: sd3[i]=sum/(float)(students[i]);
530: sd3[i]=sd3[i]/(sd[i]*sd[i]*sd[i]);
531: }
532: }
533: Print_moment(avg,sd,sd3,m,students); /* print mean, sd, skewness */
534: }
535:
536: /*--------------------------------------------------------------*/
537: /* */
538: /* */
539: /*--------------------------------------------------------------*/
540: void Percentage_Scores(set)
541: int set;
542: {
543: int i,j;
544: int total_weight = 0,
545: total_scores=0;
546: float percentage;
547:
548: for (i=0;i<NumberOfStudents;i++){
549: if (set_record[i].valid){
550: for (j=0;j<NumberOfProblems;j++){
551: total_weight = total_weight+Weight[j];
552: switch (set_record[i].answer[j]){
553: case 'Y': YesCnt[j] = YesCnt[j]+1;
554: total_scores = total_scores + Weight[j];
555: break;
556: case 'y': yesCnt[j] = yesCnt[j]+1;
557: total_scores = total_scores + Weight[j];
558: break;
559: default : if (set_record[i].answer[j] >= '0' &&
560: set_record[i].answer[j] <= '9' ) {
561: correct[i]=correct[i]+1;
562: total_scores=total_scores+(set_record[i].answer[j]-'0');
563: }
564: break;
565: }
566: }
567: }
568: }
569:
570: percentage = (float)total_scores / (float)total_weight;
571: percentage = percentage * 100.0;
572: printf("\nThe percentage score for set%d.db is %7.2f%%\n",set,percentage);
573: /*printf("Total Number of Students in set%d.db is %d\n",set,ValidStudents);*/
574:
575: }
576:
577: /*--------------------------------------------------------------*/
578: /* */
579: /* */
580: /*--------------------------------------------------------------*/
581: void Large_Tries(LargeTry, NumberLargeTry)
582: int LargeTry, NumberLargeTry;
583: {
584: int i,j;
585: int count;
586: int credit; /* Number of credits should be taken off */
587:
588:
589: printf("\nHere is a list of students who have %d tries more than %d times: \n\n", LargeTry, NumberLargeTry);
590:
591: for (i=0;i<NumberOfStudents;i++){
592: count=0;
593: credit=0;
594: for (j=0;j<NumberOfProblems;j++){
595: if (t[i][j]>=LargeTry){
596: count++;
597: if (set_record[i].answer[j]=='Y' ||
598: set_record[i].answer[j]=='y')
599: credit ++;
600: }
601: }
602: if (count >= NumberLargeTry){
603: printf("(%d) %s \n",credit, set_record[i].s_number);
604: printf("%s %s \n", set_record[i].answer, set_record[i].tries);
605: }
606: }
607:
608: }
609:
610: /*--------------------------------------------------------------*/
611: /* */
612: /* */
613: /*--------------------------------------------------------------*/
614: int main(argc,argv)
615: int argc;
616: char *argv[];
617:
618: {
619:
620: int set=1;
621: int inputNotOK=1;
622: int LargeTry=0,NumberLargeTry=0;
623: FILE *fp_set;
624: char set_file[FILE_NAME_LENGTH];
625: char path[FILE_NAME_LENGTH];
626: char filename[FILE_NAME_LENGTH];
627:
628: for( progname = *argv++; --argc; argv++) {
629: if ( argv[0][0] == '-' ) {
630: switch(argv[0][1]) {
631: case 's': set = atoi(argv[1]); break;
632: case 't': LargeTry = atoi(argv[1]); break;
633: case 'n': NumberLargeTry = atoi(argv[1]); break;
634: default: usage(); break;
635: }
636: }
637: }
638:
639: while ( inputNotOK ) {
640: puts("Enter the ABSOLUTE path of class");
641: scanf("%s", path);
642: if( access(path, F_OK) == -1 ) {
643: } else {
644: sprintf(filename,"%s/records",path);
645: if( access(filename, F_OK) == -1 ) {
646: puts("There isn't a records dir in this CLASS directory");
647: puts("Please Specify another calss");
648: } else {
649: inputNotOK = 0;
650: }
651: }
652: }
653: chdir(path);
654: sprintf(set_file, "records/set%d.db",set);
655: /* sprintf(out_file, "records/set%d.out",set); */
656: fp_set=Open_Read(set_file);
657: /* fp_out=Open_Write(out_file); */
658:
659: Read_Record(fp_set);
660:
661: Sort_By_Tries();
662: /* Print_Tries(); */
663: Percentage_Scores(set);
664: Average_Tries();
665:
666: Large_Tries(LargeTry, NumberLargeTry);
667: return 0;
668: }
669:
670:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>