diff --git a/sql/swad.sql b/sql/swad.sql index 848acdd1..1f69733c 100644 --- a/sql/swad.sql +++ b/sql/swad.sql @@ -587,10 +587,11 @@ CREATE TABLE IF NOT EXISTS games ( -- Table gam_answers: stores the answers to the games -- CREATE TABLE IF NOT EXISTS gam_answers ( + GamCod INT NOT NULL, QstCod INT NOT NULL, AnsInd TINYINT NOT NULL, NumUsrs INT NOT NULL DEFAULT 0, - UNIQUE INDEX(QstCod,AnsInd)); + UNIQUE INDEX(GamCod,QstCod,AnsInd)); -- -- Table gam_grp: stores the groups associated to each game -- diff --git a/swad_changelog.h b/swad_changelog.h index b144f2be..504bbda6 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -238,19 +238,24 @@ /****************************** Public constants *****************************/ /*****************************************************************************/ -#define Log_PLATFORM_VERSION "SWAD 16.251.9 (2017-09-06)" +#define Log_PLATFORM_VERSION "SWAD 16.251.10 (2017-09-06)" #define CSS_FILE "swad16.251.8.css" #define JS_FILE "swad16.206.3.js" // Number of lines (includes comments but not blank lines) has been got with the following command: // nl swad*.c swad*.h css/swad*.css py/swad*.py js/swad*.js soap/swad*?.h sql/swad*.sql | tail -1 /* + Version 16.251.10:Sep 06, 2017 Listing games for remote control. Not finished. (226913 lines) + 2 changes necessary in database: +DROP TABLE IF EXISTS gam_answers; +CREATE TABLE IF NOT EXISTS gam_answers (GamCod INT NOT NULL,QstCod INT NOT NULL,AnsInd TINYINT NOT NULL,NumUsrs INT NOT NULL DEFAULT 0,UNIQUE INDEX(GamCod,QstCod,AnsInd)); + Version 16.251.9: Sep 06, 2017 Listing games for remote control. Not finished. (227273 lines) Version 16.251.8: Sep 06, 2017 Listing games for remote control. Not finished. (227211 lines) Version 16.251.7: Sep 04, 2017 Listing games for remote control. Not finished. (227218 lines) Version 16.251.6: Sep 01, 2017 Listing games for remote control. Not finished. (227111 lines) Version 16.251.5: Sep 01, 2017 Listing games for remote control. Not finished. (227045 lines) - 1 change necessary in database: + 2 changes necessary in database: ALTER TABLE gam_answers DROP COLUMN Answer; UPDATE actions SET Obsolete='Y' WHERE ActCod='1663'; diff --git a/swad_database.c b/swad_database.c index c6231581..e166572d 100644 --- a/swad_database.c +++ b/swad_database.c @@ -1278,17 +1278,19 @@ mysql> DESCRIBE gam_answers; +---------+------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+------------+------+-----+---------+-------+ +| GamCod | int(11) | NO | PRI | NULL | | | QstCod | int(11) | NO | PRI | NULL | | | AnsInd | tinyint(4) | NO | PRI | NULL | | | NumUsrs | int(11) | NO | | 0 | | +---------+------------+------+-----+---------+-------+ -3 rows in set (0,00 sec) +4 rows in set (0,00 sec) */ DB_CreateTable ("CREATE TABLE IF NOT EXISTS gam_answers (" + "GamCod INT NOT NULL," "QstCod INT NOT NULL," "AnsInd TINYINT NOT NULL," "NumUsrs INT NOT NULL DEFAULT 0," - "UNIQUE INDEX(QstCod,AnsInd))"); + "UNIQUE INDEX(GamCod,QstCod,AnsInd))"); /***** Table gam_grp *****/ /* diff --git a/swad_remote_control.c b/swad_remote_control.c index cea5d0ad..e6aee10b 100644 --- a/swad_remote_control.c +++ b/swad_remote_control.c @@ -136,11 +136,6 @@ static void Rmt_InitQst (struct GameQuestion *GameQst); static void Rmt_PutParamQstCod (long QstCod); static long Rmt_GetParamQstCod (void); static void Rmt_RemAnswersOfAQuestion (long QstCod); -// static Rmt_AnswerType_t Rmt_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeBD); -// static bool Rmt_CheckIfAnswerExists (long QstCod,unsigned AnsInd); -// static bool Rmt_AllocateTextChoiceAnswer (struct GameQuestion *GameQst,unsigned NumAns); -// static void Rmt_FreeTextChoiceAnswers (struct GameQuestion *GameQst,unsigned NumAnswers); -// static void Rmt_FreeTextChoiceAnswer (struct GameQuestion *GameQst,unsigned NumAns); static unsigned Rmt_GetQstIndFromQstCod (long QstCod); static unsigned Rmt_GetNextQuestionIndexInGame (long GamCod); @@ -156,9 +151,7 @@ static void Rmt_AllocateListSelectedQuestions (void); static void Rmt_FreeListsSelectedQuestions (void); static unsigned Rmt_CountNumQuestionsInList (void); -// static void Rmt_WriteQstStem (const char *Stem); -static void Rmt_WriteAnswersOfAQst (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions, - struct Game *Game,struct GameQuestion *GameQst); +static unsigned Rmt_GetNumUsrsWhoAnswered (long GamCod,long QstCod,unsigned AnsInd); static void Rmt_DrawBarNumUsrs (unsigned NumUsrs,unsigned MaxUsrs); // static void Rmt_PutIconToRemoveOneQst (void); @@ -2629,273 +2622,6 @@ static void Rmt_RemAnswersOfAQuestion (long QstCod) DB_QueryDELETE (Query,"can not remove the answers of a question"); } -/*****************************************************************************/ -/*********** Convert a string with the answer type to answer type ************/ -/*****************************************************************************/ -/* -static Rmt_AnswerType_t Rmt_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeBD) - { - Rmt_AnswerType_t AnsType; - - for (AnsType = (Rmt_AnswerType_t) 0; - AnsType < Rmt_NUM_ANS_TYPES; - AnsType++) - if (!strcmp (StrAnsTypeBD,Rmt_StrAnswerTypesDB[AnsType])) - return AnsType; - - return (Rmt_AnswerType_t) 0; - } -*/ -/*****************************************************************************/ -/*********** Check if an answer of a question exists in database *************/ -/*****************************************************************************/ -/* -static bool Rmt_CheckIfAnswerExists (long QstCod,unsigned AnsInd) - { - char Query[256]; - - ***** Get answers of a question from database ***** - sprintf (Query,"SELECT COUNT(*) FROM gam_answers" - " WHERE QstCod=%ld AND AnsInd=%u", - QstCod,AnsInd); - return (DB_QueryCOUNT (Query,"can not check if an answer exists") != 0); - } -*/ -/*****************************************************************************/ -/**** Get number of users who selected a given answer of a game question *****/ -/*****************************************************************************/ - -unsigned Rmt_GetNumUsrsWhoAnswered (long GamCod,long QstCod,unsigned AnsInd) - { - char Query[128]; - MYSQL_RES *mysql_res; - MYSQL_ROW row; - unsigned NumUsrs = 0; // Default returned value - - /***** Get answers of a question from database *****/ - sprintf (Query,"SELECT NumUsrs FROM gam_answers" - " WHERE GamCod=%ld AND QstCod=%ld AND AnsInd=%u", - GamCod,QstCod,AnsInd); - DB_QuerySELECT (Query,&mysql_res,"can not get number of users who answered"); - row = mysql_fetch_row (mysql_res); - if (row[0]) // There are users who selected this answer - if (sscanf (row[0],"%u",&NumUsrs) != 1) - Lay_ShowErrorAndExit ("Error when getting number of users who answered."); - - return NumUsrs; - } - -/*****************************************************************************/ -/******************* Allocate memory for a choice answer *********************/ -/*****************************************************************************/ -/* -static bool Rmt_AllocateTextChoiceAnswer (struct GameQuestion *GameQst,unsigned NumAns) - { - Rmt_FreeTextChoiceAnswer (GameQst,NumAns); - if ((GameQst->AnsChoice[NumAns].Text = malloc (Rmt_MAX_BYTES_ANSWER + 1)) == NULL) - { - sprintf (Gbl.Alert.Txt,"Not enough memory to store answer."); - return false; - } - GameQst->AnsChoice[NumAns].Text[0] = '\0'; - return true; - } -*/ -/*****************************************************************************/ -/******************** Free memory of all choice answers **********************/ -/*****************************************************************************/ -/* -static void Rmt_FreeTextChoiceAnswers (struct GameQuestion *GameQst,unsigned NumAnswers) - { - unsigned NumAns; - - for (NumAns = 0; - NumAns < NumAnswers; - NumAns++) - Rmt_FreeTextChoiceAnswer (GameQst,NumAns); - } -*/ -/*****************************************************************************/ -/********************** Free memory of a choice answer ***********************/ -/*****************************************************************************/ -/* -static void Rmt_FreeTextChoiceAnswer (struct GameQuestion *GameQst,unsigned NumAns) - { - if (GameQst->AnsChoice[NumAns].Text) - { - free ((void *) GameQst->AnsChoice[NumAns].Text); - GameQst->AnsChoice[NumAns].Text = NULL; - } - } -*/ -/*****************************************************************************/ -/************************ Receive a question of a game ***********************/ -/*****************************************************************************/ -/* -void Rmt_ReceiveQst (void) - { - extern const char *Txt_You_must_type_the_stem_of_the_question; - extern const char *Txt_You_can_not_leave_empty_intermediate_answers; - extern const char *Txt_You_must_type_at_least_the_first_two_answers; - extern const char *Txt_The_game_has_been_modified; - char Txt[Cns_MAX_BYTES_TEXT + 1]; - char Query[512 + Cns_MAX_BYTES_TEXT]; - struct Game Game; - struct GameQuestion GameQst; - unsigned NumAns; - char AnsStr[8 + 10 + 1]; - unsigned NumLastAns; - bool ThereIsEndOfAnswers; - bool Error = false; - - ***** Initialize new question to zero ***** - Rmt_InitQst (&GameQst); - - ***** Get parameters from form ***** - * Get game code * - if ((Game.GamCod = Rmt_GetParamGameCod ()) == -1L) - Lay_ShowErrorAndExit ("Code of game is missing."); - - * Get question code * - GameQst.QstCod = Rmt_GetParamQstCod (); - - * Get answer type * - GameQst.AnswerType = (Rmt_AnswerType_t) - Par_GetParToUnsignedLong ("AnswerType", - 0, - Rmt_NUM_ANS_TYPES - 1, - (unsigned long) Rmt_ANSWER_TYPE_DEFAULT); - - * Get question text * - Par_GetParToHTML ("Txt",Txt,Cns_MAX_BYTES_TEXT); - - * Get the texts of the answers * - for (NumAns = 0; - NumAns < Rmt_MAX_ANSWERS_PER_QUESTION; - NumAns++) - { - if (!Rmt_AllocateTextChoiceAnswer (&GameQst,NumAns)) - Lay_ShowErrorAndExit (Gbl.Alert.Txt); - sprintf (AnsStr,"AnsStr%u",NumAns); - Par_GetParToHTML (AnsStr,GameQst.AnsChoice[NumAns].Text,Rmt_MAX_BYTES_ANSWER); - } - - ***** Make sure that stem and answer are not empty ***** - if (Txt[0]) - { - if (GameQst.AnsChoice[0].Text[0]) // If the first answer has been filled - { - for (NumAns = 0, NumLastAns = 0, ThereIsEndOfAnswers = false; - !Error && NumAns < Rmt_MAX_ANSWERS_PER_QUESTION; - NumAns++) - if (GameQst.AnsChoice[NumAns].Text[0]) - { - if (ThereIsEndOfAnswers) - { - Ale_ShowAlert (Ale_WARNING,Txt_You_can_not_leave_empty_intermediate_answers); - Error = true; - } - else - NumLastAns = NumAns; - } - else - ThereIsEndOfAnswers = true; - if (!Error) - { - if (NumLastAns < 1) - { - Ale_ShowAlert (Ale_WARNING,Txt_You_must_type_at_least_the_first_two_answers); - Error = true; - } - } - } - else // If first answer is empty - { - Ale_ShowAlert (Ale_WARNING,Txt_You_must_type_at_least_the_first_two_answers); - Error = true; - } - } - else - { - Ale_ShowAlert (Ale_WARNING,Txt_You_must_type_the_stem_of_the_question); - Error = true; - } - - if (Error) - Tst_ShowFormAskSelectTstsForGame (Game.GamCod); - else - { - ***** Form is received OK ==> insert question and answer in the database ***** - if (GameQst.QstCod < 0) // It's a new question - { - GameQst.QstInd = Rmt_GetNextQuestionIndexInGame (Game.GamCod); - - * Insert question in the table of questions * - sprintf (Query,"INSERT INTO gam_questions" - " (GamCod,QstInd,AnsType,Stem)" - " VALUES" - " (%ld,%u,'%s','%s')", - Game.GamCod,GameQst.QstInd,Rmt_StrAnswerTypesDB[GameQst.AnswerType],Txt); - GameQst.QstCod = DB_QueryINSERTandReturnCode (Query,"can not create question"); - } - else // It's an existing question - { - * Update question * - sprintf (Query,"UPDATE gam_questions SET Stem='%s',AnsType='%s'" - " WHERE QstCod=%ld AND GamCod=%ld", - Txt,Rmt_StrAnswerTypesDB[GameQst.AnswerType], - GameQst.QstCod,Game.GamCod); - DB_QueryUPDATE (Query,"can not update question"); - } - - * Insert, update or delete answers in the answers table * - for (NumAns = 0; - NumAns < Rmt_MAX_ANSWERS_PER_QUESTION; - NumAns++) - if (Rmt_CheckIfAnswerExists (GameQst.QstCod,NumAns)) // If this answer exists... - { - if (GameQst.AnsChoice[NumAns].Text[0]) // Answer is not empty - { - * Update answer text * - sprintf (Query,"UPDATE gam_answers SET Answer='%s'" - " WHERE QstCod=%ld AND AnsInd=%u", - GameQst.AnsChoice[NumAns].Text,GameQst.QstCod,NumAns); - DB_QueryUPDATE (Query,"can not update answer"); - } - else // Answer is empty - { - * Delete answer from database * - sprintf (Query,"DELETE FROM gam_answers" - " WHERE QstCod=%ld AND AnsInd=%u", - GameQst.QstCod,NumAns); - DB_QueryDELETE (Query,"can not delete answer"); - } - } - else // If this answer does not exist... - { - if (GameQst.AnsChoice[NumAns].Text[0]) // Answer is not empty - { - * Create answer into database * - sprintf (Query,"INSERT INTO gam_answers" - " (QstCod,AnsInd,NumUsrs,Answer)" - " VALUES" - " (%ld,%u,0,'%s')", - GameQst.QstCod,NumAns,GameQst.AnsChoice[NumAns].Text); - DB_QueryINSERT (Query,"can not create answer"); - } - } - - ***** List the questions of this game, including the new one just inserted into the database ***** - Ale_ShowAlert (Ale_SUCCESS,Txt_The_game_has_been_modified); - } - - ***** Free answers ***** - Rmt_FreeTextChoiceAnswers (&GameQst,Rmt_MAX_ANSWERS_PER_QUESTION); - - ***** Show current game ***** - Rmt_ShowOneGame (Game.GamCod,&GameQst,true); - } -*/ /*****************************************************************************/ /******************** Get next question index in a game **********************/ /*****************************************************************************/ @@ -3117,14 +2843,12 @@ static void Rmt_ListOneOrMoreQuestionsForEdition (struct Game *Game, Act_FormStart (ActReqRemGamQst); Rmt_PutParamGameCod (Game->GamCod); Rmt_PutParamQstCod (GameQst->QstCod); - // Tst_PutParamQstCod (); Ico_PutIconRemove (); Act_FormEnd (); /* Write icon to edit the question */ Act_FormStart (ActEdiOneTstQst); Rmt_PutParamQstCod (GameQst->QstCod); - // Tst_PutParamQstCod (); fprintf (Gbl.F.Out,"", @@ -3169,8 +2893,8 @@ static void Rmt_ListOneOrMoreQuestionsForEdition (struct Game *Game, "TEST_IMG_EDIT_LIST_STEM_CONTAINER", "TEST_IMG_EDIT_LIST_STEM"); Tst_WriteQstFeedback (row[3],"TEST_EDI_LIGHT"); - // Tst_WriteAnswersEdit (Gbl.Test.QstCod); - Rmt_WriteAnswersOfAQst (Tst_SHOW_GAME_RESULT,Game,GameQst); + Tst_WriteAnswersGameResult (Game,GameQst->QstInd,GameQst->QstCod); + fprintf (Gbl.F.Out,"" ""); @@ -3326,183 +3050,45 @@ static unsigned Rmt_CountNumQuestionsInList (void) } /*****************************************************************************/ -/****************** Write the heading of a game question *******************/ +/*** Get number of users who selected this answer and draw proportional bar **/ /*****************************************************************************/ -/* -static void Rmt_WriteQstStem (const char *Stem) + +void Rmt_GetAndDrawBarNumUsrsWhoAnswered (struct Game *Game,long QstCod,unsigned AnsInd) { - char *HeadingRigorousHTML; - size_t Length; - - * Convert the stem, that is in HTML, to rigorous HTML * - Length = strlen (Stem) * Str_MAX_BYTES_PER_CHAR; - if ((HeadingRigorousHTML = malloc (Length + 1)) == NULL) - Lay_ShowErrorAndExit ("Not enough memory to store stem of question."); - Str_Copy (HeadingRigorousHTML,Stem, - Length); - Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, - HeadingRigorousHTML,Length,false); - - * Write the stem * - fprintf (Gbl.F.Out,"%s",HeadingRigorousHTML); - - * Free memory allocated for the stem * - free ((void *) HeadingRigorousHTML); - } -*/ -/*****************************************************************************/ -/************** Get and write the answers of a game question ***************/ -/*****************************************************************************/ - -static void Rmt_WriteAnswersOfAQst (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions, - struct Game *Game,struct GameQuestion *GameQst) - { - extern const char *Txt_Question_removed; - MYSQL_RES *mysql_res; - MYSQL_ROW row; - double ScoreThisQst; - bool AnswerIsNotBlank; - - /***** Query database *****/ - if (Tst_GetOneQuestionByCod (GameQst->QstCod,&mysql_res)) // Question exists - { - /***** Get row of the result of the query *****/ - row = mysql_fetch_row (mysql_res); - /* - row[ 0] QstCod - row[ 1] UNIX_TIMESTAMP(EditTime) - row[ 2] AnsType - row[ 3] Shuffle - row[ 4] Stem - row[ 5] Feedback - row[ 6] ImageName - row[ 7] ImageTitle - row[ 8] ImageURL - row[ 9] NumHits - row[10] NumHitsNotBlank - row[11] Score - */ - - /***** Write question and answers *****/ - Gbl.Games.CurrentGamCod = Game->GamCod; - Tst_WriteQstAndAnsTest (ActionToDoWithQuestions, - GameQst->QstInd,GameQst->QstCod,row, - &ScoreThisQst,&AnswerIsNotBlank); - } - else - /***** Question does not exists *****/ - fprintf (Gbl.F.Out,"" - "" - "%u" - "" - "" - "%s" - "" - "", - Gbl.RowEvenOdd,GameQst->QstInd + 1, - Gbl.RowEvenOdd,Txt_Question_removed); - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - - -/* - - - - - - - - - unsigned NumAnswers; - unsigned NumAns; - MYSQL_RES *mysql_res; - MYSQL_ROW row; unsigned NumUsrsThisAnswer; - ***** Get answers of this question ***** - NumAnswers = Rmt_GetNumUsrsWhoAnswered (GameQst->QstCod,&mysql_res); // Result: AnsInd,NumUsrs,Answer + /***** Get number of users who selected this answer *****/ + NumUsrsThisAnswer = Rmt_GetNumUsrsWhoAnswered (Game->GamCod,QstCod,AnsInd); - ***** Write the answers ***** - if (NumAnswers) + /***** Show stats of this answer *****/ + if (Game->Status.ICanViewResults) + Rmt_DrawBarNumUsrs (NumUsrsThisAnswer,Game->NumUsrs); + } + +/*****************************************************************************/ +/**** Get number of users who selected a given answer of a game question *****/ +/*****************************************************************************/ + +static unsigned Rmt_GetNumUsrsWhoAnswered (long GamCod,long QstCod,unsigned AnsInd) + { + char Query[256]; + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned NumUsrs = 0; // Default returned value + + /***** Get answers of a question from database *****/ + sprintf (Query,"SELECT NumUsrs FROM gam_answers" + " WHERE GamCod=%ld AND QstCod=%ld AND AnsInd=%u", + GamCod,QstCod,AnsInd); + if (DB_QuerySELECT (Query,&mysql_res,"can not get number of users who answered")) { - * Check number of answers * - if (NumAnswers > Rmt_MAX_ANSWERS_PER_QUESTION) - Lay_ShowErrorAndExit ("Wrong number of answers."); - - * Write one row for each answer * - Tbl_StartTable (5); - for (NumAns = 0; - NumAns < NumAnswers; - NumAns++) - { - row = mysql_fetch_row (mysql_res); - - * Get number of users who have marked this answer (row[1]) * - if (sscanf (row[1],"%u",&NumUsrsThisAnswer) != 1) - Lay_ShowErrorAndExit ("Error when getting number of users who have marked an answer."); - - * Convert the answer (row[2]), that is in HTML, to rigorous HTML * - if (!Rmt_AllocateTextChoiceAnswer (GameQst,NumAns)) - Lay_ShowErrorAndExit (Gbl.Alert.Txt); - Str_Copy (GameQst->AnsChoice[NumAns].Text,row[2], - Rmt_MAX_BYTES_ANSWER); - Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, - GameQst->AnsChoice[NumAns].Text,Rmt_MAX_BYTES_ANSWER,false); - - * Selectors and label with the letter of the answer * - fprintf (Gbl.F.Out,""); - - if (PutFormAnswerGame) - { - * Write selector to choice this answer * - fprintf (Gbl.F.Out,"" - "AnswerType == Rmt_ANS_UNIQUE_CHOICE) - fprintf (Gbl.F.Out,"radio\"" - " onclick=\"selectUnselectRadio(this,this.form.Ans%010u,%u)\"", - (unsigned) GameQst->QstCod,NumAnswers); - else // GameQst->AnswerType == Rmt_ANS_MULTIPLE_CHOICE - fprintf (Gbl.F.Out,"checkbox\""); - fprintf (Gbl.F.Out," id=\"Ans%010u_%010u\" name=\"Ans%010u\"" - " value=\"%u\" />" - "", - (unsigned) GameQst->QstCod,NumAns,(unsigned) GameQst->QstCod, - NumAns); - } - - * Write the number of option * - fprintf (Gbl.F.Out,"" - "" - "", - (unsigned) GameQst->QstCod,NumAns,NumAns + 1); - - * Write the text of the answer * - fprintf (Gbl.F.Out,"" - "" - "", - (unsigned) GameQst->QstCod,NumAns, - GameQst->AnsChoice[NumAns].Text); - - * Show stats of this answer * - if (Game->Status.ICanViewResults) - Rmt_DrawBarNumUsrs (NumUsrsThisAnswer,Game->NumUsrs); - - fprintf (Gbl.F.Out,""); - - * Free memory allocated for the answer * - Rmt_FreeTextChoiceAnswer (GameQst,NumAns); - } - Tbl_EndTable (); + row = mysql_fetch_row (mysql_res); + if (row[0]) // There are users who selected this answer + if (sscanf (row[0],"%u",&NumUsrs) != 1) + Lay_ShowErrorAndExit ("Error when getting number of users who answered."); } - ***** Free structure that stores the query result ***** - DB_FreeMySQLResult (&mysql_res); -*/ + return NumUsrs; } /*****************************************************************************/ @@ -3545,9 +3131,7 @@ static void Rmt_DrawBarNumUsrs (unsigned NumUsrs,unsigned MaxUsrs) BarWidth); /***** Write the number of users *****/ - fprintf (Gbl.F.Out,"%s" - "", - Gbl.Title); + fprintf (Gbl.F.Out,"%s",Gbl.Title); } /*****************************************************************************/ diff --git a/swad_remote_control.h b/swad_remote_control.h index 3f11b3e1..f65cfeb5 100644 --- a/swad_remote_control.h +++ b/swad_remote_control.h @@ -113,7 +113,7 @@ void Rmt_RemoveGames (Sco_Scope_t Scope,long Cod); void Rmt_RequestEditQuestion (void); // void Rmt_ReceiveQst (void); -unsigned Rmt_GetNumUsrsWhoAnswered (long GamCod,long QstCod,unsigned AnsInd); +void Rmt_GetAndDrawBarNumUsrsWhoAnswered (struct Game *Game,long QstCod,unsigned AnsInd); void Rmt_AddTstQuestionsToGame (void); diff --git a/swad_test.c b/swad_test.c index 034d798b..eef7aaff 100644 --- a/swad_test.c +++ b/swad_test.c @@ -194,7 +194,6 @@ static void Tst_WriteAnswersEdit (long QstCod); static void Tst_WriteAnswersTestToAnswer (unsigned NumQst,long QstCod,bool Shuffle); static void Tst_WriteAnswersTestResult (unsigned NumQst,long QstCod, double *ScoreThisQst,bool *AnswerIsNotBlank); -static void Tst_WriteAnswersGameResult (unsigned NumQst,long QstCod); static void Tst_WriteTFAnsViewTest (unsigned NumQst); static void Tst_WriteTFAnsAssessTest (unsigned NumQst,MYSQL_RES *mysql_res, @@ -203,7 +202,7 @@ static void Tst_WriteTFAnsAssessTest (unsigned NumQst,MYSQL_RES *mysql_res, static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod,bool Shuffle); static void Tst_WriteChoiceAnsAssessTest (unsigned NumQst,MYSQL_RES *mysql_res, double *ScoreThisQst,bool *AnswerIsNotBlank); -static void Tst_WriteChoiceAnsViewGame (unsigned NumQst,long QstCod); +static void Tst_WriteChoiceAnsViewGame (struct Game *Game,unsigned NumQst,long QstCod); static void Tst_WriteTextAnsViewTest (unsigned NumQst); static void Tst_WriteTextAnsAssessTest (unsigned NumQst,MYSQL_RES *mysql_res, @@ -833,7 +832,7 @@ static void Tst_ShowTestQuestionsWhenSeeing (MYSQL_RES *mysql_res) Lay_ShowErrorAndExit ("Wrong code of question."); Tst_WriteQstAndAnsTest (Tst_SHOW_TEST_TO_ANSWER, - NumQst,QstCod,row, + NULL,NumQst,QstCod,row, &ScoreThisQst, // Not used here &AnswerIsNotBlank); // Not used here } @@ -934,7 +933,7 @@ static void Tst_ShowTestResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank /***** Write question and answers *****/ Tst_WriteQstAndAnsTest (Tst_SHOW_TEST_RESULT, - NumQst,QstCod,row, + NULL,NumQst,QstCod,row, &ScoreThisQst,&AnswerIsNotBlank); /***** Store test result question in database *****/ @@ -974,6 +973,7 @@ static void Tst_ShowTestResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank /*****************************************************************************/ void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions, + struct Game *Game, unsigned NumQst,long QstCod,MYSQL_ROW row, double *ScoreThisQst,bool *AnswerIsNotBlank) { @@ -1041,7 +1041,7 @@ void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestio Tst_WriteAnswersTestToAnswer (NumQst,QstCod,(row[3][0] == 'Y')); break; case Tst_SHOW_GAME_RESULT: - Tst_WriteAnswersGameResult (NumQst,QstCod); + Tst_WriteAnswersGameResult (Game,NumQst,QstCod); break; } fprintf (Gbl.F.Out,"" @@ -3545,7 +3545,7 @@ static void Tst_WriteAnswersTestResult (unsigned NumQst,long QstCod, /************** Write answers of a question when viewing a game **************/ /*****************************************************************************/ -static void Tst_WriteAnswersGameResult (unsigned NumQst,long QstCod) +void Tst_WriteAnswersGameResult (struct Game *Game,unsigned NumQst,long QstCod) { /***** Write parameter with question code *****/ Tst_WriteParamQstCod (NumQst,QstCod); @@ -3561,7 +3561,7 @@ static void Tst_WriteAnswersGameResult (unsigned NumQst,long QstCod) break; case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE: - Tst_WriteChoiceAnsViewGame (NumQst,QstCod); + Tst_WriteChoiceAnsViewGame (Game,NumQst,QstCod); break; default: break; @@ -4045,12 +4045,12 @@ static void Tst_WriteChoiceAnsAssessTest (unsigned NumQst,MYSQL_RES *mysql_res, /******** Write single or multiple choice answer when viewing a test *********/ /*****************************************************************************/ -static void Tst_WriteChoiceAnsViewGame (unsigned NumQst,long QstCod) +static void Tst_WriteChoiceAnsViewGame (struct Game *Game,unsigned NumQst,long QstCod) { unsigned NumOpt; MYSQL_RES *mysql_res; MYSQL_ROW row; - unsigned Index; + unsigned AnsInd; bool ErrorInIndex = false; /***** Get answers of a question from database *****/ @@ -4082,9 +4082,9 @@ static void Tst_WriteChoiceAnsViewGame (unsigned NumQst,long QstCod) /***** 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 (sscanf (row[0],"%u",&AnsInd) == 1) { - if (Index >= Tst_MAX_OPTIONS_PER_QUESTION) + if (AnsInd >= Tst_MAX_OPTIONS_PER_QUESTION) ErrorInIndex = true; } else @@ -4122,8 +4122,11 @@ static void Tst_WriteChoiceAnsViewGame (unsigned NumQst,long QstCod) Img_ShowImage (&Gbl.Test.Answer.Options[NumOpt].Image, "TEST_IMG_SHOW_ANS_CONTAINER", "TEST_IMG_SHOW_ANS"); - fprintf (Gbl.F.Out,"" - ""); + fprintf (Gbl.F.Out,""); + + /* Get number of users who selected this answer and draw proportional bar */ + Rmt_GetAndDrawBarNumUsrsWhoAnswered (Game,QstCod,AnsInd); + fprintf (Gbl.F.Out,""); } /***** End table *****/ @@ -8311,7 +8314,7 @@ static void Tst_ShowTestResult (time_t TstTimeUTC) /***** Write questions and answers *****/ Tst_WriteQstAndAnsTest (Tst_SHOW_TEST_RESULT, - NumQst,QstCod,row, + NULL,NumQst,QstCod,row, &ScoreThisQst, // Not used here &AnswerIsNotBlank); // Not used here } diff --git a/swad_test.h b/swad_test.h index 2074bbd5..a67690f6 100644 --- a/swad_test.h +++ b/swad_test.h @@ -27,6 +27,8 @@ /********************************* Headers ***********************************/ /*****************************************************************************/ +#include "swad_remote_control.h" + /*****************************************************************************/ /***************************** Public constants ******************************/ /*****************************************************************************/ @@ -143,6 +145,7 @@ void Tst_ShowNewTest (void); void Tst_AssessTest (void); void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions, + struct Game *Game, unsigned NumQst,long QstCod,MYSQL_ROW row, double *ScoreThisQst,bool *AnswerIsNotBlank); void Tst_WriteQstStem (const char *Stem,const char *ClassStem); @@ -156,6 +159,7 @@ void Tst_ListQuestionsToSelect (void); bool Tst_GetOneQuestionByCod (long QstCod,MYSQL_RES **mysql_res); void Tst_WriteParamEditQst (void); unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle); +void Tst_WriteAnswersGameResult (struct Game *Game,unsigned NumQst,long QstCod); void Tst_WriteAnsTF (char AnsTF); void Tst_CheckIfNumberOfAnswersIsOne (void);