version 1.1.1.1, 1999/09/28 21:26:21
|
version 1.27, 2005/12/20 19:59:57
|
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 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 |
|
General Public License for more details. |
|
|
|
You should have received a copy of the GNU 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. |
|
|
|
As a special exception, you have permission to link this program |
|
with the TtH/TtM library and distribute executables, as long as you |
|
follow the requirements of the GNU GPL in regard to all of the |
|
software in the executable aside from TtH/TtM. |
|
*/ |
|
|
/* =||>|===================== capaCommon.c =====================|<||= */ |
/* =||>|===================== capaCommon.c =====================|<||= */ |
/* created 1994 by Isaac Tsai */ |
/* created 1994 by Isaac Tsai */ |
/* 1994, 1995, 1996, 1997, 1998, 1999 copyrighted by Isaac Tsai */ |
|
/* TODO: restructure capa_check_ans*() calls into one */ |
/* TODO: restructure capa_check_ans*() calls into one */ |
/* =||>|===================== capaCommon.c =====================|<||= */ |
/* =||>|===================== capaCommon.c =====================|<||= */ |
#include <ctype.h> |
#include <ctype.h> |
Line 25 int yyparse();
|
Line 48 int yyparse();
|
extern FILE *yyin; |
extern FILE *yyin; |
extern void yyrestart(); |
extern void yyrestart(); |
|
|
|
extern FILE *dfp; |
|
|
/*----------------------------------------------------------*/ |
/*----------------------------------------------------------*/ |
/* RETURN: -1 file error */ |
/* RETURN: -1 file error */ |
/* 0 success */ |
/* 0 success */ |
Line 46 capa_excuse(int set,int prob,int secti
|
Line 71 capa_excuse(int set,int prob,int secti
|
/* Calculate parameters */ |
/* Calculate parameters */ |
if (capa_get_header(&header,set)) return (-1); |
if (capa_get_header(&header,set)) return (-1); |
sscanf(header.num_questions,"%d", &nq); |
sscanf(header.num_questions,"%d", &nq); |
capa_mfree(header.weight); |
|
capa_mfree(header.partial_credit); |
|
|
|
if( ( prob > nq ) || (section < 0 ) || (section > MAX_SECTION_COUNT) ) return (-1); |
if( ( prob > nq ) || (section < 0 ) || (section > MAX_SECTION_COUNT) ) return (-1); |
num_students= 0; |
num_students= 0; |
Line 57 capa_excuse(int set,int prob,int secti
|
Line 80 capa_excuse(int set,int prob,int secti
|
offset = capa_get_entry(&entry,tmp_number,set); |
offset = capa_get_entry(&entry,tmp_number,set); |
if(offset < 0 ) offset = -offset; |
if(offset < 0 ) offset = -offset; |
switch(entry.answers[prob-1]) { |
switch(entry.answers[prob-1]) { |
|
case '0': |
case '-': entry.answers[prob-1] = 'E'; break; |
case '-': entry.answers[prob-1] = 'E'; break; |
case 'N': entry.answers[prob-1] = 'E'; break; |
case 'N': entry.answers[prob-1] = 'E'; break; |
case 'n': entry.answers[prob-1] = 'e'; break; |
case 'n': entry.answers[prob-1] = 'e'; break; |
|
case '1': case '2': case '3': case '4': case '5': |
|
case '6': case '7': case '8': case '9': |
|
if (entry.answers[prob-1] < header.weight[prob-1]) { |
|
entry.answers[prob-1] = 'E'; |
|
} |
|
break; |
default : break; |
default : break; |
} |
} |
capa_set_entry(&entry,tmp_number,set,offset); |
capa_set_entry(&entry,tmp_number,set,offset); |
capa_mfree(entry.answers); entry.answers = NULL; |
capa_mfree(entry.answers); entry.answers = NULL; |
capa_mfree(entry.tries); entry.tries = NULL; |
capa_mfree(entry.tries); entry.tries = NULL; |
} |
} |
|
capa_mfree(header.weight); |
|
capa_mfree(header.partial_credit); |
free_students(student_p); |
free_students(student_p); |
return (0); |
return (0); |
} |
} |
Line 562 int set;
|
Line 594 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 578 int set;
|
Line 610 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 1350 int capa_check_option(int option,int set
|
Line 1384 int capa_check_option(int option,int set
|
} |
} |
|
|
/*----------------------------------------------------------*/ |
/*----------------------------------------------------------*/ |
/* INPUT: set the X in logX.db */ |
/* INPUT: time the current time */ |
|
/* datetime the datetime string to compare */ |
/* OUTPUT: none */ |
/* OUTPUT: none */ |
/* */ |
/* */ |
/* RETURN: -1 file error */ |
/* RETURN: -1 time is earlier then datetime */ |
/* 0 no login */ |
/* 1 time is later than datetime */ |
/* >0 number of logins in that logX.db file */ |
|
/*----------------------------------------------------------*/ |
/*----------------------------------------------------------*/ |
int |
int |
compare_datetime(time,datetime) |
compare_datetime(time,datetime) |
Line 1384 char *datetime;
|
Line 1418 char *datetime;
|
/* What if: [7,3] date_info */ |
/* What if: [7,3] date_info */ |
/* [3,7] date_info */ |
/* [3,7] date_info */ |
/* 4 date_info */ |
/* 4 date_info */ |
|
/* RETURN: -1 if not pass time */ |
|
/* 1 if pass time (or no time available */ |
int capa_check_date(int which,char *student_number, int section,int set) |
int capa_check_date(int which,char *student_number, int section,int set) |
{ |
{ |
int result; |
int result; |
Line 1414 void capa_get_due_date(char *date_str,T_
|
Line 1449 void capa_get_due_date(char *date_str,T_
|
if ((duration > 0) && (student_number!=NULL)) { |
if ((duration > 0) && (student_number!=NULL)) { |
if (capa_get_login_time(student_number,set,&logintime)==1) { |
if (capa_get_login_time(student_number,set,&logintime)==1) { |
duetime=logintime+duration; |
duetime=logintime+duration; |
due_time_tm=localtime(&duetime); |
if (compare_datetime(duetime,current->due_date)==-1) { |
sprintf(date_str,"%04d/%02d/%02d %02d:%02d",((due_time_tm->tm_year)+1900), |
due_time_tm=localtime(&duetime); |
due_time_tm->tm_mon+1,due_time_tm->tm_mday,due_time_tm->tm_hour, |
sprintf(date_str,"%04d/%02d/%02d %02d:%02d",((due_time_tm->tm_year)+1900), |
due_time_tm->tm_min); |
due_time_tm->tm_mon+1,due_time_tm->tm_mday,due_time_tm->tm_hour, |
|
due_time_tm->tm_min); |
|
} else { |
|
strncpy(date_str,current->due_date,DATE_BUFFER); |
|
} |
return; |
return; |
} |
} |
} |
} |
Line 2114 extern int Symb_count;
|
Line 2153 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 2142 extern void (*Status_Func)();
|
Line 2185 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 2407 check_input_usymb(u_symb)char *u_symb;
|
Line 2454 check_input_usymb(u_symb)char *u_symb;
|
/* num_p : the numerical part in string */ |
/* num_p : the numerical part in string */ |
/* unit_p : the unit string */ |
/* unit_p : the unit string */ |
/* num_p is used to calculate sig figs */ |
/* num_p is used to calculate sig figs */ |
/* return : 0 empty string */ |
/* return : -1 invalid string */ |
|
/* 0 empty string */ |
/* 1 number without units */ |
/* 1 number without units */ |
/* 2 empty number with units */ |
/* 2 empty number with units */ |
/* 3 number with units */ |
/* 3 number with units */ |
Line 2452 char *buf;double *num; char *num_p; char
|
Line 2500 char *buf;double *num; char *num_p; char
|
while( isspace(buf[idx]) ) { idx++; } |
while( isspace(buf[idx]) ) { idx++; } |
sscanf(num_str, "%lg", &result); /* put the numerical value into a double variable */ |
sscanf(num_str, "%lg", &result); /* put the numerical value into a double variable */ |
errcode = errcode | 1; |
errcode = errcode | 1; |
} else if( buf[idx] == 'x' || buf[idx] == 'X') { /* optional x or X part */ |
} else if( buf[idx] == 'x' || buf[idx] == 'X' || buf[idx] == '*') { /* optional x or X part */ |
idx++; /* skip x or X */ |
idx++; /* skip x or X */ |
while( isspace(buf[idx]) ) { idx++; } |
while( isspace(buf[idx]) ) { idx++; } |
|
|
e_part = 1.0; /* default power */ |
e_part = 1.0; /* default power */ |
base_str[b_idx] = 0; /* initialize base_str[] */ |
base_str[b_idx] = 0; /* initialize base_str[] */ |
while( isdigit(buf[idx]) || buf[idx] == '.' ) { /* should start with a digit or . */ |
if( buf[idx] == '1' && buf[idx+1] == '0') { |
|
base_str[b_idx++] = buf[idx++]; |
base_str[b_idx++] = buf[idx++]; |
base_str[b_idx++] = buf[idx++]; |
|
} else { |
|
return (-1); |
} |
} |
base_str[b_idx] = 0; /* terminate base_str[] */ |
base_str[b_idx] = 0; /* terminate base_str[] */ |
while( isspace(buf[idx]) ) { idx++; } /* skip over white spaces */ |
while( isspace(buf[idx]) ) { idx++; } /* skip over white spaces */ |
Line 2473 char *buf;double *num; char *num_p; char
|
Line 2524 char *buf;double *num; char *num_p; char
|
while( isspace(buf[idx]) ) { idx++; } |
while( isspace(buf[idx]) ) { idx++; } |
if( isdigit(buf[idx]) || buf[idx] == '+' || buf[idx] == '-' ) { |
if( isdigit(buf[idx]) || buf[idx] == '+' || buf[idx] == '-' ) { |
exp_str[e_idx] = 0; /* initialize exp_str[], again */ |
exp_str[e_idx] = 0; /* initialize exp_str[], again */ |
while( isdigit(buf[idx]) || buf[idx] == '.' || buf[idx] == '+' || buf[idx] == '-' ) { |
while( isdigit(buf[idx]) /*|| buf[idx] == '.'*/ || buf[idx] == '+' || buf[idx] == '-' ) { |
exp_str[e_idx++] = buf[idx++]; |
exp_str[e_idx++] = buf[idx++]; |
} |
} |
exp_str[e_idx] = 0; /* terminate exp_str[] */ |
exp_str[e_idx] = 0; /* terminate exp_str[] */ |
Line 2507 char *buf;double *num; char *num_p; char
|
Line 2558 char *buf;double *num; char *num_p; char
|
while( isspace(buf[idx]) ) { idx++; } |
while( isspace(buf[idx]) ) { idx++; } |
if( isdigit(buf[idx]) || buf[idx] == '+' || buf[idx] == '-' ) { |
if( isdigit(buf[idx]) || buf[idx] == '+' || buf[idx] == '-' ) { |
exp_str[e_idx] = 0; |
exp_str[e_idx] = 0; |
while( isdigit(buf[idx]) || buf[idx] == '.' || buf[idx] == '+' || buf[idx] == '-' ) { |
while( isdigit(buf[idx]) /*|| buf[idx] == '.'*/ || buf[idx] == '+' || buf[idx] == '-' ) { |
exp_str[e_idx++] = buf[idx++]; |
exp_str[e_idx++] = buf[idx++]; |
} |
} |
exp_str[e_idx] = 0; |
exp_str[e_idx] = 0; |
Line 2518 char *buf;double *num; char *num_p; char
|
Line 2569 char *buf;double *num; char *num_p; char
|
} |
} |
sscanf(exp_str, "%lg", &e_part); |
sscanf(exp_str, "%lg", &e_part); |
sscanf(num_str, "%lg", &n_part); |
sscanf(num_str, "%lg", &n_part); |
|
if( n_part != 10 ) { |
|
return (-1); |
|
} |
result = pow(n_part,e_part); |
result = pow(n_part,e_part); |
errcode = errcode | 1; |
errcode = errcode | 1; |
} else { /* number unit */ |
} else { /* number unit */ |
Line 2591 answers_string(mode, p)int mode;Problem_
|
Line 2645 answers_string(mode, p)int mode;Problem_
|
if(len_dd == 0 ) { /* no unit_str */ |
if(len_dd == 0 ) { /* no unit_str */ |
sprintf(ans_str," %s [%s,%s]\n\n", str_aa,str_bb,str_cc); |
sprintf(ans_str," %s [%s,%s]\n\n", str_aa,str_bb,str_cc); |
} else { |
} else { |
sprintf(ans_str," %s [%s,%s] $%s$\n\n", str_aa,str_bb,str_cc,p->unit_str); |
sprintf(ans_str," %s [%s,%s] $\\mathrm{%s}$\n\n", str_aa,str_bb,str_cc,p->unit_str); |
} |
} |
capa_mfree((char *)str_aa); |
capa_mfree((char *)str_aa); |
capa_mfree((char *)str_bb); |
capa_mfree((char *)str_bb); |
Line 2602 answers_string(mode, p)int mode;Problem_
|
Line 2656 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 2613 answers_string(mode, p)int mode;Problem_
|
Line 2667 answers_string(mode, p)int mode;Problem_
|
if(len_dd == 0 ) { /* no unit_str */ |
if(len_dd == 0 ) { /* no unit_str */ |
sprintf(ans_str," %s\n", str_bb); |
sprintf(ans_str," %s\n", str_bb); |
} else { |
} else { |
sprintf(ans_str," %s $%s$\n", str_bb,p->unit_str); |
sprintf(ans_str," %s $\\mathrm{%s}$\n", str_bb,p->unit_str); |
} |
} |
capa_mfree((char *)str_bb); |
capa_mfree((char *)str_bb); |
} |
} |
Line 2850 answers_string(mode, p)int mode;Problem_
|
Line 2904 answers_string(mode, p)int mode;Problem_
|
} |
} |
|
|
|
|
|
int check_for_unit_fail(int result) |
|
{ |
|
int ret; |
|
ret = (result == UNIT_FAIL || |
|
result == UNIT_IRRECONCIBLE || |
|
result == UNIT_INVALID_STUDENT3 || |
|
result == UNIT_INVALID_STUDENT2 || |
|
result == UNIT_INVALID_STUDENT1); |
|
return ret; |
|
} |
|
|
/* ------------------------------ called from capalogin */ |
/* ------------------------------ called from capalogin */ |
/* impose stronger checking on the user input string *answer */ |
/* impose stronger checking on the user input string *answer */ |
Line 2857 answers_string(mode, p)int mode;Problem_
|
Line 2921 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 2870 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
Line 2934 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
char *us; /* ans_unit_str */ |
char *us; /* ans_unit_str */ |
Unit_t *u_p; /* ans_unit */ |
Unit_t *u_p; /* ans_unit */ |
int input_len, all_alphabet = 1, idx, ii, type; |
int input_len, all_alphabet = 1, idx, ii, type; |
int outcome, result = INCORRECT; |
int outcome=-1, result = INCORRECT; |
int sig, corr_len; |
int sig, corr_len; |
int choice[ANSWER_STRING_LENG]; |
int choice[ANSWER_STRING_LENG]; |
char num_str[ANSWER_STRING_LENG], unit_str[ANSWER_STRING_LENG]; |
char num_str[ANSWER_STRING_LENG], unit_str[ANSWER_STRING_LENG]; |
char fmted[ANSWER_STRING_LENG], correct[ANSWER_STRING_LENG], answer[ANSWER_STRING_LENG]; |
char fmted[ANSWER_STRING_LENG], correctans[ANSWER_STRING_LENG], answer[ANSWER_STRING_LENG]; |
double n_part; |
double n_part; |
double given, target, ratio, fmted_target, target_u, target_l, scale=1.0; |
double given, target, ratio, fmted_target, target_u, target_l, scale=1.0; |
double delta; |
double delta; |
Line 2896 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
Line 2960 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
all_alphabet = 0; |
all_alphabet = 0; |
} |
} |
} |
} |
if( !all_alphabet ) { /* answer string is not all alphabets */ |
if( !all_alphabet ) { |
outcome = split_num_unit(ans,&n_part,num_str,unit_str); |
outcome = split_num_unit(ans,&n_part,num_str,unit_str); |
|
} |
|
if( outcome > 0 ) { |
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); |
result = check_correct_unit(unit_str,u_p,&scale); |
|
if (check_for_unit_fail(result)) { |
|
*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 ) { |
result = NO_UNIT; |
result = NO_UNIT; |
} |
} |
} |
} |
if( (result != NO_UNIT) && (result != UNIT_FAIL) && ( result != UNIT_NOTNEEDED) ) { |
if( (result != NO_UNIT) && (!check_for_unit_fail(result)) && ( result != UNIT_NOTNEEDED) ) { |
if( t == ANSWER_IS_FLOAT ) { |
if( t == ANSWER_IS_FLOAT ) { |
target = (double)atof(s); /* real number */ |
target = (double)atof(s); /* real number */ |
} else { |
} else { |
Line 2917 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
Line 2987 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 2960 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
Line 3032 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 2968 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
Line 3040 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
{ |
{ |
corr_len = strlen(s); input_len = strlen(ans); |
corr_len = strlen(s); input_len = strlen(ans); |
if( corr_len == input_len ) { |
if( corr_len == input_len ) { |
for(idx=0;idx<ANSWER_STRING_LENG;idx++) choice[idx] = 0; |
for(idx=0;idx<ANSWER_STRING_LENG;idx++) { |
|
choice[idx] = 0;correctans[idx] = 0; |
|
} |
result = EXACT_ANS; |
result = EXACT_ANS; |
for(ii=0;ii<corr_len; ii++) { |
for(ii=0;ii<corr_len; ii++) { |
idx = toupper(correct[ii]) - 'A'; choice[idx] = 1; |
idx = toupper(s[ii]) - 'A'; choice[idx] = 1; |
} |
} |
for(ii=0;ii<input_len;ii++) { |
for(ii=0;ii<input_len;ii++) { |
idx = toupper(answer[ii]) - 'A'; |
idx = toupper(ans[ii]) - 'A'; correctans[idx] = 1; |
if(choice[idx] != 1 ) result = INCORRECT; |
} |
|
for(ii=0;ii<ANSWER_STRING_LENG;ii++) { |
|
if(choice[ii] != correctans[ii] ) result = INCORRECT; |
} |
} |
} else { result = INCORRECT; } |
} else { result = INCORRECT; } |
break; |
break; |
Line 2990 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
Line 3066 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 3012 capa_check_ans(ai,ans) AnswerInfo_t *ai
|
Line 3091 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 3022 capa_check_answer(p, answer) Problem_t *
|
Line 3101 capa_check_answer(p, answer) Problem_t *
|
int sig_l; |
int sig_l; |
int sig_u; |
int sig_u; |
char *fmt; |
char *fmt; |
int choice[ANSWER_STRING_LENG], ii, idx, corr_len, input_len; |
int choice[ANSWER_STRING_LENG], correctans[ANSWER_STRING_LENG]; |
int result = INCORRECT, sig, outcome, all_alphabet; |
int ii, idx, corr_len, input_len; |
|
int result = INCORRECT, sig, outcome=-1, all_alphabet; |
char fmted[FORMAT_STRING_LENG]; |
char fmted[FORMAT_STRING_LENG]; |
double given, target, ratio, fmted_target, target_u, target_l, scale=1.0; |
double given, target, ratio, fmted_target, target_u, target_l, scale=1.0; |
double delta; |
double delta; |
Line 3037 capa_check_answer(p, answer) Problem_t *
|
Line 3117 capa_check_answer(p, answer) Problem_t *
|
fmt = p->ans_fmt; |
fmt = p->ans_fmt; |
calc_type = p->calc; |
calc_type = p->calc; |
unit_str[0]=0; |
unit_str[0]=0; |
|
|
switch(type) { |
switch(type) { |
case ANSWER_IS_INTEGER: |
case ANSWER_IS_INTEGER: |
case ANSWER_IS_FLOAT: |
case ANSWER_IS_FLOAT: |
Line 3051 capa_check_answer(p, answer) Problem_t *
|
Line 3131 capa_check_answer(p, answer) Problem_t *
|
} |
} |
if( !all_alphabet ) { |
if( !all_alphabet ) { |
outcome = split_num_unit(answer,&n_part,input,unit_str); |
outcome = split_num_unit(answer,&n_part,input,unit_str); |
|
} |
|
if( outcome > 0 ) { |
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); |
result = check_correct_unit(unit_str,p->ans_unit,&scale); |
|
if (check_for_unit_fail(result)) { |
|
*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 ) { |
result = NO_UNIT; |
result = NO_UNIT; |
} |
} |
} |
} |
if( (result != NO_UNIT) && (result != UNIT_FAIL) && ( result != UNIT_NOTNEEDED) ) { |
if( (result != NO_UNIT) && (!check_for_unit_fail(result)) && ( result != UNIT_NOTNEEDED) ) { |
if( type == ANSWER_IS_FLOAT ) { |
if( type == ANSWER_IS_FLOAT ) { |
target = (double)atof(correct); /* real number */ |
target = (double)atof(correct); /* real number */ |
} else { |
} else { |
Line 3071 capa_check_answer(p, answer) Problem_t *
|
Line 3156 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 3114 capa_check_answer(p, answer) Problem_t *
|
Line 3201 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 3122 capa_check_answer(p, answer) Problem_t *
|
Line 3209 capa_check_answer(p, answer) Problem_t *
|
{ |
{ |
corr_len = strlen(correct); input_len = strlen(answer); |
corr_len = strlen(correct); input_len = strlen(answer); |
if( corr_len == input_len ) { |
if( corr_len == input_len ) { |
for(ii=0;ii<ANSWER_STRING_LENG;ii++) choice[ii] = 0; result = EXACT_ANS; |
for(idx=0;idx<ANSWER_STRING_LENG;idx++) { |
|
choice[idx] = 0;correctans[idx] = 0; |
|
} |
|
result = EXACT_ANS; |
for(ii=0;ii<corr_len; ii++) { |
for(ii=0;ii<corr_len; ii++) { |
idx = toupper(correct[ii]) - 'A'; choice[idx] = 1; |
idx = toupper(correct[ii]) - 'A'; choice[idx] = 1; |
} |
} |
for(ii=0;ii<input_len;ii++) { |
for(ii=0;ii<input_len;ii++) { |
idx = toupper(answer[ii]) - 'A'; |
idx = toupper(answer[ii]) - 'A'; correctans[idx] = 1; |
if(choice[idx] != 1 ) result = INCORRECT; |
} |
|
for(ii=0;ii<ANSWER_STRING_LENG;ii++) { |
|
if(choice[ii] != correctans[ii] ) result = INCORRECT; |
} |
} |
} else { result = INCORRECT; } |
} else { result = INCORRECT; } |
break; |
break; |
Line 3143 capa_check_answer(p, answer) Problem_t *
|
Line 3235 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 */ |
|
/* before running the program, check its existance first */ |
|
/* should we specify a time out period in capa.config file? */ |
|
/* set up a timer for this purpose */ |
|
/* FILE *popen (const char *command,const char *type ); */ |
|
|
break; |
break; |
|
|
} |
} |
return (result); |
return (result); |
} |
} |
|
|
/* ----------------------------------------------------------------------------------- */ |
int check_tol (formula_val,tol_type,tol) |
|
double formula_val;int tol_type;double tol; |
|
{ |
|
double diff; |
|
int outcome=APPROX_ANS; |
|
if( tol_type == TOL_ABSOLUTE ) { |
|
diff = tol - formula_val; |
|
if( diff < 0.0 ) { |
|
outcome = INCORRECT; |
|
} |
|
} else { |
|
diff = fabs(1.0 - formula_val) * 100.0 ; |
|
if( diff > tol ) { |
|
outcome = INCORRECT; |
|
} |
|
} |
|
return outcome; |
|
} |
|
|
|
/* -------------------------------------------------------------------------- */ |
/* assumming the formula is *fml_str and the student input is *input_str */ |
/* assumming the formula is *fml_str and the student input is *input_str */ |
/* according to the type of tolerance, we form the final formula as */ |
/* according to the type of tolerance, we form the final formula as */ |
/* absolute tolerance: (*fml_str) - (*input_str) */ |
/* absolute tolerance: (*fml_str) - (*input_str) */ |
Line 3161 char *fml_str;char *input_str;char *var_
|
Line 3281 char *fml_str;char *input_str;char *var_
|
char *check_fml_str; |
char *check_fml_str; |
int f_len, i_len, outcome, error_code; |
int f_len, i_len, outcome, error_code; |
PointsList_t *pt, *next; |
PointsList_t *pt, *next; |
double formula_val, diff; |
double formula_val; |
|
|
f_len = strlen(fml_str); |
f_len = strlen(fml_str); |
i_len = strlen(input_str); |
i_len = strlen(input_str); |
Line 3173 char *fml_str;char *input_str;char *var_
|
Line 3293 char *fml_str;char *input_str;char *var_
|
sprintf(check_fml_str,"(%s) / (%s)",input_str,fml_str); |
sprintf(check_fml_str,"(%s) / (%s)",input_str,fml_str); |
} |
} |
outcome = APPROX_ANS; |
outcome = APPROX_ANS; |
|
if( pts_list==NULL ) { |
|
error_code = f_eval_formula(&formula_val,check_fml_str, var_list, NULL); |
|
if( ! error_code ) { |
|
outcome = check_tol(formula_val,tol_type,tol); |
|
} else { |
|
outcome = BAD_FORMULA; |
|
} |
|
} |
|
|
for(pt= pts_list; pt!=NULL ; pt=next) { |
for(pt= pts_list; pt!=NULL ; pt=next) { |
next=pt->pts_next; |
next=pt->pts_next; |
error_code = f_eval_formula(&formula_val,check_fml_str, var_list, pt->pts_str); |
error_code = f_eval_formula(&formula_val,check_fml_str, var_list, pt->pts_str); |
if( ! error_code ) { |
if( ! error_code ) { |
if( tol_type == TOL_ABSOLUTE ) { |
outcome = check_tol(formula_val,tol_type,tol); |
diff = tol - formula_val; |
|
if( diff < 0.0 ) { |
|
outcome = INCORRECT; |
|
} |
|
} else { |
|
diff = abs(1.0 - formula_val) * 100.0 ; |
|
if( diff < tol ) { |
|
outcome = INCORRECT; |
|
} |
|
} |
|
} else { |
} else { |
outcome = BAD_FORMULA; |
outcome = BAD_FORMULA; |
break; |
break; |
Line 3294 int tol_type;double tol;char *lower;char
|
Line 3413 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]); |
|
#ifdef COMMON_DBUG |
|
printf("CAPA_CHECK_ANSWER(%s,%s):: outcome[0]=%d\n", |
|
p->answer,answers[0],outcomes[0]); |
|
#endif |
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])); |
|
#ifdef COMMON_DBUG |
|
printf("CAPA_CHECK_ANS(%s,%s): outcome[%d]=%d\n", ai->ans_str,answers[ii],ii,outcomes[ii]); |
|
#endif |
} |
} |
done = ii = 0; |
done = ii = 0; |
result = 0; |
result = 0; |
while( !done ) { /* check if any of the outcome has failed on units */ |
while( !done ) { /* check if any of the outcome has failed on units */ |
if( (outcomes[ii] == UNIT_FAIL) || |
if( (check_for_unit_fail(outcomes[ii])) || |
(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 on sig figs */ |
if( result == 0 ) { |
|
/* check if any of the outcome has failed to be a numeric |
|
or was a malformed equation */ |
|
done = ii = 0; |
|
while( !done ) { |
|
if( outcomes[ii] == WANTED_NUMERIC || outcomes[ii] == BAD_FORMULA ) { |
|
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*/ |
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 3343 capa_check_answers(p,answers,cnt) Proble
|
Line 3487 capa_check_answers(p,answers,cnt) Proble
|
if(ii==cnt) done = 1; |
if(ii==cnt) done = 1; |
} |
} |
} |
} |
|
for (ii=0;ii<cnt;ii++) { |
|
if( (check_for_unit_fail(outcomes[ii])) || |
|
(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)&&((check_for_unit_fail(result))||(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); |
Line 3451 char *key_word;char *value;
|
Line 3607 char *key_word;char *value;
|
} |
} |
} |
} |
if (c=='\n') found=1; |
if (c=='\n') found=1; |
if (((char)c)==((char)EOF)) break; |
if (((char)c)==((char)EOF)) {failed=1;break;} |
} |
} |
} |
} |
} while (!done && !failed); |
} while (!done && !failed); |
Line 3459 char *key_word;char *value;
|
Line 3615 char *key_word;char *value;
|
fclose(fp); |
fclose(fp); |
|
|
if (done) { |
if (done) { |
|
trim_response_ws(right); /*get rid of leading and trailing spaces*/ |
for(i=0,j=0;i<(strlen(right)+1);i++) { |
for(i=0,j=0;i<(strlen(right)+1);i++) { |
value[j]='\0'; |
value[j]='\0'; |
if (right[i] == '\\' && (i < (strlen(right))) ) { |
if (right[i] == '\\' && (i < (strlen(right))) ) { |