Version19.12

This commit is contained in:
Antonio Cañas Vargas 2019-09-24 01:41:51 +02:00
parent b7987d6356
commit b4bc3aa6ef
10 changed files with 221 additions and 157 deletions

View File

@ -12878,4 +12878,19 @@ REPLACE gam_time (MchCod,QstInd,ElapsedTime) VALUES (61,1,ADDTIME(ElapsedTime,SE
INSERT INTO gam_time (MchCod,QstInd) VALUES (61,1,SEC_TO_TIME(1)) ON DUPLICATE KEY UPDATE ElapsedTime=ADDTIME(ElapsedTime,SEC_TO_TIME(1)); INSERT INTO gam_time (MchCod,QstInd) VALUES (61,1,SEC_TO_TIME(1)) ON DUPLICATE KEY UPDATE ElapsedTime=ADDTIME(ElapsedTime,SEC_TO_TIME(1));
----------------
SELECT gam_questions.QstCod,
gam_questions.QstInd,
mch_indexes.Indexes
FROM mch_matches,gam_questions,mch_indexes
WHERE mch_matches.MchCod=69
AND mch_matches.GamCod=gam_questions.GamCod
AND mch_matches.MchCod=mch_indexes.MchCod
AND gam_questions.QstInd=mch_indexes.QstInd
ORDER BY gam_questions.QstInd;
SELECT Correct FROM tst_answers WHERE QstCod=1787 ORDER BY AnsInd;

View File

@ -613,11 +613,12 @@ CREATE TABLE IF NOT EXISTS gam_games (
-- --
-- Table mch_answers: stores the users' answers to the matches -- Table mch_answers: stores the users' answers to the matches
-- --
CREATE TABLE IF NOT EXISTS mch_answers (" CREATE TABLE IF NOT EXISTS mch_answers (
MchCod INT NOT NULL," MchCod INT NOT NULL,
UsrCod INT NOT NULL," UsrCod INT NOT NULL,
QstInd INT NOT NULL," QstInd INT NOT NULL,
AnsInd TINYINT NOT NULL," NumOpt TINYINT NOT NULL,
AnsInd TINYINT NOT NULL,
UNIQUE INDEX(MchCod,UsrCod,QstInd)); UNIQUE INDEX(MchCod,UsrCod,QstInd));
-- --
-- Table mch_groups: stores the groups associated to each match in a game -- Table mch_groups: stores the groups associated to each match in a game

View File

@ -470,10 +470,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.11 (2019-09-23)" #define Log_PLATFORM_VERSION "SWAD 19.12 (2019-09-24)"
#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.12: Sep 24, 2019 View matches results. Not finished. (245973 lines)
1 change necessary in database:
ALTER TABLE mch_answers ADD COLUMN NumOpt TINYINT NOT NULL AFTER QstInd;
Version 19.11: Sep 23, 2019 Create indexes when a match is created. (245933 lines) Version 19.11: Sep 23, 2019 Create indexes when a match is created. (245933 lines)
Version 19.10.3: Sep 23, 2019 View matches results. Not finished. (245815 lines) Version 19.10.3: Sep 23, 2019 View matches results. Not finished. (245815 lines)
Version 19.10.2: Sep 23, 2019 View matches results. Not finished. (245812 lines) Version 19.10.2: Sep 23, 2019 View matches results. Not finished. (245812 lines)

View File

@ -1339,15 +1339,17 @@ mysql> DESCRIBE mch_answers;
| MchCod | int(11) | NO | PRI | NULL | | | MchCod | int(11) | NO | PRI | NULL | |
| UsrCod | int(11) | NO | PRI | NULL | | | UsrCod | int(11) | NO | PRI | NULL | |
| QstInd | int(11) | NO | PRI | NULL | | | QstInd | int(11) | NO | PRI | NULL | |
| AnsInd | tinyint(4) | NO | PRI | NULL | | | NumOpt | tinyint(4) | NO | | NULL | |
| AnsInd | tinyint(4) | NO | | NULL | |
+--------+------------+------+-----+---------+-------+ +--------+------------+------+-----+---------+-------+
4 rows in set (0.00 sec) 5 rows in set (0.00 sec)
*/ */
DB_CreateTable ("CREATE TABLE IF NOT EXISTS mch_answers (" DB_CreateTable ("CREATE TABLE IF NOT EXISTS mch_answers ("
"MchCod INT NOT NULL," "MchCod INT NOT NULL,"
"UsrCod INT NOT NULL," "UsrCod INT NOT NULL,"
"QstInd INT NOT NULL," "QstInd INT NOT NULL,"
"AnsInd TINYINT NOT NULL," "NumOpt TINYINT NOT NULL," // Number of button on screen (Always ordered: 0,1,2,3)
"AnsInd TINYINT NOT NULL," // Answer index (Can be shuffled: 0,3,1,2)
"UNIQUE INDEX(MchCod,UsrCod,QstInd))"); "UNIQUE INDEX(MchCod,UsrCod,QstInd))");
/***** Table mch_groups *****/ /***** Table mch_groups *****/

View File

@ -1382,13 +1382,13 @@ void Gam_PutParamQstInd (unsigned QstInd)
unsigned Gam_GetParamQstInd (void) unsigned Gam_GetParamQstInd (void)
{ {
long LongNum; long QstInd;
LongNum = Par_GetParToLong ("QstInd"); QstInd = Par_GetParToLong ("QstInd");
if (LongNum < 0) if (QstInd < 0)
Lay_ShowErrorAndExit ("Wrong question index."); Lay_ShowErrorAndExit ("Wrong question index.");
return (unsigned) LongNum; return (unsigned) QstInd;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -1397,11 +1397,11 @@ unsigned Gam_GetParamQstInd (void)
unsigned Gam_GetQstIndFromStr (const char *UnsignedStr) unsigned Gam_GetQstIndFromStr (const char *UnsignedStr)
{ {
long LongNum; long QstInd;
LongNum = Str_ConvertStrCodToLongCod (UnsignedStr); QstInd = Str_ConvertStrCodToLongCod (UnsignedStr);
return (LongNum > 0) ? (unsigned) LongNum : return (QstInd > 0) ? (unsigned) QstInd :
0; 0;
} }
/*****************************************************************************/ /*****************************************************************************/

View File

@ -99,6 +99,12 @@ struct Match
} Status; } Status;
}; };
struct Mch_UsrAnswer
{
int NumOpt; // < 0 ==> no answer selected
int AnsInd; // < 0 ==> no answer selected
};
/*****************************************************************************/ /*****************************************************************************/
/***************************** Private constants *****************************/ /***************************** Private constants *****************************/
/*****************************************************************************/ /*****************************************************************************/
@ -177,8 +183,8 @@ static void Mch_ShowMatchTitle (struct Match *Match);
static void Mch_ShowQuestionAndAnswersTch (struct Match *Match); static void Mch_ShowQuestionAndAnswersTch (struct Match *Match);
static void Mch_ShowQuestionAndAnswersStd (struct Match *Match); static void Mch_ShowQuestionAndAnswersStd (struct Match *Match);
static void Mch_PutParamAnswer (unsigned AnsInd); static void Mch_PutParamNumOpt (unsigned NumOpt);
static unsigned Mch_GetParamAnswer (void); static unsigned Mch_GetParamNumOpt (void);
static void Mch_PutBigButton (Act_Action_t NextAction,long MchCod, static void Mch_PutBigButton (Act_Action_t NextAction,long MchCod,
const char *Icon,const char *Txt); const char *Icon,const char *Txt);
@ -194,7 +200,8 @@ static bool Mch_GetIfMatchIsBeingPlayed (long MchCod);
static void Mch_RegisterMeAsPlayerInMatch (long MchCod); 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,long UsrCod,unsigned QstInd); static void Mch_GetQstAnsFromDB (long MchCod,long UsrCod,unsigned QstInd,
struct Mch_UsrAnswer *UsrAnswer);
static void Mch_ComputeScore (struct Match *Match,unsigned NumQsts,long UsrCod, static void Mch_ComputeScore (struct Match *Match,unsigned NumQsts,long UsrCod,
unsigned *NumQstsNotBlank,double *TotalScore); unsigned *NumQstsNotBlank,double *TotalScore);
@ -1088,7 +1095,7 @@ static void Mch_CreateIndexes (long GamCod,long MchCod)
DB_QuerySELECT (&mysql_res,"can not get questions of a game", DB_QuerySELECT (&mysql_res,"can not get questions of a game",
"SELECT gam_questions.QstCod," // row[0] "SELECT gam_questions.QstCod," // row[0]
"gam_questions.QstInd," // row[1] "gam_questions.QstInd," // row[1]
"tst_questions.AnsType" // row[2] "tst_questions.AnsType," // row[2]
"tst_questions.Shuffle" // row[3] "tst_questions.Shuffle" // row[3]
" FROM gam_questions,tst_questions" " FROM gam_questions,tst_questions"
" WHERE gam_questions.GamCod=%ld" " WHERE gam_questions.GamCod=%ld"
@ -1153,10 +1160,10 @@ static void Mch_ReorderAnswer (long MchCod,unsigned QstInd,
DB_QuerySELECT (&mysql_res,"can not get questions of a game", DB_QuerySELECT (&mysql_res,"can not get questions of a game",
"SELECT AnsInd" // row[0] "SELECT AnsInd" // row[0]
" FROM tst_answers" " FROM tst_answers"
" WHERE GamCod=%ld" " WHERE QstCod=%ld"
" ORDER BY %s", " ORDER BY %s",
QstCod, QstCod,
Shuffle ? "RAND(NOW())" : Shuffle ? "RAND()" : // Use RAND() because is really random; RAND(NOW()) repeats order
"AnsInd"); "AnsInd");
/***** For each answer in question... *****/ /***** For each answer in question... *****/
@ -1170,10 +1177,10 @@ static void Mch_ReorderAnswer (long MchCod,unsigned QstInd,
if ((LongNum = Str_ConvertStrCodToLongCod (row[0])) < 0) if ((LongNum = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong answer index."); Lay_ShowErrorAndExit ("Wrong answer index.");
AnsInd = (unsigned) LongNum; AnsInd = (unsigned) LongNum;
snprintf (StrOneAnswer,sizeof (StrOneAnswer),
"%u",AnsInd);
/* Concatenate answer index to list of answers */ /* Concatenate answer index to list of answers */
snprintf (StrOneAnswer,10 + 1,
"%u",AnsInd);
if (NumAns) if (NumAns)
Str_Concat (StrAnswersOneQst,",", Str_Concat (StrAnswersOneQst,",",
Tst_MAX_BYTES_ANSWERS_ONE_QST); Tst_MAX_BYTES_ANSWERS_ONE_QST);
@ -1193,6 +1200,38 @@ static void Mch_ReorderAnswer (long MchCod,unsigned QstInd,
MchCod,QstInd,StrAnswersOneQst); MchCod,QstInd,StrAnswersOneQst);
} }
/*****************************************************************************/
/***************** Get indexes for a question from database ******************/
/*****************************************************************************/
void Mch_GetIndexes (long MchCod,unsigned QstInd,
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION])
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1];
/***** Get indexes for a question from database *****/
if (!DB_QuerySELECT (&mysql_res,"can not get data of a question",
"SELECT Indexes" // row[0]
" FROM mch_indexes"
" WHERE MchCod=%ld AND QstInd=%u",
MchCod,QstInd))
Lay_ShowErrorAndExit ("No indexes found for a question.");
row = mysql_fetch_row (mysql_res);
/* Get indexes (row[0]) */
Str_Copy (StrIndexesOneQst,row[0],
Tst_MAX_BYTES_INDEXES_ONE_QST);
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
/***** Get indexes from string *****/
Par_ReplaceCommaBySeparatorMultiple (StrIndexesOneQst);
Tst_GetIndexesFromStr (StrIndexesOneQst,Indexes);
}
/*****************************************************************************/ /*****************************************************************************/
/******************* Create groups associated to a match *********************/ /******************* Create groups associated to a match *********************/
/*****************************************************************************/ /*****************************************************************************/
@ -1976,7 +2015,10 @@ static void Mch_ShowQuestionAndAnswersTch (struct Match *Match)
"TEST_MED_EDIT_LIST_STEM_CONTAINER", "TEST_MED_EDIT_LIST_STEM_CONTAINER",
"TEST_MED_EDIT_LIST_STEM"); "TEST_MED_EDIT_LIST_STEM");
/* Write answers? */ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
/***** Write answers? *****/
switch (Match->Status.Showing) switch (Match->Status.Showing)
{ {
case Mch_NOTHING: case Mch_NOTHING:
@ -2013,14 +2055,9 @@ static void Mch_ShowQuestionAndAnswersTch (struct Match *Match)
static void Mch_ShowQuestionAndAnswersStd (struct Match *Match) static void Mch_ShowQuestionAndAnswersStd (struct Match *Match)
{ {
bool Shuffle = false; // TODO: Read shuffle from question struct Mch_UsrAnswer UsrAnswer;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
int StdAnsInd;
unsigned NumOptions; unsigned NumOptions;
unsigned NumOpt; unsigned NumOpt;
unsigned Index;
bool ErrorInIndex = false;
/***** Show question *****/ /***** Show question *****/
/* Write buttons for answers? */ /* Write buttons for answers? */
@ -2030,24 +2067,14 @@ static void Mch_ShowQuestionAndAnswersStd (struct Match *Match)
{ {
/***** Get student's answer to this question /***** Get student's answer to this question
(<0 ==> no answer) *****/ (<0 ==> no answer) *****/
StdAnsInd = Mch_GetQstAnsFromDB (Match->MchCod, Mch_GetQstAnsFromDB (Match->MchCod,
Gbl.Usrs.Me.UsrDat.UsrCod, Gbl.Usrs.Me.UsrDat.UsrCod,
Match->Status.QstInd); Match->Status.QstInd,
&UsrAnswer);
/***** Get number of options in this question *****/ /***** Get number of options in this question *****/
NumOptions = Tst_GetNumAnswersQst (Match->Status.QstCod); NumOptions = Tst_GetNumAnswersQst (Match->Status.QstCod);
/***** Get answers of question from database *****/
Shuffle = false;
NumOptions = Tst_GetAnswersQst (Match->Status.QstCod,&mysql_res,Shuffle);
/*
row[0] AnsInd
row[1] Answer
row[2] Feedback
row[3] MedCod
row[4] Correct
*/
/***** Start table *****/ /***** Start table *****/
Tbl_StartTableWide (8); Tbl_StartTableWide (8);
@ -2055,24 +2082,7 @@ static void Mch_ShowQuestionAndAnswersStd (struct Match *Match)
NumOpt < NumOptions; NumOpt < NumOptions;
NumOpt++) NumOpt++)
{ {
/***** Get next answer *****/
row = mysql_fetch_row (mysql_res);
/***** Assign index (row[0]).
Index is 0,1,2,3... if no shuffle
or 1,3,0,2... (example) if shuffle *****/
if (sscanf (row[0],"%u",&Index) == 1)
{
if (Index >= Tst_MAX_OPTIONS_PER_QUESTION)
ErrorInIndex = true;
}
else
ErrorInIndex = true;
if (ErrorInIndex)
Lay_ShowErrorAndExit ("Wrong index of answer when showing a test.");
/***** Start row *****/ /***** Start row *****/
// if (NumOpt % 2 == 0)
fprintf (Gbl.F.Out,"<tr>"); fprintf (Gbl.F.Out,"<tr>");
/***** Write letter for this option *****/ /***** Write letter for this option *****/
@ -2086,12 +2096,12 @@ static void Mch_ShowQuestionAndAnswersStd (struct Match *Match)
Frm_StartForm (ActAnsMchQstStd); Frm_StartForm (ActAnsMchQstStd);
Mch_PutParamMchCod (Match->MchCod); // Current match being played Mch_PutParamMchCod (Match->MchCod); // Current match being played
Gam_PutParamQstInd (Match->Status.QstInd); // Current question index shown Gam_PutParamQstInd (Match->Status.QstInd); // Current question index shown
Mch_PutParamAnswer (Index); // Index for this option Mch_PutParamNumOpt (NumOpt); // Number of button
fprintf (Gbl.F.Out,"<button type=\"submit\"" fprintf (Gbl.F.Out,"<button type=\"submit\""
" onmousedown=\"document.getElementById('%s').submit();" " onmousedown=\"document.getElementById('%s').submit();"
"return false;\" class=\"", "return false;\" class=\"",
Gbl.Form.Id); Gbl.Form.Id);
if (StdAnsInd == (int) NumOpt) // Student's answer if (UsrAnswer.NumOpt == (int) NumOpt) // Student's answer
fprintf (Gbl.F.Out,"MATCH_STD_ANSWER_SELECTED "); fprintf (Gbl.F.Out,"MATCH_STD_ANSWER_SELECTED ");
fprintf (Gbl.F.Out,"MATCH_STD_BUTTON BT_%c\">" fprintf (Gbl.F.Out,"MATCH_STD_BUTTON BT_%c\">"
"%c" "%c"
@ -2104,7 +2114,6 @@ static void Mch_ShowQuestionAndAnswersStd (struct Match *Match)
fprintf (Gbl.F.Out,"</td>"); fprintf (Gbl.F.Out,"</td>");
/***** End row *****/ /***** End row *****/
// if (NumOpt % 2 == 1)
fprintf (Gbl.F.Out,"</tr>"); fprintf (Gbl.F.Out,"</tr>");
} }
@ -2116,29 +2125,28 @@ static void Mch_ShowQuestionAndAnswersStd (struct Match *Match)
} }
} }
/*****************************************************************************/ /*****************************************************************************/
/******************* Write parameter with student's answer *******************/ /****** Write parameter with number of option (button) pressed by user *******/
/*****************************************************************************/ /*****************************************************************************/
static void Mch_PutParamAnswer (unsigned AnsInd) static void Mch_PutParamNumOpt (unsigned NumOpt)
{ {
Par_PutHiddenParamUnsigned ("Ans",AnsInd); Par_PutHiddenParamUnsigned ("NumOpt",NumOpt);
} }
/*****************************************************************************/ /*****************************************************************************/
/******************* Get parameter with student's answer *********************/ /******* Get parameter with number of option (button) pressed by user ********/
/*****************************************************************************/ /*****************************************************************************/
static unsigned Mch_GetParamAnswer (void) static unsigned Mch_GetParamNumOpt (void)
{ {
long LongNum; long NumOpt;
LongNum = Par_GetParToLong ("Ans"); NumOpt = Par_GetParToLong ("NumOpt");
if (LongNum < 0) if (NumOpt < 0)
Lay_ShowErrorAndExit ("Wrong answer index."); Lay_ShowErrorAndExit ("Wrong number of option.");
return (unsigned) LongNum; return (unsigned) NumOpt;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -2384,32 +2392,41 @@ void Mch_RefreshMatchStd (void)
/**** Receive previous question answer in a match question from database *****/ /**** Receive previous question answer in a match question from database *****/
/*****************************************************************************/ /*****************************************************************************/
static int Mch_GetQstAnsFromDB (long MchCod,long UsrCod,unsigned QstInd) static void Mch_GetQstAnsFromDB (long MchCod,long UsrCod,unsigned QstInd,
struct Mch_UsrAnswer *UsrAnswer)
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
unsigned NumRows; unsigned NumRows;
int AnsInd = -1; // <0 ==> no answer selected
/***** Set default values for number of option and answer index *****/
UsrAnswer->NumOpt = -1; // < 0 ==> no answer selected
UsrAnswer->AnsInd = -1; // < 0 ==> no answer selected
/***** Get student's answer *****/ /***** Get student's answer *****/
NumRows = (unsigned) DB_QuerySELECT (&mysql_res,"can not get student's answer to a match question", NumRows = (unsigned) DB_QuerySELECT (&mysql_res,"can not get user's answer to a match question",
"SELECT AnsInd FROM mch_answers" "SELECT NumOpt," // row[0]
"AnsInd" // row[1]
" FROM mch_answers"
" WHERE MchCod=%ld" " WHERE MchCod=%ld"
" AND UsrCod=%ld" " AND UsrCod=%ld"
" AND QstInd=%u", " AND QstInd=%u",
MchCod,UsrCod,QstInd); MchCod,UsrCod,QstInd);
if (NumRows) // Answer found... if (NumRows) // Answer found...
{ {
/***** Get answer index *****/
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
if (sscanf (row[0],"%d",&AnsInd) != 1)
/***** Get number of option index (row[0]) *****/
if (sscanf (row[0],"%d",&(UsrAnswer->NumOpt)) != 1)
Lay_ShowErrorAndExit ("Error when getting student's answer to a match question.");
/***** Get answer index (row[1]) *****/
if (sscanf (row[1],"%d",&(UsrAnswer->AnsInd)) != 1)
Lay_ShowErrorAndExit ("Error when getting student's answer to a match question."); Lay_ShowErrorAndExit ("Error when getting student's answer to a match question.");
} }
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
return AnsInd;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -2420,8 +2437,9 @@ void Mch_ReceiveQstAnsFromStd (void)
{ {
struct Match Match; struct Match Match;
unsigned QstInd; unsigned QstInd;
unsigned StdAnsInd; unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION];
int PreviousStdAnsInd; struct Mch_UsrAnswer PreviousUsrAnswer;
struct Mch_UsrAnswer UsrAnswer;
unsigned NumQsts; unsigned NumQsts;
unsigned NumQstsNotBlank; unsigned NumQstsNotBlank;
double TotalScore; double TotalScore;
@ -2437,39 +2455,53 @@ void Mch_ReceiveQstAnsFromStd (void)
/***** Get question index from form *****/ /***** Get question index from form *****/
QstInd = Gam_GetParamQstInd (); QstInd = Gam_GetParamQstInd ();
/***** Get indexes for this question from database *****/
Mch_GetIndexes (Match.MchCod,QstInd,Indexes);
/***** Check that question index is the current one being played *****/ /***** Check that question index is the current one being played *****/
if (QstInd == Match.Status.QstInd) // Receiving an answer if (QstInd == Match.Status.QstInd) // Receiving an answer
// to the current question being played // to the current question being played
{ {
/***** Get answer index *****/ /***** Get answer index *****/
/*-------+--------------+ /*
| Button | Answer index | Indexes[4] = {0,3,1,2}
+--------+--------------+ +-------+--------+----------+---------+
| a | 0 | | Button | Option | Answer | Correct |
| b | 1 | | letter | number | index | |
| c | 2 | | screen | screen | database | |
| d | 3 | +--------+--------+----------+---------+
| ... | ... | | a | 0 | 0 | |
+--------+-------------*/ | b | 1 | 3 | |
StdAnsInd = Mch_GetParamAnswer (); | c | 2 | 1 | Y | <---- User press button #2 (index = 1, correct)
| d | 3 | 2 | |
+--------+--------+----------+---------+
UsrAnswer.NumOpt = 2
UsrAnswer.AnsInd = 1
*/
UsrAnswer.NumOpt = Mch_GetParamNumOpt ();
UsrAnswer.AnsInd = Indexes[UsrAnswer.NumOpt];
/***** Get previous student's answer to this question /***** Get previous student's answer to this question
(<0 ==> no answer) *****/ (<0 ==> no answer) *****/
PreviousStdAnsInd = Mch_GetQstAnsFromDB (Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,QstInd); Mch_GetQstAnsFromDB (Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,QstInd,
&PreviousUsrAnswer);
/***** Store student's answer *****/ /***** Store student's answer *****/
if (PreviousStdAnsInd == (int) StdAnsInd) if (PreviousUsrAnswer.AnsInd == UsrAnswer.AnsInd)
DB_QueryDELETE ("can not register your answer to the match question", DB_QueryDELETE ("can not remove your answer to the match question",
"DELETE FROM mch_answers" "DELETE FROM mch_answers"
" WHERE MchCod=%ld AND UsrCod=%ld AND QstInd=%u", " WHERE MchCod=%ld AND UsrCod=%ld AND QstInd=%u",
Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,QstInd); Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,QstInd);
else else if (UsrAnswer.NumOpt >= 0 &&
UsrAnswer.AnsInd >= 0)
DB_QueryREPLACE ("can not register your answer to the match question", DB_QueryREPLACE ("can not register your answer to the match question",
"REPLACE mch_answers" "REPLACE mch_answers"
" (MchCod,UsrCod,QstInd,AnsInd)" " (MchCod,UsrCod,QstInd,NumOpt,AnsInd)"
" VALUES" " VALUES"
" (%ld,%ld,%u,%u)", " (%ld,%ld,%u,%d,%d)",
Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,QstInd,StdAnsInd); Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,QstInd,
UsrAnswer.NumOpt,
UsrAnswer.AnsInd);
/***** Update student's match result *****/ /***** Update student's match result *****/
NumQsts = Gam_GetNumQstsGame (Match.GamCod); NumQsts = Gam_GetNumQstsGame (Match.GamCod);
@ -2488,7 +2520,7 @@ void Mch_ReceiveQstAnsFromStd (void)
"NumQsts=%u," "NumQsts=%u,"
"NumQstsNotBlank=%u," "NumQstsNotBlank=%u,"
"Score='%lf'" "Score='%lf'"
" WHERE MchCod=%ld AND UsrCod=%ld", " WHERE MchCod=%ld AND UsrCod=%ld",
NumQsts,NumQstsNotBlank,TotalScore, NumQsts,NumQstsNotBlank,TotalScore,
Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod); Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod);
else // Result doesn't exist else // Result doesn't exist
@ -2529,7 +2561,7 @@ static void Mch_ComputeScore (struct Match *Match,unsigned NumQsts,long UsrCod,
double ScoreThisQst; double ScoreThisQst;
bool AnswerIsNotBlank; bool AnswerIsNotBlank;
long LongNum; long LongNum;
int AnsInd; struct Mch_UsrAnswer UsrAnswer;
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
bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION]; bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION];
@ -2540,11 +2572,11 @@ static void Mch_ComputeScore (struct Match *Match,unsigned NumQsts,long UsrCod,
"SELECT gam_questions.QstCod," // row[0] "SELECT gam_questions.QstCod," // row[0]
"gam_questions.QstInd," // row[1] "gam_questions.QstInd," // row[1]
"mch_indexes.Indexes" // row[2] "mch_indexes.Indexes" // row[2]
" FROM mch_matches,gam_questions,mch_questions" " FROM mch_matches,gam_questions,mch_indexes"
" WHERE mch_matches.MchCod=%ld" " WHERE mch_matches.MchCod=%ld"
" AND mch_matches.GamCod=gam_questions.GamCod" " AND mch_matches.GamCod=gam_questions.GamCod"
" AND mch_matches.MchCod=mch_indexes.MchCod" " AND mch_matches.MchCod=mch_indexes.MchCod"
" AND mch_matches.QstInd=mch_indexes.QstInd" " AND gam_questions.QstInd=mch_indexes.QstInd"
" ORDER BY gam_questions.QstInd"); " ORDER BY gam_questions.QstInd");
/***** For each question in match... *****/ /***** For each question in match... *****/
@ -2568,20 +2600,22 @@ static void Mch_ComputeScore (struct Match *Match,unsigned NumQsts,long UsrCod,
Tst_MAX_BYTES_INDEXES_ONE_QST); Tst_MAX_BYTES_INDEXES_ONE_QST);
/***** Get answers selected by user for this question *****/ /***** Get answers selected by user for this question *****/
AnsInd = Mch_GetQstAnsFromDB (Match->MchCod,UsrCod,QstInd); Mch_GetQstAnsFromDB (Match->MchCod,UsrCod,QstInd,&UsrAnswer);
if (AnsInd >= 0) // AnsInd >= 0 ==> answer selected if (UsrAnswer.AnsInd >= 0) // AnsInd >= 0 ==> answer selected
{ {
snprintf (Gbl.Test.StrAnswersOneQst[NumQst],Tst_MAX_BYTES_ANSWERS_ONE_QST + 1, snprintf (Gbl.Test.StrAnswersOneQst[NumQst],Tst_MAX_BYTES_ANSWERS_ONE_QST + 1,
"%d",AnsInd); "%d",UsrAnswer.AnsInd);
(*NumQstsNotBlank)++; (*NumQstsNotBlank)++;
} }
else // AnsInd < 0 ==> no answer selected else // AnsInd < 0 ==> no answer selected
Gbl.Test.StrAnswersOneQst[NumQst][0] = '\0'; // Empty answer Gbl.Test.StrAnswersOneQst[NumQst][0] = '\0'; // Empty answer
/***** Get indexes for this question from string *****/ /***** Get indexes for this question from string *****/
Par_ReplaceCommaBySeparatorMultiple (Gbl.Test.StrIndexesOneQst[NumQst]);
Tst_GetIndexesFromStr (Gbl.Test.StrIndexesOneQst[NumQst],Indexes); Tst_GetIndexesFromStr (Gbl.Test.StrIndexesOneQst[NumQst],Indexes);
/***** Get the user's answers for this question from string *****/ /***** Get the user's answers for this question from string *****/
Par_ReplaceCommaBySeparatorMultiple (Gbl.Test.StrAnswersOneQst[NumQst]);
Tst_GetAnswersFromStr (Gbl.Test.StrAnswersOneQst[NumQst],AnswersUsr); Tst_GetAnswersFromStr (Gbl.Test.StrAnswersOneQst[NumQst],AnswersUsr);
/***** Get correct answers of test question from database *****/ /***** Get correct answers of test question from database *****/
@ -3486,7 +3520,7 @@ static void Mch_GetMatchResultQuestionsFromDB (long MchCod,long UsrCod)
unsigned NumQst; unsigned NumQst;
long LongNum; long LongNum;
unsigned QstInd; unsigned QstInd;
int AnsInd; struct Mch_UsrAnswer UsrAnswer;
/***** Get questions and answers of a match result *****/ /***** Get questions and answers of a match result *****/
NumQsts = (unsigned) NumQsts = (unsigned)
@ -3521,11 +3555,11 @@ static void Mch_GetMatchResultQuestionsFromDB (long MchCod,long UsrCod)
Tst_MAX_BYTES_INDEXES_ONE_QST); Tst_MAX_BYTES_INDEXES_ONE_QST);
/* Get answers selected by user for this question */ /* Get answers selected by user for this question */
AnsInd = Mch_GetQstAnsFromDB (MchCod,UsrCod,QstInd); Mch_GetQstAnsFromDB (MchCod,UsrCod,QstInd,&UsrAnswer);
if (AnsInd >= 0) // AnsInd >= 0 ==> answer selected if (UsrAnswer.AnsInd >= 0) // UsrAnswer.AnsInd >= 0 ==> answer selected
snprintf (Gbl.Test.StrAnswersOneQst[NumQst],Tst_MAX_BYTES_ANSWERS_ONE_QST + 1, snprintf (Gbl.Test.StrAnswersOneQst[NumQst],Tst_MAX_BYTES_ANSWERS_ONE_QST + 1,
"%d",AnsInd); "%d",UsrAnswer.AnsInd);
else // AnsInd < 0 ==> no answer selected else // UsrAnswer.AnsInd < 0 ==> no answer selected
Gbl.Test.StrAnswersOneQst[NumQst][0] = '\0'; // Empty answer Gbl.Test.StrAnswersOneQst[NumQst][0] = '\0'; // Empty answer
/* Replace each comma by a separator of multiple parameters */ /* Replace each comma by a separator of multiple parameters */

View File

@ -48,6 +48,8 @@ void Mch_RemoveMatchTch (void);
void Mch_CreateNewMatchTch (void); void Mch_CreateNewMatchTch (void);
void Mch_RequestStartResumeMatchTch (void); void Mch_RequestStartResumeMatchTch (void);
void Mch_GetIndexes (long MchCod,unsigned QstInd,
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]);
void Mch_PauseMatchTch (void); void Mch_PauseMatchTch (void);
void Mch_ResumeMatchTch (void); void Mch_ResumeMatchTch (void);
void Mch_ToggleDisplayResultsMatchTch (void); void Mch_ToggleDisplayResultsMatchTch (void);

View File

@ -981,9 +981,11 @@ bool Par_GetNextStrUntilSeparParamMult (const char **StrSrc,char *StrDst,size_t
do do
if ((Ch = (unsigned char) **StrSrc)) if ((Ch = (unsigned char) **StrSrc))
(*StrSrc)++; (*StrSrc)++;
while (Ch && Ch < 32); // Skip special characters (the separator will be a special character less than 32) while (Ch && Ch < 32); // Skip special characters
// (the separator will be a special character
// less than 32)
while (Ch >= 32) while (Ch >= 32) // Until special character or end
{ {
CharsFound = true; CharsFound = true;
if (i < LongMax) if (i < LongMax)

View File

@ -85,6 +85,7 @@ unsigned Par_GetParAndChangeFormat (const char *ParamName,char *ParamValue,size_
Str_ChangeTo_t ChangeTo,bool RemoveLeadingAndTrailingSpaces); Str_ChangeTo_t ChangeTo,bool RemoveLeadingAndTrailingSpaces);
bool Par_GetNextStrUntilSeparParamMult (const char **StrSrc,char *StrDst,size_t LongMax); bool Par_GetNextStrUntilSeparParamMult (const char **StrSrc,char *StrDst,size_t LongMax);
bool Par_GetNextStrUntilComma (const char **StrSrc,char *StrDst,size_t LongMax);
void Par_ReplaceSeparatorMultipleByComma (const char *StrSrc,char *StrDst); void Par_ReplaceSeparatorMultipleByComma (const char *StrSrc,char *StrDst);
void Par_ReplaceCommaBySeparatorMultiple (char *Str); void Par_ReplaceCommaBySeparatorMultiple (char *Str);

View File

@ -4017,13 +4017,22 @@ void Tst_GetIndexesFromStr (const char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ON
const char *Ptr; const char *Ptr;
char StrOneIndex[10 + 1]; char StrOneIndex[10 + 1];
/***** Initialize to 0 *****/
for (NumOpt = 0, Ptr = StrIndexesOneQst; for (NumOpt = 0, Ptr = StrIndexesOneQst;
NumOpt < Gbl.Test.Answer.NumOptions; NumOpt < Tst_MAX_OPTIONS_PER_QUESTION && *Ptr;
NumOpt++)
Indexes[NumOpt] = 0;
/***** Get indexes from string *****/
for (NumOpt = 0, Ptr = StrIndexesOneQst;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION && *Ptr;
NumOpt++) NumOpt++)
{ {
Par_GetNextStrUntilSeparParamMult (&Ptr,StrOneIndex,10); Par_GetNextStrUntilSeparParamMult (&Ptr,StrOneIndex,10);
if (sscanf (StrOneIndex,"%u",&(Indexes[NumOpt])) != 1) if (sscanf (StrOneIndex,"%u",&(Indexes[NumOpt])) != 1)
Lay_ShowErrorAndExit ("Wrong index of answer when assessing a test."); Lay_ShowErrorAndExit ("Wrong index of answer.");
if (Indexes[NumOpt] >= Tst_MAX_OPTIONS_PER_QUESTION)
Lay_ShowErrorAndExit ("Wrong index of answer.");
} }
} }
@ -4136,12 +4145,10 @@ static void Tst_WriteChoiceAnsViewMatch (long MchCod,unsigned QstInd,long QstCod
unsigned NumOpt; unsigned NumOpt;
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
unsigned AnsInd;
unsigned NumAnswerersQst; unsigned NumAnswerersQst;
bool Correct; unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question
bool ErrorInIndex = false;
/***** Get number of users who hasve answered this question from database *****/ /***** Get number of users who have answered this question from database *****/
NumAnswerersQst = Mch_GetNumUsrsWhoHaveAnswerQst (MchCod,QstInd); NumAnswerersQst = Mch_GetNumUsrsWhoHaveAnswerQst (MchCod,QstInd);
/***** Get answers of a question from database *****/ /***** Get answers of a question from database *****/
@ -4154,45 +4161,47 @@ static void Tst_WriteChoiceAnsViewMatch (long MchCod,unsigned QstInd,long QstCod
row[4] Correct row[4] Correct
*/ */
/***** Start table *****/
Tbl_StartTableWide (2);
for (NumOpt = 0; for (NumOpt = 0;
NumOpt < Gbl.Test.Answer.NumOptions; NumOpt < Gbl.Test.Answer.NumOptions;
NumOpt++) NumOpt++)
{ {
/***** Get next answer *****/ /* Get next answer */
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
/***** Allocate memory for text in this choice answer *****/ /* Allocate memory for text in this choice answer */
if (!Tst_AllocateTextChoiceAnswer (NumOpt)) if (!Tst_AllocateTextChoiceAnswer (NumOpt))
/* Abort on error */ /* Abort on error */
Ale_ShowAlertsAndExit (); Ale_ShowAlertsAndExit ();
/***** Assign index (row[0]). /* Copy text (row[1]) and convert it, that is in HTML, to rigorous HTML */
Index is 0,1,2,3... if no shuffle
or 1,3,0,2... (example) if shuffle *****/
if (sscanf (row[0],"%u",&AnsInd) == 1)
{
if (AnsInd >= Tst_MAX_OPTIONS_PER_QUESTION)
ErrorInIndex = true;
}
else
ErrorInIndex = true;
if (ErrorInIndex)
Lay_ShowErrorAndExit ("Wrong index of answer when showing a test.");
/***** Copy text (row[1]) and convert it, that is in HTML, to rigorous HTML ******/
Str_Copy (Gbl.Test.Answer.Options[NumOpt].Text,row[1], Str_Copy (Gbl.Test.Answer.Options[NumOpt].Text,row[1],
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK); Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
Gbl.Test.Answer.Options[NumOpt].Text, Gbl.Test.Answer.Options[NumOpt].Text,
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false);
/***** Get media (row[3]) *****/ /* Get media (row[3]) */
Gbl.Test.Answer.Options[NumOpt].Media.MedCod = Str_ConvertStrCodToLongCod (row[3]); Gbl.Test.Answer.Options[NumOpt].Media.MedCod = Str_ConvertStrCodToLongCod (row[3]);
Med_GetMediaDataByCod (&Gbl.Test.Answer.Options[NumOpt].Media); Med_GetMediaDataByCod (&Gbl.Test.Answer.Options[NumOpt].Media);
/* Get if correct (row[4]) */
Gbl.Test.Answer.Options[NumOpt].Correct = (row[4][0] == 'Y');
}
/* Free structure that stores the query result */
DB_FreeMySQLResult (&mysql_res);
/***** Get indexes for this question in match *****/
Mch_GetIndexes (MchCod,QstInd,Indexes);
/***** Start table *****/
Tbl_StartTableWide (2);
/***** Show one row for each option *****/
for (NumOpt = 0;
NumOpt < Gbl.Test.Answer.NumOptions;
NumOpt++)
{
/***** Start row for this option *****/ /***** Start row for this option *****/
fprintf (Gbl.F.Out,"<tr>"); fprintf (Gbl.F.Out,"<tr>");
@ -4212,22 +4221,18 @@ static void Tst_WriteChoiceAnsViewMatch (long MchCod,unsigned QstInd,long QstCod
"</label>", "</label>",
QstInd,NumOpt, QstInd,NumOpt,
Class, Class,
Gbl.Test.Answer.Options[NumOpt].Text); Gbl.Test.Answer.Options[Indexes[NumOpt]].Text);
Med_ShowMedia (&Gbl.Test.Answer.Options[NumOpt].Media, Med_ShowMedia (&Gbl.Test.Answer.Options[Indexes[NumOpt]].Media,
"TEST_MED_SHOW_CONTAINER", "TEST_MED_SHOW_CONTAINER",
"TEST_MED_SHOW"); "TEST_MED_SHOW");
/* Show result (number of users who answered? */ /* Show result (number of users who answered? */
if (ShowResult) if (ShowResult)
{
/* Get if correct (row[4]) */
Correct = (row[4][0] == 'Y');
/* Get number of users who selected this answer /* Get number of users who selected this answer
and draw proportional bar */ and draw proportional bar */
Mch_GetAndDrawBarNumUsrsWhoHaveChosenAns (MchCod,QstInd,AnsInd, Mch_GetAndDrawBarNumUsrsWhoHaveChosenAns (MchCod,QstInd,Indexes[NumOpt],
NumAnswerersQst,Correct); NumAnswerersQst,
} Gbl.Test.Answer.Options[Indexes[NumOpt]].Correct);
fprintf (Gbl.F.Out,"</td>"); fprintf (Gbl.F.Out,"</td>");
@ -4237,9 +4242,6 @@ static void Tst_WriteChoiceAnsViewMatch (long MchCod,unsigned QstInd,long QstCod
/***** End table *****/ /***** End table *****/
Tbl_EndTable (); Tbl_EndTable ();
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
} }
/*****************************************************************************/ /*****************************************************************************/