mirror of
https://github.com/acanas/swad-core.git
synced 2024-06-05 00:05:23 +02:00
Version19.9
This commit is contained in:
parent
1f02939f6c
commit
f946925237
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 *****/
|
||||||
|
|
139
swad_match.c
139
swad_match.c
|
@ -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 **/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
300
swad_test.c
300
swad_test.c
|
@ -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 = "✓";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Ans.Class = "ANS_BAD";
|
||||||
|
Ans.Str = "✗";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Ans.Class = "ANS_0";
|
||||||
|
Ans.Str = "•";
|
||||||
|
}
|
||||||
|
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\">•</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) "
|
||||||
|
"</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 = "✓";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Ans.Class = "ANS_BAD";
|
|
||||||
Ans.Str = "✗";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Ans.Class = "ANS_0";
|
|
||||||
Ans.Str = "•";
|
|
||||||
}
|
|
||||||
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\">•</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) "
|
|
||||||
"</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 ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user