Version19.9

This commit is contained in:
Antonio Cañas Vargas 2019-09-23 01:48:28 +02:00
parent 1f02939f6c
commit f946925237
7 changed files with 329 additions and 154 deletions

View File

@ -661,13 +661,11 @@ CREATE TABLE IF NOT EXISTS mch_players (
-- Table mch_results: stores the current match results -- Table mch_results: stores the current match results
-- --
CREATE TABLE IF NOT EXISTS mch_results ( CREATE TABLE IF NOT EXISTS mch_results (
MchResCod INT NOT NULL AUTO_INCREMENT,
MchCod INT NOT NULL, MchCod INT NOT NULL,
UsrCod INT NOT NULL, UsrCod INT NOT NULL,
NumQsts INT NOT NULL DEFAULT 0, NumQsts INT NOT NULL DEFAULT 0,
NumQstsNotBlank INT NOT NULL DEFAULT 0, NumQstsNotBlank INT NOT NULL DEFAULT 0,
Score DOUBLE PRECISION NOT NULL DEFAULT 0, Score DOUBLE PRECISION NOT NULL DEFAULT 0,
UNIQUE INDEX(MchResCod),
UNIQUE INDEX(MchCod,UsrCod)); UNIQUE INDEX(MchCod,UsrCod));
-- --
-- Table gam_questions: stores the questions in the games -- Table gam_questions: stores the questions in the games

View File

@ -468,10 +468,15 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - *
En OpenSWAD: En OpenSWAD:
ps2pdf source.ps destination.pdf ps2pdf source.ps destination.pdf
*/ */
#define Log_PLATFORM_VERSION "SWAD 19.8.2 (2019-09-22)" #define Log_PLATFORM_VERSION "SWAD 19.9 (2019-09-23)"
#define CSS_FILE "swad19.3.css" #define CSS_FILE "swad19.3.css"
#define JS_FILE "swad18.130.2.js" #define JS_FILE "swad18.130.2.js"
/* /*
Version 19.9: Sep 23, 2019 View matches results. Not finished. (245579 lines)
2 changes necessary in database:
DROP TABLE IF EXISTS mch_results;
CREATE TABLE IF NOT EXISTS mch_results (MchCod INT NOT NULL,UsrCod INT NOT NULL,NumQsts INT NOT NULL DEFAULT 0,NumQstsNotBlank INT NOT NULL DEFAULT 0,Score DOUBLE PRECISION NOT NULL DEFAULT 0,UNIQUE INDEX(MchCod,UsrCod));
Version 19.8.2: Sep 22, 2019 View matches results. Not finished. (245429 lines) Version 19.8.2: Sep 22, 2019 View matches results. Not finished. (245429 lines)
Version 19.8.1: Sep 22, 2019 View matches results. Not finished. (245474 lines) Version 19.8.1: Sep 22, 2019 View matches results. Not finished. (245474 lines)
Version 19.8: Sep 22, 2019 View matches results. Not finished. Version 19.8: Sep 22, 2019 View matches results. Not finished.

View File

@ -1436,26 +1436,23 @@ mysql> DESCRIBE mch_players;
/***** Table mch_results *****/ /***** Table mch_results *****/
/* /*
mysql> DESCRIBE mch_results; mysql> DESCRIBE mch_results;
+-----------------+---------+------+-----+---------+----------------+ +-----------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra | | Field | Type | Null | Key | Default | Extra |
+-----------------+---------+------+-----+---------+----------------+ +-----------------+---------+------+-----+---------+-------+
| MchResCod | int(11) | NO | PRI | NULL | auto_increment | | MchCod | int(11) | NO | PRI | NULL | |
| MchCod | int(11) | NO | MUL | NULL | | | UsrCod | int(11) | NO | PRI | NULL | |
| UsrCod | int(11) | NO | | NULL | | | NumQsts | int(11) | NO | | 0 | |
| NumQsts | int(11) | NO | | 0 | | | NumQstsNotBlank | int(11) | NO | | 0 | |
| NumQstsNotBlank | int(11) | NO | | 0 | | | Score | double | NO | | 0 | |
| Score | double | NO | | 0 | | +-----------------+---------+------+-----+---------+-------+
+-----------------+---------+------+-----+---------+----------------+ 5 rows in set (0.00 sec)
6 rows in set (0.01 sec)
*/ */
DB_CreateTable ("CREATE TABLE IF NOT EXISTS mch_results (" DB_CreateTable ("CREATE TABLE IF NOT EXISTS mch_results ("
"MchResCod INT NOT NULL AUTO_INCREMENT,"
"MchCod INT NOT NULL," "MchCod INT NOT NULL,"
"UsrCod INT NOT NULL," "UsrCod INT NOT NULL,"
"NumQsts INT NOT NULL DEFAULT 0," "NumQsts INT NOT NULL DEFAULT 0,"
"NumQstsNotBlank INT NOT NULL DEFAULT 0," "NumQstsNotBlank INT NOT NULL DEFAULT 0,"
"Score DOUBLE PRECISION NOT NULL DEFAULT 0," "Score DOUBLE PRECISION NOT NULL DEFAULT 0,"
"UNIQUE INDEX(MchResCod),"
"UNIQUE INDEX(MchCod,UsrCod))"); "UNIQUE INDEX(MchCod,UsrCod))");
/***** Table gam_questions *****/ /***** Table gam_questions *****/

View File

@ -192,6 +192,8 @@ static void Mch_RegisterMeAsPlayerInMatch (long MchCod);
static void Mch_GetNumPlayers (struct Match *Match); static void Mch_GetNumPlayers (struct Match *Match);
static int Mch_GetQstAnsFromDB (long MchCod,unsigned QstInd); static int Mch_GetQstAnsFromDB (long MchCod,unsigned QstInd);
static void Mch_ComputeScore (struct Match *Match,unsigned NumQsts,
unsigned *NumQstsNotBlank,double *TotalScore);
static unsigned Mch_GetNumUsrsWhoHaveChosenAns (long MchCod,unsigned QstInd,unsigned AnsInd); static unsigned Mch_GetNumUsrsWhoHaveChosenAns (long MchCod,unsigned QstInd,unsigned AnsInd);
static unsigned Mch_GetNumUsrsWhoHaveAnswerMch (long MchCod); static unsigned Mch_GetNumUsrsWhoHaveAnswerMch (long MchCod);
@ -2286,6 +2288,9 @@ void Mch_ReceiveQstAnsFromStd (void)
unsigned QstInd; unsigned QstInd;
unsigned StdAnsInd; unsigned StdAnsInd;
int PreviousStdAnsInd; int PreviousStdAnsInd;
unsigned NumQsts;
unsigned NumQstsNotBlank;
double TotalScore;
/***** Remove old players. /***** Remove old players.
This function must be called before getting match status. *****/ This function must be called before getting match status. *****/
@ -2331,6 +2336,20 @@ void Mch_ReceiveQstAnsFromStd (void)
" VALUES" " VALUES"
" (%ld,%ld,%u,%u)", " (%ld,%ld,%u,%u)",
Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,QstInd,StdAnsInd); Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,QstInd,StdAnsInd);
/***** Update student's match result *****/
NumQsts = Gam_GetNumQstsGame (Match.GamCod);
Mch_ComputeScore (&Match,NumQsts,&NumQstsNotBlank,&TotalScore);
Str_SetDecimalPointToUS (); // To print the floating point as a dot
DB_QueryREPLACE ("can not update match result",
"REPLACE mch_results"
" (MchCod,UsrCod,NumQsts,NumQstsNotBlank,Score)"
" VALUES"
" (%ld,%ld,%u,%u,'%lf')",
Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,
NumQsts,NumQstsNotBlank,TotalScore);
Str_SetDecimalPointToLocal (); // Return to local system
} }
/***** Show current match status *****/ /***** Show current match status *****/
@ -2339,6 +2358,126 @@ void Mch_ReceiveQstAnsFromStd (void)
fprintf (Gbl.F.Out,"</div>"); fprintf (Gbl.F.Out,"</div>");
} }
/*****************************************************************************/
/******************** Compute match score for a student **********************/
/*****************************************************************************/
static void Mch_ComputeScore (struct Match *Match,unsigned NumQsts,
unsigned *NumQstsNotBlank,double *TotalScore)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumQst;
unsigned NumQstNotBlank;
unsigned QstInd;
unsigned NumOpt;
long QstCod;
long LongNum;
double ScoreThisQst;
bool AnswerIsNotBlank;
struct UsrAnswer
{
unsigned QstInd;
unsigned AnsInd;
} *UsrAnswers;
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question
bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION];
/***** Get user's answers *****/
/* Query database */
*NumQstsNotBlank = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get user's answers",
"SELECT QstInd," // row[0]
"AnsInd" // row[1]
" FROM mch_answers"
" WHERE MchCod=%ld AND UsrCod=%ld",
Match->MchCod,Gbl.Usrs.Me.UsrDat.UsrCod);
/* Allocate memory for answers */
if ((UsrAnswers = (struct UsrAnswer *) malloc (*NumQstsNotBlank *
sizeof (struct UsrAnswer))) == NULL)
Lay_NotEnoughMemoryExit ();
/* Get answers from database */
for (NumQstNotBlank = 0;
NumQstNotBlank < *NumQstsNotBlank;
NumQstNotBlank++)
{
row = mysql_fetch_row (mysql_res);
/* Get question index (row[0]) */
if ((LongNum = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong question index.");
UsrAnswers[NumQstNotBlank].QstInd = (unsigned) LongNum;
/* Get answer index (row[1]) */
if ((LongNum = Str_ConvertStrCodToLongCod (row[1])) < 0)
Lay_ShowErrorAndExit ("Wrong answer index.");
UsrAnswers[NumQstNotBlank].AnsInd = (unsigned) LongNum;
}
/* Free structure that stores the query result */
DB_FreeMySQLResult (&mysql_res);
/***** For each question in match... *****/
for (NumQst = 0, *TotalScore = 0.0;
NumQst < NumQsts;
NumQst++)
{
QstInd = NumQst + 1;
/***** Get question code *****/
QstCod = Gam_GetQstCodFromQstInd (Match->GamCod,QstInd);
/***** Get answers of test question from database *****/
/* Query database */
Gbl.Test.Answer.NumOptions = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get answers of a question",
"SELECT Correct" // row[0]
" FROM tst_answers"
" WHERE QstCod=%ld ORDER BY AnsInd",
QstCod);
for (NumOpt = 0;
NumOpt < Gbl.Test.Answer.NumOptions;
NumOpt++)
{
/* Get next answer */
row = mysql_fetch_row (mysql_res);
/* Assign correctness (row[0]) of this answer (this option) */
Gbl.Test.Answer.Options[NumOpt].Correct = (row[0][0] == 'Y');
}
/* Free structure that stores the query result */
DB_FreeMySQLResult (&mysql_res);
/***** Get indexes for this question *****/
// TODO: Answers should be shuffled?
for (NumOpt = 0;
NumOpt < Gbl.Test.Answer.NumOptions;
NumOpt++)
Indexes[NumOpt] = NumOpt;
/***** Get the user's answers for this question *****/
for (NumOpt = 0;
NumOpt < Gbl.Test.Answer.NumOptions;
NumOpt++)
AnswersUsr[NumOpt] = false;
for (NumQstNotBlank = 0;
NumQstNotBlank < *NumQstsNotBlank;
NumQstNotBlank++)
if (UsrAnswers[NumQstNotBlank].QstInd == QstInd)
if (UsrAnswers[NumQstNotBlank].AnsInd < Gbl.Test.Answer.NumOptions)
AnswersUsr[UsrAnswers[NumQstNotBlank].AnsInd] = true;
/***** Compute the total score of this question *****/
Tst_ComputeScoreQst (Indexes,AnswersUsr,&ScoreThisQst,&AnswerIsNotBlank);
/***** Compute total score *****/
*TotalScore += ScoreThisQst;
}
}
/*****************************************************************************/ /*****************************************************************************/
/*** Get number of users who selected this answer and draw proportional bar **/ /*** Get number of users who selected this answer and draw proportional bar **/
/*****************************************************************************/ /*****************************************************************************/

View File

@ -2638,7 +2638,7 @@ void Prj_GetDataOfProjectByCod (struct Project *Prj)
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
long NumLong; long LongNum;
Prj_Proposal_t Proposal; Prj_Proposal_t Proposal;
if (Prj->PrjCod > 0) if (Prj->PrjCod > 0)
@ -2693,9 +2693,9 @@ void Prj_GetDataOfProjectByCod (struct Project *Prj)
Prj_NONPREASSIG; Prj_NONPREASSIG;
/* Get if project is preassigned or not (row[6]) */ /* Get if project is preassigned or not (row[6]) */
NumLong = Str_ConvertStrCodToLongCod (row[6]); LongNum = Str_ConvertStrCodToLongCod (row[6]);
if (NumLong >= 0) if (LongNum >= 0)
Prj->NumStds = (unsigned) NumLong; Prj->NumStds = (unsigned) LongNum;
else else
Prj->NumStds = 1; Prj->NumStds = 1;

View File

@ -3284,7 +3284,8 @@ unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle)
"Feedback," // row[2] "Feedback," // row[2]
"MedCod," // row[3] "MedCod," // row[3]
"Correct" // row[4] "Correct" // row[4]
" FROM tst_answers WHERE QstCod=%ld ORDER BY %s", " FROM tst_answers"
" WHERE QstCod=%ld ORDER BY %s",
QstCod, QstCod,
Shuffle ? "RAND(NOW())" : Shuffle ? "RAND(NOW())" :
"AnsInd"); "AnsInd");
@ -3794,7 +3795,6 @@ static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat,
extern const char *Txt_TST_Answer_given_by_the_user; extern const char *Txt_TST_Answer_given_by_the_user;
extern const char *Txt_TST_Answer_given_by_the_teachers; extern const char *Txt_TST_Answer_given_by_the_teachers;
unsigned NumOpt; unsigned NumOpt;
MYSQL_ROW row;
char StrOneIndex[10 + 1]; char StrOneIndex[10 + 1];
const char *Ptr; const char *Ptr;
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question
@ -3805,10 +3805,152 @@ static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat,
char *Class; char *Class;
char *Str; char *Str;
} Ans; } Ans;
unsigned NumOptTotInQst = 0;
unsigned NumOptCorrInQst = 0; /***** Get text and correctness of answers for this question
unsigned NumAnsGood = 0; from database (one row per answer) *****/
unsigned NumAnsBad = 0; Tst_GetChoiceAns (mysql_res);
/***** Get indexes for this question from string *****/
for (NumOpt = 0, Ptr = Gbl.Test.StrIndexesOneQst[NumQst];
NumOpt < Gbl.Test.Answer.NumOptions;
NumOpt++)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,StrOneIndex,10);
if (sscanf (StrOneIndex,"%u",&(Indexes[NumOpt])) != 1)
Lay_ShowErrorAndExit ("Wrong index of answer when assessing a test.");
}
/***** Get the user's answers for this question from string *****/
for (NumOpt = 0;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
NumOpt++)
AnswersUsr[NumOpt] = false;
for (NumOpt = 0, Ptr = Gbl.Test.StrAnswersOneQst[NumQst];
NumOpt < Gbl.Test.Answer.NumOptions;
NumOpt++)
if (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,StrOneIndex,10);
if (sscanf (StrOneIndex,"%d",&AnsUsr) != 1)
Lay_ShowErrorAndExit ("Bad user's answer.");
if (AnsUsr < 0 || AnsUsr >= Tst_MAX_OPTIONS_PER_QUESTION)
Lay_ShowErrorAndExit ("Bad user's answer.");
AnswersUsr[AnsUsr] = true;
}
/***** Compute the total score of this question *****/
Tst_ComputeScoreQst (Indexes,AnswersUsr,ScoreThisQst,AnswerIsNotBlank);
/***** Start table *****/
Tbl_StartTable (2);
fprintf (Gbl.F.Out,"<tr>");
Tst_WriteHeadUserCorrect (UsrDat);
fprintf (Gbl.F.Out,"<td></td>"
"<td></td>"
"</tr>");
/***** Write answers (one row per answer) *****/
for (NumOpt = 0;
NumOpt < Gbl.Test.Answer.NumOptions;
NumOpt++)
{
fprintf (Gbl.F.Out,"<tr>");
/* Draw icon depending on user's answer */
if (AnswersUsr[Indexes[NumOpt]] == true) // This answer has been selected by the user
{
if (Gbl.Test.Config.Feedback == Tst_FEEDBACK_EACH_GOOD_BAD ||
Gbl.Test.Config.Feedback == Tst_FEEDBACK_FULL_FEEDBACK)
{
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Correct)
{
Ans.Class = "ANS_OK";
Ans.Str = "&check;";
}
else
{
Ans.Class = "ANS_BAD";
Ans.Str = "&cross;";
}
}
else
{
Ans.Class = "ANS_0";
Ans.Str = "&bull;";
}
fprintf (Gbl.F.Out,"<td class=\"%s CENTER_TOP\" title=\"%s\">%s</td>",
Ans.Class,Txt_TST_Answer_given_by_the_user,Ans.Str);
}
else // This answer has NOT been selected by the user
fprintf (Gbl.F.Out,"<td></td>");
/* Draw icon that indicates whether the answer is correct */
if (Gbl.Test.Config.Feedback == Tst_FEEDBACK_EACH_GOOD_BAD ||
Gbl.Test.Config.Feedback == Tst_FEEDBACK_FULL_FEEDBACK)
{
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Correct)
fprintf (Gbl.F.Out,"<td class=\"ANS_0 CENTER_TOP\" title=\"%s\">&bull;</td>",
Txt_TST_Answer_given_by_the_teachers);
else
fprintf (Gbl.F.Out,"<td></td>");
}
else
fprintf (Gbl.F.Out,"<td class=\"ANS_0 CENTER_TOP\">?</td>");
/* Answer letter (a, b, c,...) */
fprintf (Gbl.F.Out,"<td class=\"ANS_TXT LEFT_TOP\">"
"%c)&nbsp;"
"</td>",
'a' + (char) NumOpt);
/* Answer text and feedback */
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP\">"
"<div class=\"ANS_TXT\">"
"%s",
Gbl.Test.Answer.Options[Indexes[NumOpt]].Text);
Med_ShowMedia (&Gbl.Test.Answer.Options[Indexes[NumOpt]].Media,
"TEST_MED_SHOW_CONTAINER",
"TEST_MED_SHOW");
fprintf (Gbl.F.Out,"</div>");
if (Gbl.Test.Config.Feedback == Tst_FEEDBACK_FULL_FEEDBACK)
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Feedback)
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Feedback[0])
fprintf (Gbl.F.Out,"<div class=\"TEST_EXA_LIGHT\">"
"%s"
"</div>",
Gbl.Test.Answer.Options[Indexes[NumOpt]].Feedback);
fprintf (Gbl.F.Out,"</td>"
"</tr>");
}
/***** Write the total score of this question *****/
if (Gbl.Test.Config.Feedback == Tst_FEEDBACK_EACH_RESULT ||
Gbl.Test.Config.Feedback == Tst_FEEDBACK_EACH_GOOD_BAD ||
Gbl.Test.Config.Feedback == Tst_FEEDBACK_FULL_FEEDBACK)
{
Tst_WriteScoreStart (4);
if (*ScoreThisQst == 0.0)
fprintf (Gbl.F.Out,"ANS_0");
else if (*ScoreThisQst > 0.0)
fprintf (Gbl.F.Out,"ANS_OK");
else
fprintf (Gbl.F.Out,"ANS_BAD");
fprintf (Gbl.F.Out,"\">%.2lf",*ScoreThisQst);
Tst_WriteScoreEnd ();
}
/***** End table *****/
Tbl_EndTable ();
}
/*****************************************************************************/
/************************ Get choice answer from row *************************/
/*****************************************************************************/
void Tst_GetChoiceAns (MYSQL_RES *mysql_res)
{
unsigned NumOpt;
MYSQL_ROW row;
/***** Get text and correctness of answers for this question /***** Get text and correctness of answers for this question
from database (one row per answer) *****/ from database (one row per answer) *****/
@ -3859,118 +4001,31 @@ static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat,
/***** Assign correctness (row[4]) of this answer (this option) *****/ /***** Assign correctness (row[4]) of this answer (this option) *****/
Gbl.Test.Answer.Options[NumOpt].Correct = (row[4][0] == 'Y'); Gbl.Test.Answer.Options[NumOpt].Correct = (row[4][0] == 'Y');
} }
}
/***** Get indexes for this question from string *****/ /*****************************************************************************/
for (NumOpt = 0, Ptr = Gbl.Test.StrIndexesOneQst[NumQst]; /********************* Compute the score of this question ********************/
NumOpt < Gbl.Test.Answer.NumOptions; /*****************************************************************************/
NumOpt++)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,StrOneIndex,10);
if (sscanf (StrOneIndex,"%u",&(Indexes[NumOpt])) != 1)
Lay_ShowErrorAndExit ("Wrong index of answer when assessing a test.");
}
/***** Get the user's answers for this question from string *****/ void Tst_ComputeScoreQst (unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION], // Indexes of all answers of this question
for (NumOpt = 0; bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION],
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION; double *ScoreThisQst,bool *AnswerIsNotBlank)
NumOpt++) {
AnswersUsr[NumOpt] = false; unsigned NumOpt;
for (NumOpt = 0, Ptr = Gbl.Test.StrAnswersOneQst[NumQst]; unsigned NumOptTotInQst = 0;
NumOpt < Gbl.Test.Answer.NumOptions; unsigned NumOptCorrInQst = 0;
NumOpt++) unsigned NumAnsGood = 0;
if (*Ptr) unsigned NumAnsBad = 0;
{
Par_GetNextStrUntilSeparParamMult (&Ptr,StrOneIndex,10);
if (sscanf (StrOneIndex,"%d",&AnsUsr) != 1)
Lay_ShowErrorAndExit ("Bad user's answer.");
if (AnsUsr < 0 || AnsUsr >= Tst_MAX_OPTIONS_PER_QUESTION)
Lay_ShowErrorAndExit ("Bad user's answer.");
AnswersUsr[AnsUsr] = true;
}
/***** Start table *****/ /***** Compute the total score of this question *****/
Tbl_StartTable (2);
fprintf (Gbl.F.Out,"<tr>");
Tst_WriteHeadUserCorrect (UsrDat);
fprintf (Gbl.F.Out,"<td></td>"
"<td></td>"
"</tr>");
/***** Write answers (one row per answer) *****/
for (NumOpt = 0; for (NumOpt = 0;
NumOpt < Gbl.Test.Answer.NumOptions; NumOpt < Gbl.Test.Answer.NumOptions;
NumOpt++) NumOpt++)
{ {
fprintf (Gbl.F.Out,"<tr>");
/* Draw icon depending on user's answer */
if (AnswersUsr[Indexes[NumOpt]] == true) // This answer has been selected by the user
{
if (Gbl.Test.Config.Feedback == Tst_FEEDBACK_EACH_GOOD_BAD ||
Gbl.Test.Config.Feedback == Tst_FEEDBACK_FULL_FEEDBACK)
{
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Correct)
{
Ans.Class = "ANS_OK";
Ans.Str = "&check;";
}
else
{
Ans.Class = "ANS_BAD";
Ans.Str = "&cross;";
}
}
else
{
Ans.Class = "ANS_0";
Ans.Str = "&bull;";
}
fprintf (Gbl.F.Out,"<td class=\"%s CENTER_TOP\" title=\"%s\">%s</td>",
Ans.Class,Txt_TST_Answer_given_by_the_user,Ans.Str);
}
else // This answer has NOT been selected by the user
fprintf (Gbl.F.Out,"<td></td>");
/* Draw icon that indicates whether the answer is correct */
if (Gbl.Test.Config.Feedback == Tst_FEEDBACK_EACH_GOOD_BAD ||
Gbl.Test.Config.Feedback == Tst_FEEDBACK_FULL_FEEDBACK)
{
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Correct)
fprintf (Gbl.F.Out,"<td class=\"ANS_0 CENTER_TOP\" title=\"%s\">&bull;</td>",
Txt_TST_Answer_given_by_the_teachers);
else
fprintf (Gbl.F.Out,"<td></td>");
}
else
fprintf (Gbl.F.Out,"<td class=\"ANS_0 CENTER_TOP\">?</td>");
/* Answer letter (a, b, c,...) */
fprintf (Gbl.F.Out,"<td class=\"ANS_TXT LEFT_TOP\">"
"%c)&nbsp;"
"</td>",
'a' + (char) NumOpt);
/* Answer text and feedback */
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP\">"
"<div class=\"ANS_TXT\">"
"%s",
Gbl.Test.Answer.Options[Indexes[NumOpt]].Text);
Med_ShowMedia (&Gbl.Test.Answer.Options[Indexes[NumOpt]].Media,
"TEST_MED_SHOW_CONTAINER",
"TEST_MED_SHOW");
fprintf (Gbl.F.Out,"</div>");
if (Gbl.Test.Config.Feedback == Tst_FEEDBACK_FULL_FEEDBACK)
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Feedback)
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Feedback[0])
fprintf (Gbl.F.Out,"<div class=\"TEST_EXA_LIGHT\">"
"%s"
"</div>",
Gbl.Test.Answer.Options[Indexes[NumOpt]].Feedback);
fprintf (Gbl.F.Out,"</td>"
"</tr>");
NumOptTotInQst++; NumOptTotInQst++;
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Correct)
NumOptCorrInQst++;
if (AnswersUsr[Indexes[NumOpt]] == true) // This answer has been selected by the user if (AnswersUsr[Indexes[NumOpt]] == true) // This answer has been selected by the user
{ {
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Correct) if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Correct)
@ -3978,14 +4033,10 @@ static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat,
else else
NumAnsBad++; NumAnsBad++;
} }
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Correct)
NumOptCorrInQst++;
} }
/***** The answer is blank? *****/ /* The answer is blank? */
*AnswerIsNotBlank = NumAnsGood != 0 || NumAnsBad != 0; *AnswerIsNotBlank = NumAnsGood != 0 || NumAnsBad != 0;
/***** Compute and write the total score of this question *****/
if (*AnswerIsNotBlank) if (*AnswerIsNotBlank)
{ {
/* Compute the score */ /* Compute the score */
@ -4018,25 +4069,6 @@ static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat,
} }
else // Answer is blank else // Answer is blank
*ScoreThisQst = 0.0; *ScoreThisQst = 0.0;
/* Write the score */
if (Gbl.Test.Config.Feedback == Tst_FEEDBACK_EACH_RESULT ||
Gbl.Test.Config.Feedback == Tst_FEEDBACK_EACH_GOOD_BAD ||
Gbl.Test.Config.Feedback == Tst_FEEDBACK_FULL_FEEDBACK)
{
Tst_WriteScoreStart (4);
if (*ScoreThisQst == 0.0)
fprintf (Gbl.F.Out,"ANS_0");
else if (*ScoreThisQst > 0.0)
fprintf (Gbl.F.Out,"ANS_OK");
else
fprintf (Gbl.F.Out,"ANS_BAD");
fprintf (Gbl.F.Out,"\">%.2lf",*ScoreThisQst);
Tst_WriteScoreEnd ();
}
/***** End table *****/
Tbl_EndTable ();
} }
/*****************************************************************************/ /*****************************************************************************/

View File

@ -158,6 +158,10 @@ void Tst_WriteAnswersMatchResult (long MchCod,unsigned QstInd,long QstCod,
const char *Class,bool ShowResult); const char *Class,bool ShowResult);
bool Tst_CheckIfQuestionIsValidForGame (long QstCod); bool Tst_CheckIfQuestionIsValidForGame (long QstCod);
void Tst_WriteAnsTF (char AnsTF); void Tst_WriteAnsTF (char AnsTF);
void Tst_GetChoiceAns (MYSQL_RES *mysql_res);
void Tst_ComputeScoreQst (unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION],
bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION],
double *ScoreThisQst,bool *AnswerIsNotBlank);
void Tst_CheckIfNumberOfAnswersIsOne (void); void Tst_CheckIfNumberOfAnswersIsOne (void);
unsigned long Tst_GetTagsQst (long QstCod,MYSQL_RES **mysql_res); unsigned long Tst_GetTagsQst (long QstCod,MYSQL_RES **mysql_res);