From 05db22eb5e440d50e02a53f1218e191f3e70dbc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Ca=C3=B1as=20Vargas?= Date: Tue, 10 Dec 2019 21:52:22 +0100 Subject: [PATCH] Version19.89 --- sql/cambios.sql | 2 +- sql/swad.sql | 2 +- swad_API.c | 6 +- swad_action.c | 2 +- swad_changelog.h | 10 +- swad_database.c | 36 +++---- swad_game.c | 64 ++++++------ swad_game.h | 19 ++-- swad_match.c | 246 +++++++++++++++++++++++++++-------------------- swad_match.h | 10 +- 10 files changed, 223 insertions(+), 174 deletions(-) diff --git a/sql/cambios.sql b/sql/cambios.sql index 474dedb4..59f4c59a 100644 --- a/sql/cambios.sql +++ b/sql/cambios.sql @@ -13097,7 +13097,7 @@ SELECT projects.PrjCod,COUNT(prj_usr.UsrCod) AS NumStds FROM projects LEFT JOIN SELECT COUNT(*) FROM tst_answers,gam_questions WHERE gam_questions.GamCod=6 AND gam_questions.QstCod=tst_answers.QstCod; - +SELECT MIN(QstInd) FROM gam_questions WHERE GamCod=47 AND QstInd>5; diff --git a/sql/swad.sql b/sql/swad.sql index 83cdc8fc..b849d2af 100644 --- a/sql/swad.sql +++ b/sql/swad.sql @@ -639,7 +639,7 @@ CREATE TABLE IF NOT EXISTS mch_matches ( Title VARCHAR(2047) NOT NULL, QstInd INT NOT NULL DEFAULT 0, QstCod INT NOT NULL DEFAULT -1, - Showing ENUM('nothing','stem','answers','results') NOT NULL DEFAULT 'nothing', + Showing ENUM('start','stem','answers','results','end') NOT NULL DEFAULT 'start', NumCols INT NOT NULL DEFAULT 1, ShowQstResults ENUM('N','Y') NOT NULL DEFAULT 'N', ShowUsrResults ENUM('N','Y') NOT NULL DEFAULT 'N', diff --git a/swad_API.c b/swad_API.c index 387c00f3..b24a5352 100644 --- a/swad_API.c +++ b/swad_API.c @@ -4811,9 +4811,9 @@ int swad__getMatchStatus (struct soap *soap, "Type of answer not valid in a game."); /***** Join match *****/ - getMatchStatusOut->matchCode = 0; // == 0 ==> wait - if (Match.Status.Playing && // Match is being played - Match.Status.QstInd < Mch_AFTER_LAST_QUESTION) // Unfinished + getMatchStatusOut->matchCode = 0; // == 0 ==> wait + if (Match.Status.Playing && // Match is being played + Match.Status.Showing != Mch_END) // Unfinished /* Update players */ getMatchStatusOut->matchCode = Mch_RegisterMeAsPlayerInMatch (&Match) ? matchCode : // > 0 ==> OK -1; // < 0 ==> can not join this match diff --git a/swad_action.c b/swad_action.c index 4af246a3..30642aa2 100644 --- a/swad_action.c +++ b/swad_action.c @@ -2166,7 +2166,7 @@ const struct Act_Actions Act_Actions[Act_NUM_ACTIONS] = [ActJoiMch ] = {1780,-1,TabUnk,ActSeeAllGam ,0x008, 0, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_NEW_TAB,Mch_GetMatchBeingPlayed ,Mch_JoinMatchAsStd ,NULL}, [ActSeeMchAnsQstStd ] = {1808,-1,TabUnk,ActSeeAllGam ,0x008, 0, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_2ND_TAB,Mch_GetMatchBeingPlayed ,Mch_JoinMatchAsStd ,NULL}, - [ActRemMchAnsQstStd ] = {1809,-1,TabUnk,ActSeeAllGam ,0x008, 0, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_2ND_TAB,Mch_GetMatchBeingPlayed ,Mch_RemoveQuestionAnswer ,NULL}, + [ActRemMchAnsQstStd ] = {1809,-1,TabUnk,ActSeeAllGam ,0x008, 0, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_2ND_TAB,Mch_GetMatchBeingPlayed ,Mch_RemoveMyQuestionAnswer ,NULL}, [ActAnsMchQstStd ] = {1651,-1,TabUnk,ActSeeAllGam ,0x008, 0, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_2ND_TAB,Mch_GetMatchBeingPlayed ,Mch_ReceiveQuestionAnswer ,NULL}, [ActRefMchStd ] = {1782,-1,TabUnk,ActSeeAllGam ,0x008, 0, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_AJAX_RFRESH,Mch_GetMatchBeingPlayed ,Mch_RefreshMatchStd ,NULL}, diff --git a/swad_changelog.h b/swad_changelog.h index a2c78df5..f73fc506 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -490,13 +490,19 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - * En OpenSWAD: ps2pdf source.ps destination.pdf */ -#define Log_PLATFORM_VERSION "SWAD 19.88.11 (2019-12-10)" +#define Log_PLATFORM_VERSION "SWAD 19.89 (2019-12-10)" #define CSS_FILE "swad19.88.5.css" #define JS_FILE "swad19.70.js" /* // TODO: Hacer un nuevo rol en los TFG: tutor externo (profesor de áreas no vinculadas con el centro, profesionales de empresas, etc.) // TODO: Impedir la creación y edición de proyectos si no son editables. -// TODO: ¿Poner en color rojo las fechas de los juegos que tengan todas las partidas terminadas? + + Version 19.89: Dec 10, 2019 Game dates are in red colour if all their matches are finished or ot don't have matches. (248186 lines) + 4 changes necessary in database: +ALTER TABLE mch_matches CHANGE COLUMN Showing Showing ENUM('nothing','stem','answers','results','start','end') NOT NULL DEFAULT 'nothing'; +UPDATE mch_matches SET Showing='start' WHERE QstInd='0' AND Showing='nothing'; +UPDATE mch_matches SET Showing='end' WHERE QstInd='2147483647' AND Showing='nothing'; +ALTER TABLE mch_matches CHANGE COLUMN Showing Showing ENUM('start','stem','answers','results','end') NOT NULL DEFAULT 'start'; Version 19.88.11: Dec 10, 2019 Fixed bug in selection of groups. (248141 lines) Version 19.88.10: Dec 10, 2019 Fixed bug in matches results. (248145 lines) diff --git a/swad_database.c b/swad_database.c index 193ffbad..4e214d70 100644 --- a/swad_database.c +++ b/swad_database.c @@ -1372,23 +1372,23 @@ mysql> DESCRIBE mch_groups; /***** Table mch_matches *****/ /* mysql> DESCRIBE mch_matches; -+----------------+--------------------------------------------+------+-----+---------+----------------+ -| Field | Type | Null | Key | Default | Extra | -+----------------+--------------------------------------------+------+-----+---------+----------------+ -| MchCod | int(11) | NO | PRI | NULL | auto_increment | -| GamCod | int(11) | NO | MUL | NULL | | -| UsrCod | int(11) | NO | | NULL | | -| StartTime | datetime | NO | | NULL | | -| EndTime | datetime | NO | | NULL | | -| Title | varchar(2047) | NO | | NULL | | -| QstInd | int(11) | NO | | 0 | | -| QstCod | int(11) | NO | | -1 | | -| Showing | enum('nothing','stem','answers','results') | NO | | nothing | | -| NumCols | int(11) | NO | | 1 | | -| ShowQstResults | enum('N','Y') | NO | | N | | -| ShowUsrResults | enum('N','Y') | NO | | N | | -+----------------+--------------------------------------------+------+-----+---------+----------------+ -12 rows in set (0.01 sec) ++----------------+------------------------------------------------+------+-----+---------+----------------+ +| Field | Type | Null | Key | Default | Extra | ++----------------+------------------------------------------------+------+-----+---------+----------------+ +| MchCod | int(11) | NO | PRI | NULL | auto_increment | +| GamCod | int(11) | NO | MUL | NULL | | +| UsrCod | int(11) | NO | | NULL | | +| StartTime | datetime | NO | | NULL | | +| EndTime | datetime | NO | | NULL | | +| Title | varchar(2047) | NO | | NULL | | +| QstInd | int(11) | NO | | 0 | | +| QstCod | int(11) | NO | | -1 | | +| Showing | enum('start','stem','answers','results','end') | NO | | start | | +| NumCols | int(11) | NO | | 1 | | +| ShowQstResults | enum('N','Y') | NO | | N | | +| ShowUsrResults | enum('N','Y') | NO | | N | | ++----------------+------------------------------------------------+------+-----+---------+----------------+ +12 rows in set (0.00 sec) */ DB_CreateTable ("CREATE TABLE IF NOT EXISTS mch_matches (" "MchCod INT NOT NULL AUTO_INCREMENT," @@ -1399,7 +1399,7 @@ mysql> DESCRIBE mch_matches; "Title VARCHAR(2047) NOT NULL," // Gam_MAX_BYTES_TITLE "QstInd INT NOT NULL DEFAULT 0," "QstCod INT NOT NULL DEFAULT -1," - "Showing ENUM('nothing','stem','answers','results') NOT NULL DEFAULT 'nothing'," + "Showing ENUM('start','stem','answers','results','end') NOT NULL DEFAULT 'start'," "NumCols INT NOT NULL DEFAULT 1," "ShowQstResults ENUM('N','Y') NOT NULL DEFAULT 'N'," "ShowUsrResults ENUM('N','Y') NOT NULL DEFAULT 'N'," diff --git a/swad_game.c b/swad_game.c index 0033a1f6..640fa0c2 100644 --- a/swad_game.c +++ b/swad_game.c @@ -160,7 +160,7 @@ static void Gam_PutParamsOneQst (void); static void Gam_ExchangeQuestions (long GamCod, unsigned QstIndTop,unsigned QstIndBottom); -static bool Gam_GetNumMchsGameAndCheckIfEditable (struct Game *Game); +static bool Gam_CheckIfEditable (const struct Game *Game); static long Gam_GetCurrentGamCod (void); @@ -251,8 +251,8 @@ static void Gam_ListAllGames (void) HTM_TR_End (); - /***** Write all the games *****/ - for (NumGame = Pagination.FirstItemVisible; + /***** Write all games *****/ + for (NumGame = Pagination.FirstItemVisible; NumGame <= Pagination.LastItemVisible; NumGame++) { @@ -442,6 +442,7 @@ static void Gam_ShowOneGame (struct Game *Game,bool ShowOnlyThisGame) static unsigned UniqueId = 0; char *Id; Dat_StartEndTime_t StartEndTime; + const char *Color; char Txt[Cns_MAX_BYTES_TEXT + 1]; /***** Set anchor string *****/ @@ -470,21 +471,22 @@ static void Gam_ShowOneGame (struct Game *Game,bool ShowOnlyThisGame) /***** Start/end date/time *****/ UniqueId++; - for (StartEndTime = (Dat_StartEndTime_t) 0; + for (StartEndTime = (Dat_StartEndTime_t) 0; StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1); StartEndTime++) { if (asprintf (&Id,"gam_date_%u_%u",(unsigned) StartEndTime,UniqueId) < 0) Lay_NotEnoughMemoryExit (); + Color = Game->NumUnfinishedMchs ? (Game->Hidden ? "DATE_GREEN_LIGHT": + "DATE_GREEN") : + (Game->Hidden ? "DATE_RED_LIGHT": + "DATE_RED"); if (ShowOnlyThisGame) HTM_TD_Begin ("id=\"%s\" class=\"%s LT\"", - Id,Game->Hidden ? "DATE_GREEN_LIGHT": - "DATE_GREEN"); + Id,Color); else HTM_TD_Begin ("id=\"%s\" class=\"%s LT COLOR%u\"", - Id,Game->Hidden ? "DATE_GREEN_LIGHT": - "DATE_GREEN", - Gbl.RowEvenOdd); + Id,Color,Gbl.RowEvenOdd); if (Game->TimeUTC[Dat_START_TIME]) Dat_WriteLocalDateHMSFromUTC (Id,Game->TimeUTC[StartEndTime], Gbl.Prefs.DateFormat,Dat_SEPARATOR_BREAK, @@ -934,6 +936,9 @@ void Gam_GetDataOfGameByCod (struct Game *Game) /* Get number of matches */ Game->NumMchs = Mch_GetNumMchsInGame (Game->GamCod); + + /* Get number of unfinished matches */ + Game->NumUnfinishedMchs = Mch_GetNumUnfinishedMchsInGame (Game->GamCod); } else /* Initialize to empty game */ @@ -989,6 +994,7 @@ static void Gam_ResetGame (struct Game *Game) Game->Title[0] = '\0'; Game->NumQsts = 0; Game->NumMchs = 0; + Game->NumUnfinishedMchs = 0; Game->Hidden = false; } @@ -1514,7 +1520,7 @@ void Gam_RequestNewQuestion (void) Gam_GetDataOfGameByCod (&Game); /***** Check if game has matches *****/ - if (Gam_GetNumMchsGameAndCheckIfEditable (&Game)) + if (Gam_CheckIfEditable (&Game)) { /***** Show form to create a new question in this game *****/ Gam_SetCurrentGamCod (Game.GamCod); // Used to pass parameter @@ -1540,9 +1546,10 @@ void Gam_ListTstQuestionsToSelect (void) /***** Get parameters *****/ if ((Game.GamCod = Gam_GetParams ()) == -1L) Lay_ShowErrorAndExit ("Code of game is missing."); + Gam_GetDataOfGameByCod (&Game); /***** Check if game has matches *****/ - if (Gam_GetNumMchsGameAndCheckIfEditable (&Game)) + if (Gam_CheckIfEditable (&Game)) { /***** List several test questions for selection *****/ Gam_SetCurrentGamCod (Game.GamCod); // Used to pass parameter @@ -1683,9 +1690,10 @@ unsigned Gam_GetPrevQuestionIndexInGame (long GamCod,unsigned QstInd) /***** Get previous question index (row[0]) *****/ row = mysql_fetch_row (mysql_res); - if (row[0]) - if (sscanf (row[0],"%u",&PrevQstInd) != 1) - Lay_ShowErrorAndExit ("Error when getting previous question index."); + if (row) + if (row[0]) + if (sscanf (row[0],"%u",&PrevQstInd) != 1) + Lay_ShowErrorAndExit ("Error when getting previous question index."); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); @@ -1716,9 +1724,10 @@ unsigned Gam_GetNextQuestionIndexInGame (long GamCod,unsigned QstInd) /***** Get next question index (row[0]) *****/ row = mysql_fetch_row (mysql_res); - if (row[0]) - if (sscanf (row[0],"%u",&NextQstInd) != 1) - Lay_ShowErrorAndExit ("Error when getting next question index."); + if (row) + if (row[0]) + if (sscanf (row[0],"%u",&NextQstInd) != 1) + Lay_ShowErrorAndExit ("Error when getting next question index."); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); @@ -1737,7 +1746,7 @@ static void Gam_ListGameQuestions (struct Game *Game) extern const char *Txt_This_game_has_no_questions; MYSQL_RES *mysql_res; unsigned NumQsts; - bool ICanEditQuestions = Gam_GetNumMchsGameAndCheckIfEditable (Game); + bool ICanEditQuestions = Gam_CheckIfEditable (Game); /***** Get data of questions from database *****/ NumQsts = (unsigned) DB_QuerySELECT (&mysql_res,"can not get data of a question", @@ -1996,7 +2005,7 @@ void Gam_AddTstQuestionsToGame (void) Gam_GetDataOfGameByCod (&Game); /***** Check if game has matches *****/ - if (Gam_GetNumMchsGameAndCheckIfEditable (&Game)) + if (Gam_CheckIfEditable (&Game)) { /***** Get selected questions *****/ /* Allocate space for selected question codes */ @@ -2122,7 +2131,7 @@ void Gam_RequestRemoveQst (void) Gam_GetDataOfGameByCod (&Game); /***** Check if game has matches *****/ - if (Gam_GetNumMchsGameAndCheckIfEditable (&Game)) + if (Gam_CheckIfEditable (&Game)) { /***** Get question index *****/ QstInd = Gam_GetParamQstInd (); @@ -2160,7 +2169,7 @@ void Gam_RemoveQst (void) Gam_GetDataOfGameByCod (&Game); /***** Check if game has matches *****/ - if (Gam_GetNumMchsGameAndCheckIfEditable (&Game)) + if (Gam_CheckIfEditable (&Game)) { /***** Get question index *****/ QstInd = Gam_GetParamQstInd (); @@ -2220,7 +2229,7 @@ void Gam_MoveUpQst (void) Gam_GetDataOfGameByCod (&Game); /***** Check if game has matches *****/ - if (Gam_GetNumMchsGameAndCheckIfEditable (&Game)) + if (Gam_CheckIfEditable (&Game)) { /***** Get question index *****/ QstIndBottom = Gam_GetParamQstInd (); @@ -2271,7 +2280,7 @@ void Gam_MoveDownQst (void) Gam_GetDataOfGameByCod (&Game); /***** Check if game has matches *****/ - if (Gam_GetNumMchsGameAndCheckIfEditable (&Game)) + if (Gam_CheckIfEditable (&Game)) { /***** Get question index *****/ QstIndTop = Gam_GetParamQstInd (); @@ -2365,16 +2374,13 @@ static void Gam_ExchangeQuestions (long GamCod, /*****************************************************************************/ /*********** Get number of matches and check is edition is possible **********/ /*****************************************************************************/ -// Games with matches should not be edited +// Before calling this function, number of matches must be calculated -static bool Gam_GetNumMchsGameAndCheckIfEditable (struct Game *Game) +static bool Gam_CheckIfEditable (const struct Game *Game) { - /***** Get number of matches *****/ - Game->NumMchs = Mch_GetNumMchsInGame (Game->GamCod); - if (Gam_CheckIfICanEditGames ()) /***** Questions are editable only if game has no matches *****/ - return (bool) (Game->NumMchs == 0); + return (bool) (Game->NumMchs == 0); // Games with matches should not be edited else return false; // Questions are not editable } diff --git a/swad_game.h b/swad_game.h index 08e101bb..480a9f2a 100644 --- a/swad_game.h +++ b/swad_game.h @@ -45,17 +45,18 @@ struct GameSelected struct Game { - long GamCod; // Game code - long CrsCod; // Course code - long UsrCod; // Author code - double MaxGrade; // Score range [0...max.score] - // will be converted to - // grade range [0...max.grade] + long GamCod; // Game code + long CrsCod; // Course code + long UsrCod; // Author code + double MaxGrade; // Score range [0...max.score] + // will be converted to + // grade range [0...max.grade] char Title[Gam_MAX_BYTES_TITLE + 1]; time_t TimeUTC[Dat_NUM_START_END_TIME]; - bool Hidden; // Game is hidden - unsigned NumQsts; // Number of questions in the game - unsigned NumMchs; // Number of matches in the game + bool Hidden; // Game is hidden + unsigned NumQsts; // Number of questions in the game + unsigned NumMchs; // Number of matches in the game + unsigned NumUnfinishedMchs; // Number of unfinished matches in the game }; #define Gam_NUM_ORDERS 3 diff --git a/swad_match.c b/swad_match.c index bcf6bec0..68b74a49 100644 --- a/swad_match.c +++ b/swad_match.c @@ -77,10 +77,11 @@ typedef enum const char *Mch_ShowingStringsDB[Mch_NUM_SHOWING] = { - "nothing", - "stem", - "answers", - "results", + [Mch_START ] = "start", + [Mch_STEM ] = "stem", + [Mch_ANSWERS] = "answers", + [Mch_RESULTS] = "results", + [Mch_END ] = "end", }; #define Mch_MAX_COLS 4 @@ -205,7 +206,7 @@ static void Mch_SetMatchAsNotBeingPlayed (long MchCod); static bool Mch_GetIfMatchIsBeingPlayed (long MchCod); static void Mch_GetNumPlayers (struct Match *Match); -static void Mch_RemoveAnswerToMatchQuestion (const struct Match *Match); +static void Mch_RemoveMyAnswerToMatchQuestion (const struct Match *Match); static double Mch_ComputeScore (unsigned NumQsts); @@ -357,7 +358,7 @@ void Mch_GetDataOfMatchByCod (struct Match *Match) Match->Status.QstInd = 0; Match->Status.QstCod = -1L; Match->Status.QstStartTimeUTC = (time_t) 0; - Match->Status.Showing = Mch_STEM; + Match->Status.Showing = Mch_START; Match->Status.Playing = false; Match->Status.NumPlayers = 0; Match->Status.NumCols = Mch_NUM_COLS_DEFAULT; @@ -576,8 +577,8 @@ static void Mch_ListOneOrMoreMatchesTimes (const struct Match *Match,unsigned Un Lay_NotEnoughMemoryExit (); HTM_TD_Begin ("id=\"%s\" class=\"%s LT COLOR%u\"", Id, - Match->Status.QstInd >= Mch_AFTER_LAST_QUESTION ? "DATE_RED" : - "DATE_GREEN", + Match->Status.Showing == Mch_END ? "DATE_RED" : + "DATE_GREEN", Gbl.RowEvenOdd); Dat_WriteLocalDateHMSFromUTC (Id,Match->TimeUTC[StartEndTime], Gbl.Prefs.DateFormat,Dat_SEPARATOR_BREAK, @@ -703,7 +704,7 @@ static void Mch_ListOneOrMoreMatchesStatus (const struct Match *Match,unsigned N HTM_TD_Begin ("class=\"DAT CT COLOR%u\"",Gbl.RowEvenOdd); - if (Match->Status.QstInd < Mch_AFTER_LAST_QUESTION) // Unfinished match + if (Match->Status.Showing != Mch_END) // Match not over { /* Current question index / total of questions */ HTM_DIV_Begin ("class=\"DAT\""); @@ -717,8 +718,8 @@ static void Mch_ListOneOrMoreMatchesStatus (const struct Match *Match,unsigned N ActResMch, NULL, Mch_PutParamsPlay, - Match->Status.QstInd < Mch_AFTER_LAST_QUESTION ? "play.svg" : - "flag-checkered.svg", + Match->Status.Showing == Mch_END ? "flag-checkered.svg" : + "play.svg", Gbl.Usrs.Me.Role.Logged == Rol_STD ? Txt_Play : Txt_Resume); @@ -915,9 +916,9 @@ static void Mch_GetMatchDataFromRow (MYSQL_RES *mysql_res, Match->Status.ShowUsrResults = (row[11][0] == 'Y'); /***** Get whether the match is being played or not *****/ - if (Match->Status.QstInd >= Mch_AFTER_LAST_QUESTION) // Finished + if (Match->Status.Showing == Mch_END) // Match over Match->Status.Playing = false; - else // Unfinished + else // Match not over Match->Status.Playing = Mch_GetIfMatchIsBeingPlayed (Match->MchCod); } @@ -1680,8 +1681,8 @@ static void Mch_UpdateElapsedTimeInQuestion (const struct Match *Match) { /***** Update elapsed time in current question in database *****/ if (Match->Status.Playing && // Match is being played - Match->Status.QstInd > 0 && - Match->Status.QstInd < Mch_AFTER_LAST_QUESTION) + Match->Status.Showing != Mch_START && + Match->Status.Showing != Mch_END) DB_QueryINSERT ("can not update elapsed time in question", "INSERT INTO mch_times (MchCod,QstInd,ElapsedTime)" " VALUES (%ld,%u,SEC_TO_TIME(%u))" @@ -1786,11 +1787,11 @@ void Mch_PlayPauseMatch (void) /***** Update status *****/ if (Match.Status.Playing) // Match is being played ==> pause it - Match.Status.Playing = false; // Pause match + Match.Status.Playing = false; // Pause match else // Match is paused, not being played ==> play it - /* If unfinished, update status */ - if (Match.Status.QstInd < Mch_AFTER_LAST_QUESTION) // Unfinished - Match.Status.Playing = true; // Start/resume match + /* If not over, update status */ + if (Match.Status.Showing != Mch_END) // Match not over + Match.Status.Playing = true; // Start/resume match /***** Update match status in database *****/ Mch_UpdateMatchStatusInDB (&Match); @@ -1931,24 +1932,22 @@ void Mch_ForwardMatch (void) static void Mch_SetMatchStatusToPrev (struct Match *Match) { /***** What to show *****/ - if (Match->Status.QstInd == 0) // Start - Mch_SetMatchStatusToStart (Match); - else if (Match->Status.QstInd >= Mch_AFTER_LAST_QUESTION) // End - Mch_SetMatchStatusToPrevQst (Match); - else // Between start and end - switch (Match->Status.Showing) - { - case Mch_NOTHING: - case Mch_STEM: - Mch_SetMatchStatusToPrevQst (Match); - break; - case Mch_ANSWERS: - Match->Status.Showing = Mch_STEM; - break; - case Mch_RESULTS: - Match->Status.Showing = Mch_ANSWERS; - break; - } + switch (Match->Status.Showing) + { + case Mch_START: + Mch_SetMatchStatusToStart (Match); + break; + case Mch_STEM: + case Mch_END: + Mch_SetMatchStatusToPrevQst (Match); + break; + case Mch_ANSWERS: + Match->Status.Showing = Mch_STEM; + break; + case Mch_RESULTS: + Match->Status.Showing = Mch_ANSWERS; + break; + } } static void Mch_SetMatchStatusToPrevQst (struct Match *Match) @@ -1956,15 +1955,15 @@ static void Mch_SetMatchStatusToPrevQst (struct Match *Match) /***** Get index of the previous question *****/ Match->Status.QstInd = Gam_GetPrevQuestionIndexInGame (Match->GamCod, Match->Status.QstInd); - if (Match->Status.QstInd == 0) // Start of questions has been reached - Mch_SetMatchStatusToStart (Match); - else + if (Match->Status.QstInd) // Start of questions not reached { Match->Status.QstCod = Gam_GetQstCodFromQstInd (Match->GamCod, Match->Status.QstInd); Match->Status.Showing = Match->Status.ShowQstResults ? Mch_RESULTS : Mch_ANSWERS; } + else // Start of questions reached + Mch_SetMatchStatusToStart (Match); } static void Mch_SetMatchStatusToStart (struct Match *Match) @@ -1972,7 +1971,7 @@ static void Mch_SetMatchStatusToStart (struct Match *Match) Match->Status.QstInd = 0; // Before first question Match->Status.QstCod = -1L; Match->Status.Playing = false; - Match->Status.Showing = Mch_NOTHING; + Match->Status.Showing = Mch_START; } /*****************************************************************************/ @@ -1982,29 +1981,27 @@ static void Mch_SetMatchStatusToStart (struct Match *Match) static void Mch_SetMatchStatusToNext (struct Match *Match) { /***** What to show *****/ - if (Match->Status.QstInd == 0) // Start - Mch_SetMatchStatusToNextQst (Match); - else if (Match->Status.QstInd >= Mch_AFTER_LAST_QUESTION) // End - Mch_SetMatchStatusToEnd (Match); - else // Between start and end - switch (Match->Status.Showing) - { - case Mch_NOTHING: - Match->Status.Showing = Mch_STEM; - break; - case Mch_STEM: - Match->Status.Showing = Mch_ANSWERS; - break; - case Mch_ANSWERS: - if (Match->Status.ShowQstResults) - Match->Status.Showing = Mch_RESULTS; - else - Mch_SetMatchStatusToNextQst (Match); - break; - case Mch_RESULTS: + switch (Match->Status.Showing) + { + case Mch_START: + Mch_SetMatchStatusToNextQst (Match); + break; + case Mch_STEM: + Match->Status.Showing = Mch_ANSWERS; + break; + case Mch_ANSWERS: + if (Match->Status.ShowQstResults) + Match->Status.Showing = Mch_RESULTS; + else Mch_SetMatchStatusToNextQst (Match); - break; - } + break; + case Mch_RESULTS: + Mch_SetMatchStatusToNextQst (Match); + break; + case Mch_END: + Mch_SetMatchStatusToEnd (Match); + break; + } } static void Mch_SetMatchStatusToNextQst (struct Match *Match) @@ -2014,14 +2011,14 @@ static void Mch_SetMatchStatusToNextQst (struct Match *Match) Match->Status.QstInd); /***** Get question code *****/ - if (Match->Status.QstInd >= Mch_AFTER_LAST_QUESTION) // Finished - Mch_SetMatchStatusToEnd (Match); - else // Unfinished + if (Match->Status.QstInd < Mch_AFTER_LAST_QUESTION) // End of questions not reached { Match->Status.QstCod = Gam_GetQstCodFromQstInd (Match->GamCod, Match->Status.QstInd); Match->Status.Showing = Mch_STEM; } + else // End of questions reached + Mch_SetMatchStatusToEnd (Match); } static void Mch_SetMatchStatusToEnd (struct Match *Match) @@ -2029,7 +2026,7 @@ static void Mch_SetMatchStatusToEnd (struct Match *Match) Match->Status.QstInd = Mch_AFTER_LAST_QUESTION; // After last question Match->Status.QstCod = -1L; Match->Status.Playing = false; - Match->Status.Showing = Mch_NOTHING; + Match->Status.Showing = Mch_END; } /*****************************************************************************/ @@ -2074,7 +2071,7 @@ static void Mch_ShowMatchStatusForStd (struct Match *Match,Mch_Update_t Update) } /*****************************************************************************/ -/******************* Get number of questions of a game *********************/ +/********************** Get number of matches in a game **********************/ /*****************************************************************************/ unsigned Mch_GetNumMchsInGame (long GamCod) @@ -2091,6 +2088,24 @@ unsigned Mch_GetNumMchsInGame (long GamCod) GamCod); } +/*****************************************************************************/ +/*************** Get number of unfinished matches in a game ******************/ +/*****************************************************************************/ + +unsigned Mch_GetNumUnfinishedMchsInGame (long GamCod) + { + /***** Trivial check *****/ + if (GamCod < 0) // A non-existing game... + return 0; // ...has no matches + + /***** Get number of matches in a game from database *****/ + return + (unsigned) DB_QueryCOUNT ("can not get number of unfinished matches of a game", + "SELECT COUNT(*) FROM mch_matches" + " WHERE GamCod=%ld AND Showing<>'%s'", + GamCod,Mch_ShowingStringsDB[Mch_END]); + } + /*****************************************************************************/ /************ Check if I belong to any of the groups of a match **************/ /*****************************************************************************/ @@ -2176,8 +2191,8 @@ static void Mch_ShowRefreshablePartTch (struct Match *Match) /***** Write elapsed time in question *****/ HTM_DIV_Begin ("class=\"MCH_TIME_QST\""); - if (Match->Status.QstInd > 0 && - Match->Status.QstInd < Mch_AFTER_LAST_QUESTION) + if (Match->Status.Showing != Mch_START && + Match->Status.Showing != Mch_END) { Mch_GetElapsedTimeInQuestion (Match,&Time); Dat_WriteHoursMinutesSeconds (&Time); @@ -2193,8 +2208,8 @@ static void Mch_ShowRefreshablePartTch (struct Match *Match) HTM_Txt (Txt_MATCH_respond); HTM_BR (); HTM_STRONG_Begin (); - if (Match->Status.QstInd > 0 && - Match->Status.QstInd < Mch_AFTER_LAST_QUESTION) + if (Match->Status.Showing != Mch_START && + Match->Status.Showing != Mch_END) HTM_Unsigned (NumAnswerersQst); else HTM_Hyphen (); @@ -2223,10 +2238,10 @@ static void Mch_ShowRightColumnTch (const struct Match *Match) Mch_ShowMatchTitle (Match); /***** Bottom row: current question and possible answers *****/ - if (Match->Status.QstInd < Mch_AFTER_LAST_QUESTION) // Not finished - Mch_ShowQuestionAndAnswersTch (Match); - else // Finished + if (Match->Status.Showing == Mch_END) // Match over Mch_ShowMatchScore (Match); + else // Match not over + Mch_ShowQuestionAndAnswersTch (Match); /***** End right container *****/ HTM_DIV_End (); @@ -2251,8 +2266,8 @@ static void Mch_ShowLeftColumnStd (const struct Match *Match, /***** Write number of question *****/ Mch_ShowNumQstInMatch (Match); - if (Match->Status.QstInd > 0 && - Match->Status.QstInd < Mch_AFTER_LAST_QUESTION) + if (Match->Status.Showing != Mch_START && + Match->Status.Showing != Mch_END) { /***** Write whether question is answered or not *****/ Mch_PutIfAnswered (Match,Answered); @@ -2285,9 +2300,11 @@ static void Mch_ShowRightColumnStd (struct Match *Match, Mch_ShowMatchTitle (Match); /***** Bottom row *****/ - if (Match->Status.Playing) // Match is being played + if (Match->Status.Playing) // Match is being played { - if (Match->Status.QstInd < Mch_AFTER_LAST_QUESTION) // Match not over + if (Match->Status.Showing == Mch_END) // Match over + Mch_ShowWaitImage (Txt_Please_wait_); + else // Match not over { HTM_DIV_Begin ("class=\"MCH_BOTTOM\""); @@ -2304,10 +2321,8 @@ static void Mch_ShowRightColumnStd (struct Match *Match, HTM_DIV_End (); } - else // Match over - Mch_ShowWaitImage (Txt_Please_wait_); } - else // Match is not being played + else // Match is not being played Mch_ShowWaitImage (Txt_Please_wait_); /***** End right container *****/ @@ -2325,12 +2340,18 @@ static void Mch_ShowNumQstInMatch (const struct Match *Match) unsigned NumQsts = Gam_GetNumQstsGame (Match->GamCod); HTM_DIV_Begin ("class=\"MCH_NUM_QST\""); - if (Match->Status.QstInd == 0) // Not started - HTM_Txt (Txt_MATCH_Start); - else if (Match->Status.QstInd >= Mch_AFTER_LAST_QUESTION) // Finished - HTM_Txt (Txt_MATCH_End); - else - HTM_TxtF ("%u/%u",Match->Status.QstInd,NumQsts); + switch (Match->Status.Showing) + { + case Mch_START: // Not started + HTM_Txt (Txt_MATCH_Start); + break; + case Mch_END: // Match over + HTM_Txt (Txt_MATCH_End); + break; + default: + HTM_TxtF ("%u/%u",Match->Status.QstInd,NumQsts); + break; + } HTM_DIV_End (); } @@ -2351,7 +2372,7 @@ static void Mch_PutMatchControlButtons (const struct Match *Match) /***** Left button *****/ HTM_DIV_Begin ("class=\"MCH_BUTTON_LEFT_CONTAINER\""); - if (Match->Status.QstInd == 0) + if (Match->Status.Showing == Mch_START) /* Put button to close browser tab */ Mch_PutBigButtonClose (); else @@ -2368,23 +2389,31 @@ static void Mch_PutMatchControlButtons (const struct Match *Match) Mch_ICON_PAUSE,Txt_Pause); else // Match is paused, not being played { - if (Match->Status.QstInd < Mch_AFTER_LAST_QUESTION) // Not finished - /* Put button to play match */ - Mch_PutBigButton (ActPlyPauMch,"play_pause",Match->MchCod, - Mch_ICON_PLAY,Match->Status.QstInd == 0 ? Txt_Start : - Txt_Resume); - else // Finished - /* Put disabled button to play match */ - Mch_PutBigButtonOff (Mch_ICON_PLAY); + switch (Match->Status.Showing) + { + case Mch_START: // Match just started, before first question + /* Put button to start playing match */ + Mch_PutBigButton (ActPlyPauMch,"play_pause",Match->MchCod, + Mch_ICON_PLAY,Txt_Start); + break; + case Mch_END: // Match over + /* Put disabled button to play match */ + Mch_PutBigButtonOff (Mch_ICON_PLAY); + break; + default: + /* Put button to resume match */ + Mch_PutBigButton (ActPlyPauMch,"play_pause",Match->MchCod, + Mch_ICON_PLAY,Txt_Resume); + } } HTM_DIV_End (); /***** Right button *****/ HTM_DIV_Begin ("class=\"MCH_BUTTON_RIGHT_CONTAINER\""); - if (Match->Status.QstInd >= Mch_AFTER_LAST_QUESTION) // Finished + if (Match->Status.Showing == Mch_END) // Match over /* Put button to close browser tab */ Mch_PutBigButtonClose (); - else + else // Match not over /* Put button to show answers */ Mch_PutBigButton (ActFwdMch,"forward",Match->MchCod, Mch_ICON_NEXT,Txt_Go_forward); @@ -2584,8 +2613,8 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match) MYSQL_ROW row; /***** Trivial check: question index should be correct *****/ - if (Match->Status.QstInd == 0 || - Match->Status.QstInd >= Mch_AFTER_LAST_QUESTION) + if (Match->Status.Showing == Mch_START || + Match->Status.Showing == Mch_END) return; /***** Get data of question from database *****/ @@ -2625,7 +2654,9 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match) /***** Write answers? *****/ switch (Match->Status.Showing) { - case Mch_NOTHING: + case Mch_START: + /* Don't write anything */ + break; case Mch_STEM: /* Don't write anything */ break; @@ -2644,6 +2675,9 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match) "MCH_TCH_ANS", true); // Show result break; + case Mch_END: + /* Don't write anything */ + break; } HTM_DIV_End (); // Bottom @@ -3114,7 +3148,7 @@ bool Mch_RegisterMeAsPlayerInMatch (struct Match *Match) return false; /***** Trivial check: match must not be over *****/ - if (Match->Status.QstInd >= Mch_AFTER_LAST_QUESTION) // Finished + if (Match->Status.Showing == Mch_END) // Match over return false; /***** Trivial check: only a student can join a match *****/ @@ -3161,7 +3195,7 @@ void Mch_JoinMatchAsStd (void) /****** Remove student's answer to a question and show match as student ******/ /*****************************************************************************/ -void Mch_RemoveQuestionAnswer (void) +void Mch_RemoveMyQuestionAnswer (void) { struct Match Match; unsigned QstInd; @@ -3179,7 +3213,7 @@ void Mch_RemoveQuestionAnswer (void) Match.Status.Showing == Mch_ANSWERS && // Teacher's screen is showing answers QstInd == Match.Status.QstInd) // Removing answer to the current question being played /***** Remove answer to this question *****/ - Mch_RemoveAnswerToMatchQuestion (&Match); + Mch_RemoveMyAnswerToMatchQuestion (&Match); /***** Show current match status *****/ HTM_DIV_Begin ("id=\"match\" class=\"MCH_CONT\""); @@ -3392,7 +3426,7 @@ void Mch_ReceiveQuestionAnswer (void) /********************* Remove answer to match question ***********************/ /*****************************************************************************/ -static void Mch_RemoveAnswerToMatchQuestion (const struct Match *Match) +static void Mch_RemoveMyAnswerToMatchQuestion (const struct Match *Match) { DB_QueryDELETE ("can not remove your answer to the match question", "DELETE FROM mch_answers" diff --git a/swad_match.h b/swad_match.h index a3a5f754..8108c0ab 100644 --- a/swad_match.h +++ b/swad_match.h @@ -37,15 +37,16 @@ #define Mch_AFTER_LAST_QUESTION ((unsigned)((1UL << 31) - 1)) // 2^31 - 1, don't change this number because it is used in database to indicate that a match is finished -#define Mch_NUM_SHOWING 4 +#define Mch_NUM_SHOWING 5 typedef enum { - Mch_NOTHING, // Don't show anything + Mch_START, // Start: don't show anything Mch_STEM, // Showing only the question stem Mch_ANSWERS, // Showing the question stem and the answers Mch_RESULTS, // Showing the results + Mch_END, // End: don't show anything } Mch_Showing_t; -#define Mch_SHOWING_DEFAULT Mch_NOTHING +#define Mch_SHOWING_DEFAULT Mch_START struct Match { @@ -109,13 +110,14 @@ void Mch_BackMatch (void); void Mch_ForwardMatch (void); unsigned Mch_GetNumMchsInGame (long GamCod); +unsigned Mch_GetNumUnfinishedMchsInGame (long GamCod); bool Mch_CheckIfICanPlayThisMatchBasedOnGrps (const struct Match *Match); bool Mch_RegisterMeAsPlayerInMatch (struct Match *Match); void Mch_GetMatchBeingPlayed (void); void Mch_JoinMatchAsStd (void); -void Mch_RemoveQuestionAnswer (void); +void Mch_RemoveMyQuestionAnswer (void); void Mch_RefreshMatchTch (void); void Mch_RefreshMatchStd (void);