version 1.4, 2000/01/25 17:14:29
|
version 1.12, 2000/06/30 21:36:16
|
Line 1
|
Line 1
|
|
/* Library of useful functions |
|
Copyright (C) 1992-2000 Michigan State University |
|
|
|
The CAPA system is free software; you can redistribute it and/or |
|
modify it under the terms of the GNU Library General Public License as |
|
published by the Free Software Foundation; either version 2 of the |
|
License, or (at your option) any later version. |
|
|
|
The CAPA system 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 |
|
Library General Public License for more details. |
|
|
|
You should have received a copy of the GNU Library General Public |
|
License along with the CAPA system; see the file COPYING. If not, |
|
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
Boston, MA 02111-1307, USA. */ |
|
|
/* =||>|===================== capaCommon.c =====================|<||= */ |
/* =||>|===================== capaCommon.c =====================|<||= */ |
/* created 1994 by Isaac Tsai */ |
/* created 1994 by Isaac Tsai */ |
/* 1994, 1995, 1996, 1997, 1998, 1999 copyrighted by Isaac Tsai */ |
/* 1994, 1995, 1996, 1997, 1998, 1999 copyrighted by Isaac Tsai */ |
Line 569 int set;
|
Line 587 int set;
|
} |
} |
funlockstream(fp); fclose(fp); |
funlockstream(fp); fclose(fp); |
if(!found) { |
if(!found) { |
ans_p = capa_malloc(nq+1,1); |
ans_p = capa_malloc(nq+2,1); |
tries_p = capa_malloc(3*nq+2,1); /* space and \0 */ |
tries_p = capa_malloc(3*nq+3,1); /* space and \0 */ |
for(ii=0;ii<nq;ii++) { /* Initialize answer string and tries string */ |
for(ii=0;ii<nq;ii++) { /* Initialize answer string and tries string */ |
ans_p[ii] = '-'; tries_p[3*ii] = ' '; tries_p[3*ii + 1] = '0'; |
ans_p[ii] = '-'; tries_p[3*ii] = ' '; tries_p[3*ii + 1] = '0'; |
if(ii < nq-1) tries_p[3*ii + 2] = ','; |
if(ii < nq-1) tries_p[3*ii + 2] = ','; |
Line 585 int set;
|
Line 603 int set;
|
comma=index(oneline,','); |
comma=index(oneline,','); |
length=((int)(comma-oneline))-(MAX_STUDENT_NUMBER+1); |
length=((int)(comma-oneline))-(MAX_STUDENT_NUMBER+1); |
if (length < nq) { |
if (length < nq) { |
ans_p = capa_malloc(nq+1,1); |
ans_p = capa_malloc(nq+2,1); |
tries_p = capa_malloc(3*nq+2,1); /* space and \0 */ |
tries_p = capa_malloc(3*nq+3,1); /* space and \0 */ |
} else { |
} else { |
ans_p = capa_malloc(length+1,1); |
ans_p = capa_malloc(length+2,1); |
tries_p = capa_malloc(3*length+2,1); /* space and \0 */ |
tries_p = capa_malloc(3*length+3,1); /* space and \0 */ |
} |
} |
sprintf(fmtbuf, "%%%dc",length); |
sprintf(fmtbuf, "%%%dc",length); |
sscanf(oneline + MAX_STUDENT_NUMBER+1,fmtbuf,ans_p); |
sscanf(oneline + MAX_STUDENT_NUMBER+1,fmtbuf,ans_p); |
|
ans_p[length]='\0'; |
sprintf(fmtbuf, "%%%dc",(3*length-1)); |
sprintf(fmtbuf, "%%%dc",(3*length-1)); |
sscanf(oneline + MAX_STUDENT_NUMBER+1+length+1,fmtbuf,tries_p); |
sscanf(oneline + MAX_STUDENT_NUMBER+1+length+1,fmtbuf,tries_p); |
|
tries_p[3*length-1]='\0'; |
entry->answers = ans_p; |
entry->answers = ans_p; |
entry->tries = tries_p; |
entry->tries = tries_p; |
entry->e_probs = nq; |
entry->e_probs = nq; |
Line 2122 extern int Symb_count;
|
Line 2142 extern int Symb_count;
|
extern int first_run; |
extern int first_run; |
extern int Stop_Parser; |
extern int Stop_Parser; |
extern void (*Status_Func)(); |
extern void (*Status_Func)(); |
|
#ifdef TTH |
|
extern void tth_restart(); |
|
extern char* tth_err; |
|
#endif /*TTH*/ |
long seed1, seed2; |
long seed1, seed2; |
T_student a_student; |
T_student a_student; |
char *class, *classname, warn_msg[WARN_MSG_LENGTH]; |
char *class, *classname, warn_msg[WARN_MSG_LENGTH]; |
Line 2150 extern void (*Status_Func)();
|
Line 2174 extern void (*Status_Func)();
|
} |
} |
u_getunit(fp); |
u_getunit(fp); |
fclose(fp); |
fclose(fp); |
|
#ifdef TTH |
|
if(tth_err) { free(tth_err); tth_err=NULL; } |
|
tth_restart(); |
|
#endif /*TTH*/ |
strncpy(Parse_name,a_student.s_nm,MAX_NAME_CHAR+1); |
strncpy(Parse_name,a_student.s_nm,MAX_NAME_CHAR+1); |
strncpy(Parse_student_number,student_number,MAX_STUDENT_NUMBER+1); |
strncpy(Parse_student_number,student_number,MAX_STUDENT_NUMBER+1); |
Parse_section = a_student.s_sec; |
Parse_section = a_student.s_sec; |
Line 2610 answers_string(mode, p)int mode;Problem_
|
Line 2638 answers_string(mode, p)int mode;Problem_
|
str_bb = format_toTeX(lower); |
str_bb = format_toTeX(lower); |
} else { /* answer could be string, choice */ |
} else { /* answer could be string, choice */ |
str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1); |
str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1); |
if (p->ans_type == ANSWER_IS_FORMULA || 1) |
if (p->verbatim == DO_VERBATIM) |
sprintf(str_bb,"\\begin{verbatim}%s\\end{verbatim}",lower); |
sprintf(str_bb,"\\begin{verbatim}%s\\end{verbatim}",lower); |
else |
else |
strcpy(str_bb,lower); |
strcpy(str_bb,lower); |
Line 2865 answers_string(mode, p)int mode;Problem_
|
Line 2893 answers_string(mode, p)int mode;Problem_
|
|
|
/* <== This routine checks user input string *ans against correct answer *s ==> */ |
/* <== This routine checks user input string *ans against correct answer *s ==> */ |
int |
int |
capa_check_ans(ai,ans) AnswerInfo_t *ai; char *ans; |
capa_check_ans(ai,ans, error) AnswerInfo_t *ai; char *ans; char **error; |
{ |
{ |
int t; /* ans_type */ |
int t; /* ans_type */ |
char *s; /* ans_str */ |
char *s; /* ans_str */ |
Line 2908 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
Line 2936 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
outcome = split_num_unit(ans,&n_part,num_str,unit_str); |
outcome = split_num_unit(ans,&n_part,num_str,unit_str); |
if( outcome > 1 ) { /* with both num and unit parts or only unit part */ |
if( outcome > 1 ) { /* with both num and unit parts or only unit part */ |
if( u_p != NULL ) { |
if( u_p != NULL ) { |
result = check_correct_unit(unit_str,u_p,&scale); |
if (UNIT_FAIL == (result = check_correct_unit(unit_str,u_p,&scale))) { |
|
*error=strsave(unit_str); |
|
} |
} else { /* what to do when no unit is specified but student entered a unit? */ |
} else { /* what to do when no unit is specified but student entered a unit? */ |
result = UNIT_NOTNEEDED; |
result = UNIT_NOTNEEDED; |
|
*error=strsave(unit_str); |
} |
} |
} else { |
} else { |
if( u_p != NULL ) { |
if( u_p != NULL ) { |
Line 2925 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
Line 2956 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
} |
} |
given = n_part * scale; /* convert the given answer into proper scale for units */ |
given = n_part * scale; /* convert the given answer into proper scale for units */ |
sig = calc_sig( num_str ); |
sig = calc_sig( num_str ); |
if( (sig < sl) || (sig > su) ) { |
if( ((sig < sl ) || (sig > su )) && (sig!=0)) { |
result = SIG_FAIL; |
result = SIG_FAIL; |
|
*error=capa_malloc(1,ANSWER_STRING_LENG); |
|
sprintf(*error,"%d",sig); |
} else { |
} else { |
switch( tt ) { /* tolerence type */ |
switch( tt ) { /* tolerence type */ |
case TOL_ABSOLUTE: |
case TOL_ABSOLUTE: |
Line 2968 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
Line 3001 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
} /* end sig check */ |
} /* end sig check */ |
} /* end if unit check */ |
} /* end if unit check */ |
} else { /* user entered alphabets, but no number */ |
} else { /* user entered alphabets, but no number */ |
result = INCORRECT; |
result = WANTED_NUMERIC; |
} |
} |
} |
} |
break; |
break; |
Line 2998 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
Line 3031 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
result = check_formula_ans(s,ans,ai->ans_id_list,ai->ans_pts_list,tt,to); |
result = check_formula_ans(s,ans,ai->ans_id_list,ai->ans_pts_list,tt,to); |
break; |
break; |
case ANSWER_IS_EXTERNAL: /* Not yet implemented */ |
case ANSWER_IS_EXTERNAL: /* Not yet implemented */ |
|
|
|
|
|
|
break; |
break; |
} |
} |
return (result); |
return (result); |
Line 3020 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
Line 3056 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
|
|
|
|
int |
int |
capa_check_answer(p, answer) Problem_t *p; char *answer; |
capa_check_answer(p, answer, error) Problem_t *p; char *answer; char **error; |
{ |
{ |
int type; |
int type; |
char *correct; |
char *correct; |
Line 3061 capa_check_answer(p, answer) Problem_t *
|
Line 3097 capa_check_answer(p, answer) Problem_t *
|
outcome = split_num_unit(answer,&n_part,input,unit_str); |
outcome = split_num_unit(answer,&n_part,input,unit_str); |
if( outcome > 1 ) { /* with both num and unit parts or only unit part */ |
if( outcome > 1 ) { /* with both num and unit parts or only unit part */ |
if( p->ans_unit != NULL ) { |
if( p->ans_unit != NULL ) { |
result = check_correct_unit(unit_str,p->ans_unit,&scale); |
if ( UNIT_FAIL == ( result = check_correct_unit(unit_str,p->ans_unit,&scale) ) ) { |
|
*error=strsave(unit_str); |
|
} |
} else { /* what to do when no unit is specified but student entered a unit? */ |
} else { /* what to do when no unit is specified but student entered a unit? */ |
result = UNIT_NOTNEEDED; |
result = UNIT_NOTNEEDED; |
|
*error=strsave(unit_str); |
} |
} |
} else { |
} else { |
if( p->ans_unit != NULL ) { |
if( p->ans_unit != NULL ) { |
Line 3079 capa_check_answer(p, answer) Problem_t *
|
Line 3117 capa_check_answer(p, answer) Problem_t *
|
} |
} |
given = n_part * scale; /* convert the given answer into proper scale for units */ |
given = n_part * scale; /* convert the given answer into proper scale for units */ |
sig = calc_sig( input ); |
sig = calc_sig( input ); |
if( (sig < sig_l) || (sig > sig_u) ) { |
if( ((sig < sig_l) || (sig > sig_u)) && (sig!=0)) { |
result = SIG_FAIL; |
result = SIG_FAIL; |
|
*error=capa_malloc(1,ANSWER_STRING_LENG); |
|
sprintf(*error,"%d",sig); |
} else { |
} else { |
switch( tol_type ) { |
switch( tol_type ) { |
case TOL_ABSOLUTE: |
case TOL_ABSOLUTE: |
Line 3122 capa_check_answer(p, answer) Problem_t *
|
Line 3162 capa_check_answer(p, answer) Problem_t *
|
} /* end sig check */ |
} /* end sig check */ |
} /* end if unit check */ |
} /* end if unit check */ |
} else { /* user entered alphabet, but no number */ |
} else { /* user entered alphabet, but no number */ |
result = INCORRECT; |
result = WANTED_NUMERIC; |
} |
} |
} |
} |
break; |
break; |
Line 3151 capa_check_answer(p, answer) Problem_t *
|
Line 3191 capa_check_answer(p, answer) Problem_t *
|
result = check_formula_ans(correct,answer,p->id_list,p->pts_list,tol_type,tol); |
result = check_formula_ans(correct,answer,p->id_list,p->pts_list,tol_type,tol); |
break; |
break; |
case ANSWER_IS_EXTERNAL: /* not yet implemented */ |
case ANSWER_IS_EXTERNAL: /* not yet implemented */ |
|
/* we assume the external program is called through popen() */ |
|
/* and the result will be given back as 0 or 1 to indicate the */ |
|
/* given answer is correct or not */ |
|
/* arguments are given to the program as */ |
|
|
break; |
break; |
|
|
} |
} |
Line 3302 int tol_type;double tol;char *lower;char
|
Line 3347 int tol_type;double tol;char *lower;char
|
/* New check answers routine checks the /AND and /OR group of answers */ |
/* New check answers routine checks the /AND and /OR group of answers */ |
/* use array of char pointers char **a */ |
/* use array of char pointers char **a */ |
int |
int |
capa_check_answers(p,answers,cnt) Problem_t *p; char **answers; int cnt; |
capa_check_answers(p,answers,cnt,error) |
|
Problem_t *p; char **answers; int cnt; char **error; |
{ |
{ |
AnswerInfo_t *ai; |
AnswerInfo_t *ai; |
int ii, done, result; |
int ii, done, result; |
int *outcomes; |
int *outcomes; |
|
char **errormsg; |
|
|
|
errormsg=(char**)capa_malloc(cnt,sizeof(char*)); |
if(p->ans_op == ANS_AND) { /* ans /and ans */ |
if(p->ans_op == ANS_AND) { /* ans /and ans */ |
if( (cnt != p->ans_cnt) ) { return (ANS_CNT_NOT_MATCH); } |
if( (cnt != p->ans_cnt) ) { return (ANS_CNT_NOT_MATCH); } |
if( cnt == 1 ) { return (capa_check_answer(p, answers[0])); } /* there is only one answer */ |
if( cnt == 1 ) { return (capa_check_answer(p, answers[0], error)); } /* there is only one answer */ |
outcomes = (int *)capa_malloc(sizeof(int),cnt); |
outcomes = (int *)capa_malloc(sizeof(int),cnt); |
for(ii=0;ii<cnt;ii++) outcomes[ii]=0; /* initialize the outcomes array */ |
for(ii=0;ii<cnt;ii++) outcomes[ii]=0; /* initialize the outcomes array */ |
outcomes[0] = capa_check_answer(p, answers[0]); |
outcomes[0] = capa_check_answer(p, answers[0], &errormsg[0]); |
for(ii=1, ai = p->ans_list; ai; ii++,ai = ai->ans_next ) { |
for(ii=1, ai = p->ans_list; ai; ii++,ai = ai->ans_next ) { |
outcomes[ii] = capa_check_ans(ai,answers[ii]); |
outcomes[ii] = capa_check_ans(ai,answers[ii],&(errormsg[ii])); |
} |
} |
done = ii = 0; |
done = ii = 0; |
result = 0; |
result = 0; |
Line 3324 capa_check_answers(p,answers,cnt) Proble
|
Line 3372 capa_check_answers(p,answers,cnt) Proble
|
(outcomes[ii] == NO_UNIT) || |
(outcomes[ii] == NO_UNIT) || |
(outcomes[ii] == UNIT_NOTNEEDED) ) { |
(outcomes[ii] == UNIT_NOTNEEDED) ) { |
result = outcomes[ii]; |
result = outcomes[ii]; |
|
if (result != NO_UNIT) { *error=strsave(errormsg[ii]); } |
done = 1; |
done = 1; |
} |
} |
ii++; |
ii++; |
if(ii==cnt) done = 1; |
if(ii==cnt) done = 1; |
} |
} |
|
if( result == 0 ) { /* check if any of the outcome has failed to be a numeric */ |
|
done = ii = 0; |
|
while( !done ) { |
|
if( outcomes[ii] == WANTED_NUMERIC ) { |
|
result = outcomes[ii]; |
|
done = 1; |
|
} |
|
ii++; |
|
if(ii==cnt) done = 1; |
|
} |
|
} |
if( result == 0 ) { /* check if any of the outcome has failed on sig figs */ |
if( result == 0 ) { /* check if any of the outcome has failed on sig figs */ |
done = ii = 0; |
done = ii = 0; |
while( !done ) { |
while( !done ) { |
if( outcomes[ii] == SIG_FAIL ) { |
if( outcomes[ii] == SIG_FAIL ) { |
result = outcomes[ii]; |
result = outcomes[ii]; |
|
*error = strsave(errormsg[ii]); |
done = 1; |
done = 1; |
} |
} |
ii++; |
ii++; |
Line 3351 capa_check_answers(p,answers,cnt) Proble
|
Line 3412 capa_check_answers(p,answers,cnt) Proble
|
if(ii==cnt) done = 1; |
if(ii==cnt) done = 1; |
} |
} |
} |
} |
|
for (ii=0;ii<cnt;ii++) { |
|
if( (outcomes[ii] == UNIT_FAIL) || |
|
(outcomes[ii] == SIG_FAIL) || |
|
(outcomes[ii] == UNIT_NOTNEEDED) ) { |
|
capa_mfree(errormsg[ii]); |
|
} |
|
} |
|
capa_mfree((char *)errormsg); |
capa_mfree((char *)outcomes); |
capa_mfree((char *)outcomes); |
if( result == 0 ) { |
if( result == 0 ) { |
result = APPROX_ANS; /* all answers are correct */ |
result = APPROX_ANS; /* all answers are correct */ |
} |
} |
|
|
} else { /* should be ANS_OR , user answer count should always be 1 */ |
} else { /* should be ANS_OR , user answer count should always be 1 */ |
if( cnt != 1 ) { return (ANS_CNT_NOT_MATCH); } |
if( cnt != 1 ) { return (ANS_CNT_NOT_MATCH); } |
if( p->ans_cnt == 1 ) { return (capa_check_answer(p, answers[0])); } |
if( p->ans_cnt == 1 ) { return (capa_check_answer(p, answers[0], error)); } |
result = capa_check_answer(p, answers[0]); |
result = capa_check_answer(p, answers[0], error); |
ii = 1; ai = p->ans_list; |
ii = 1; ai = p->ans_list; |
while( (ii<p->ans_cnt) && ( (result != EXACT_ANS) && (result != APPROX_ANS) ) ) { |
while( (ii<p->ans_cnt) && ( (result != EXACT_ANS) && (result != APPROX_ANS) ) ) { |
result = capa_check_ans(ai,answers[0]); |
if((ii!=1)&&((result==UNIT_FAIL)||(result==SIG_FAIL)||(result==UNIT_NOTNEEDED))) { |
ai = ai->ans_next; ii++; |
capa_mfree((char*)error); |
|
} |
|
result = capa_check_ans(ai,answers[0],error); |
|
ai = ai->ans_next; ii++; |
} |
} |
} |
} |
return (result); |
return (result); |