Version 22.114: May 19, 2023 Check if a rubric is recursive.

This commit is contained in:
acanas 2023-05-19 21:46:54 +02:00
parent a32d962dc3
commit 0bbd73d188
6 changed files with 149 additions and 85 deletions

View File

@ -629,10 +629,11 @@ TODO: Emilce Barrera Mesa: Podr
TODO: Emilce Barrera Mesa: Mis estudiantes presentan muchas dificultades a la hora de poner la foto porque la plataforma es muy exigente respecto al fondo de la imagen. TODO: Emilce Barrera Mesa: Mis estudiantes presentan muchas dificultades a la hora de poner la foto porque la plataforma es muy exigente respecto al fondo de la imagen.
*/ */
#define Log_PLATFORM_VERSION "SWAD 22.113 (2023-05-19)" #define Log_PLATFORM_VERSION "SWAD 22.114 (2023-05-19)"
#define CSS_FILE "swad22.107.36.css" #define CSS_FILE "swad22.107.36.css"
#define JS_FILE "swad22.49.js" #define JS_FILE "swad22.49.js"
/* /*
Version 22.114: May 19, 2023 Check if a rubric is recursive. (336984 lines)
Version 22.113: May 19, 2023 Check if a rubric is recursive. (336936 lines) Version 22.113: May 19, 2023 Check if a rubric is recursive. (336936 lines)
Version 22.112: May 18, 2023 Code refactoring in options of selectors. (336794 lines) Version 22.112: May 18, 2023 Code refactoring in options of selectors. (336794 lines)
Version 22.111: May 17, 2023 A project can have more than one rubric in each category. (336691 lines) Version 22.111: May 17, 2023 A project can have more than one rubric in each category. (336691 lines)

View File

@ -4577,19 +4577,8 @@ static void Prj_ShowRubricsOfType (struct Prj_Projects *Projects,
/* Change color for rubric criteria */ /* Change color for rubric criteria */
The_ChangeRowColor (); The_ChangeRowColor ();
/* Check if rubric tree is correct */ /* Write criteria of this rubric */
if (Rub_CheckRubricsTree (Rubric.RubCod, RubCri_ListCriteriaInProject (Projects,Rubric.RubCod,ICanFill);
NULL)) // The stack has not yet been created
/* Write criteria of this rubric */
RubCri_ListCriteriaInProject (Projects,Rubric.RubCod,ICanFill);
else
{
HTM_TR_Begin (NULL);
HTM_TD_Begin ("colspan=\"8\" class=\"CT %s\"",The_GetColorRows ());
Err_RecursiveRubric ();
HTM_TD_End ();
HTM_TR_End ();
}
/* Change color for next rubric */ /* Change color for next rubric */
The_ChangeRowColor (); The_ChangeRowColor ();

View File

@ -345,6 +345,7 @@ void Rub_ShowOnlyOneRubric (struct Rub_Rubrics *Rubrics)
{ {
extern const char *Hlp_ASSESSMENT_Rubrics; extern const char *Hlp_ASSESSMENT_Rubrics;
extern const char *Txt_Rubric; extern const char *Txt_Rubric;
struct Node *TOS = NULL;
/***** Begin box *****/ /***** Begin box *****/
Box_BoxBegin (NULL,Rubrics->Rubric.Title[0] ? Rubrics->Rubric.Title : Box_BoxBegin (NULL,Rubrics->Rubric.Title[0] ? Rubrics->Rubric.Title :
@ -357,8 +358,7 @@ void Rub_ShowOnlyOneRubric (struct Rub_Rubrics *Rubrics)
true); // Show only this rubric true); // Show only this rubric
/***** Check if rubric tree is correct *****/ /***** Check if rubric tree is correct *****/
if (!Rub_CheckRubricsTree (Rubrics->Rubric.RubCod, if (Rub_CheckIfRecursiveTree (Rubrics->Rubric.RubCod,&TOS))
NULL)) // The stack has not yet been created
Err_RecursiveRubric (); Err_RecursiveRubric ();
/***** Write criteria of this rubric *****/ /***** Write criteria of this rubric *****/
@ -788,6 +788,7 @@ void Rub_PutFormsOneRubric (struct Rub_Rubrics *Rubrics,
[Rub_EXISTING_RUBRIC] = &Hlp_ASSESSMENT_Rubrics_edit_rubric, [Rub_EXISTING_RUBRIC] = &Hlp_ASSESSMENT_Rubrics_edit_rubric,
[Rub_NEW_RUBRIC ] = &Hlp_ASSESSMENT_Rubrics_new_rubric, [Rub_NEW_RUBRIC ] = &Hlp_ASSESSMENT_Rubrics_new_rubric,
}; };
struct Node *TOS = NULL;
/***** Begin box *****/ /***** Begin box *****/
Box_BoxBegin (NULL, Box_BoxBegin (NULL,
@ -800,8 +801,7 @@ void Rub_PutFormsOneRubric (struct Rub_Rubrics *Rubrics,
Rub_PutFormEditionRubric (Rubrics,ExistingNewRubric); Rub_PutFormEditionRubric (Rubrics,ExistingNewRubric);
/***** Check if rubric tree is correct *****/ /***** Check if rubric tree is correct *****/
if (!Rub_CheckRubricsTree (Rubrics->Rubric.RubCod, if (Rub_CheckIfRecursiveTree (Rubrics->Rubric.RubCod,&TOS))
NULL)) // The stack has not yet been created
Err_RecursiveRubric (); Err_RecursiveRubric ();
/***** Show list of criteria inside box *****/ /***** Show list of criteria inside box *****/
@ -1026,7 +1026,7 @@ static void Rub_UpdateRubric (struct Rub_Rubric *Rubric)
/*****************************************************************************/ /*****************************************************************************/
/********** Recursive function to compute the score of a criterion ***********/ /********** Recursive function to compute the score of a criterion ***********/
/*****************************************************************************/ /*****************************************************************************/
// Return true if tree is ok, or false if infinite recursion // Return true if rubric tree is recursive
/* Tree Stack /* Tree Stack
_______ ______ _______ ______
| Rub 1 | TOS (Top Of Stack)____\|___5__| | Rub 1 | TOS (Top Of Stack)____\|___5__|
@ -1061,63 +1061,47 @@ Handwritten Handwritten |_______| Handwritten
/ | \ / | \
Handwritten Handwritten Handwritten Handwritten Handwritten Handwritten
*/ */
bool Rub_CheckIfRecursiveTree (long RubCod,struct Node **TOS)
bool Rub_CheckRubricsTree (long RubCod,struct Node *TOS)
{ {
struct Node *Node; bool RecursiveTree;
bool TreeOk;
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
unsigned NumCriteria; unsigned NumCriteria;
unsigned NumCriterion; unsigned NumCriterion;
struct RubCri_Criterion Criterion; struct RubCri_Criterion Criterion;
/***** Check that rubric is not yet in the stack *****/ /***** Check that rubric is not yet in the stack *****/
for (Node = TOS, TreeOk = true; RecursiveTree = Rub_FindRubCodInStack (*TOS,RubCod);
Node && TreeOk;
Node = Node->Prev)
if (Node->RubCod == RubCod)
TreeOk = false;
if (TreeOk) if (!RecursiveTree)
{ {
/***** Push rubric code in stack *****/ /***** Push rubric code in stack *****/
/* Save current top of stack */ Rub_PushRubCod (TOS,RubCod);
Node = TOS;
/* Create top of stack node */
if ((TOS = malloc (sizeof (struct Node))) == NULL)
Err_NotEnoughMemoryExit ();
TOS->RubCod = RubCod;
TOS->Prev = Node;
/* For each criteria in this rubric... */ /* For each criteria in this rubric... */
NumCriteria = Rub_DB_GetCriteria (&mysql_res,RubCod); NumCriteria = Rub_DB_GetCriteria (&mysql_res,RubCod);
for (NumCriterion = 0; for (NumCriterion = 0;
NumCriterion < NumCriteria && TreeOk; NumCriterion < NumCriteria;
NumCriterion++) NumCriterion++)
{ {
/* Get criterion data */ /* Get criterion data */
RubCri_GetCriterionDataFromRow (mysql_res,&Criterion); RubCri_GetCriterionDataFromRow (mysql_res,&Criterion);
switch (Criterion.Link.Type) if (Criterion.Link.Type == Rsc_RUBRIC)
{ if (Rub_CheckIfRecursiveTree (Criterion.Link.Cod,TOS))
case Rsc_RUBRIC: {
if (!Rub_CheckRubricsTree (Criterion.Link.Cod,TOS)) RecursiveTree = true;
TreeOk = false;
break; break;
default: }
break;
}
} }
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
/***** Pop rubric code from stack *****/ /***** Pop rubric code from stack *****/
free (TOS); Rub_PopRubCod (TOS);
} }
return TreeOk; return RecursiveTree;
} }
/*****************************************************************************/ /*****************************************************************************/

View File

@ -78,7 +78,7 @@ void Rub_PutFormsOneRubric (struct Rub_Rubrics *Rubrics,
void Rub_ReceiveFormRubric (void); void Rub_ReceiveFormRubric (void);
bool Rub_CheckRubricsTree (long RubCod,struct Node *TOS); bool Rub_CheckIfRecursiveTree (long RubCod,struct Node **TOS);
//-------------------------------- Figures ------------------------------------ //-------------------------------- Figures ------------------------------------
void Rub_GetAndShowRubricsStats (void); void Rub_GetAndShowRubricsStats (void);

View File

@ -109,6 +109,7 @@ static void RubCri_ListOneOrMoreCriteriaForEdition (struct Rub_Rubrics *Rubrics,
unsigned NumCriteria, unsigned NumCriteria,
MYSQL_RES *mysql_res); MYSQL_RES *mysql_res);
static void RubCri_ListOneOrMoreCriteriaInProject (struct Prj_Projects *Projects, static void RubCri_ListOneOrMoreCriteriaInProject (struct Prj_Projects *Projects,
struct Node **TOS,
bool ICanFill, bool ICanFill,
unsigned NumCriteria, unsigned NumCriteria,
MYSQL_RES *mysql_res); MYSQL_RES *mysql_res);
@ -121,8 +122,8 @@ static void RubCri_WriteWeight (const struct RubCri_Criterion *Criterion);
static void RubCri_WriteTotalLabel (unsigned ColSpan); static void RubCri_WriteTotalLabel (unsigned ColSpan);
static void RubCri_WriteTotalValue (double Total); static void RubCri_WriteTotalValue (double Total);
static double RubCri_ComputeScore (long PrjCod, static bool RubCri_ComputeRubricScore (long PrjCod,struct Node **TOS,long RubCod,
const struct RubCri_Criterion *Criterion); double *RubricScore);
static void RubCri_PutTableHeadingForCriteria (RubCri_PutColumnForIcons_t PutColumnForIcons, static void RubCri_PutTableHeadingForCriteria (RubCri_PutColumnForIcons_t PutColumnForIcons,
RubCri_PutColumnsForScore_t PutColumnsForScore); RubCri_PutColumnsForScore_t PutColumnsForScore);
@ -574,15 +575,25 @@ void RubCri_ListCriteriaInProject (struct Prj_Projects *Projects,long RubCod,
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
unsigned NumCriteria; unsigned NumCriteria;
struct Node *TOS;
/***** Get data of rubric criteria from database *****/ /***** Get data of rubric criteria from database *****/
NumCriteria = Rub_DB_GetCriteria (&mysql_res,RubCod); NumCriteria = Rub_DB_GetCriteria (&mysql_res,RubCod);
/***** Show table with rubric criteria *****/ /***** Show table with rubric criteria *****/
if (NumCriteria) if (NumCriteria)
RubCri_ListOneOrMoreCriteriaInProject (Projects,ICanFill, {
/* Push rubric code in stack */
Rub_PushRubCod (&TOS,RubCod);
/* List rubric criteria */
RubCri_ListOneOrMoreCriteriaInProject (Projects,&TOS,ICanFill,
NumCriteria,mysql_res); NumCriteria,mysql_res);
/* Pop rubric code from stack */
Rub_PopRubCod (&TOS);
}
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
} }
@ -795,6 +806,7 @@ static void RubCri_ListOneOrMoreCriteriaForEdition (struct Rub_Rubrics *Rubrics,
/*****************************************************************************/ /*****************************************************************************/
static void RubCri_ListOneOrMoreCriteriaInProject (struct Prj_Projects *Projects, static void RubCri_ListOneOrMoreCriteriaInProject (struct Prj_Projects *Projects,
struct Node **TOS,
bool ICanFill, bool ICanFill,
unsigned NumCriteria, unsigned NumCriteria,
MYSQL_RES *mysql_res) MYSQL_RES *mysql_res)
@ -803,7 +815,7 @@ static void RubCri_ListOneOrMoreCriteriaInProject (struct Prj_Projects *Projects
struct RubCri_Criterion Criterion; struct RubCri_Criterion Criterion;
unsigned NumCriterion; unsigned NumCriterion;
char *Anchor; char *Anchor;
double Score; double CriterionScore;
double WeightedScore; double WeightedScore;
double SumOfWeights = 0.0; double SumOfWeights = 0.0;
double SumOfScores = 0.0; double SumOfScores = 0.0;
@ -820,13 +832,6 @@ static void RubCri_ListOneOrMoreCriteriaInProject (struct Prj_Projects *Projects
{ {
/***** Get criterion data *****/ /***** Get criterion data *****/
RubCri_GetCriterionDataFromRow (mysql_res,&Criterion); RubCri_GetCriterionDataFromRow (mysql_res,&Criterion);
SumOfWeights += Criterion.Weight;
/***** Compute score *****/
Score = RubCri_ComputeScore (Projects->Prj.PrjCod,&Criterion);
WeightedScore = Score * Criterion.Weight;
SumOfScores += Score;
WeightedSum += WeightedScore;
/***** Build anchor string *****/ /***** Build anchor string *****/
Frm_SetAnchorStr (Criterion.CriCod,&Anchor); Frm_SetAnchorStr (Criterion.CriCod,&Anchor);
@ -849,6 +854,7 @@ static void RubCri_ListOneOrMoreCriteriaInProject (struct Prj_Projects *Projects
switch (Criterion.Link.Type) switch (Criterion.Link.Type)
{ {
case Rsc_NONE: case Rsc_NONE:
CriterionScore = Prj_DB_GetScore (Projects->Prj.PrjCod,Criterion.CriCod);
if (ICanFill) if (ICanFill)
{ {
Frm_BeginFormAnchor (ActChgPrjSco,Anchor); Frm_BeginFormAnchor (ActChgPrjSco,Anchor);
@ -858,7 +864,7 @@ static void RubCri_ListOneOrMoreCriteriaInProject (struct Prj_Projects *Projects
Criterion.Values[RubCri_MIN], Criterion.Values[RubCri_MIN],
Criterion.Values[RubCri_MAX], Criterion.Values[RubCri_MAX],
RubCri_SCORE_STEP, RubCri_SCORE_STEP,
Score, CriterionScore,
HTM_SUBMIT_ON_CHANGE,false, HTM_SUBMIT_ON_CHANGE,false,
" class=\"INPUT_FLOAT INPUT_%s\"" " class=\"INPUT_FLOAT INPUT_%s\""
" required=\"required\"", " required=\"required\"",
@ -866,10 +872,15 @@ static void RubCri_ListOneOrMoreCriteriaInProject (struct Prj_Projects *Projects
Frm_EndForm (); Frm_EndForm ();
} }
else else
HTM_Double2Decimals (Score); HTM_Double2Decimals (CriterionScore);
break; break;
case Rsc_RUBRIC: case Rsc_RUBRIC:
HTM_Double2Decimals (Score); if (RubCri_ComputeRubricScore (Projects->Prj.PrjCod,TOS,
Criterion.Link.Cod,
&CriterionScore))
Err_RecursiveRubric ();
else
HTM_Double2Decimals (CriterionScore);
break; break;
default: default:
Err_NoPermission (); Err_NoPermission ();
@ -881,11 +892,17 @@ static void RubCri_ListOneOrMoreCriteriaInProject (struct Prj_Projects *Projects
HTM_TD_Begin ("class=\"RT DAT_%s %s\"", HTM_TD_Begin ("class=\"RT DAT_%s %s\"",
The_GetSuffix (), The_GetSuffix (),
The_GetColorRows ()); The_GetColorRows ());
WeightedScore = CriterionScore * Criterion.Weight;
HTM_Double2Decimals (WeightedScore); HTM_Double2Decimals (WeightedScore);
HTM_TD_End (); HTM_TD_End ();
/***** End row *****/ /***** End row *****/
HTM_TR_End (); HTM_TR_End ();
/***** Update totals *****/
SumOfWeights += Criterion.Weight;
SumOfScores += CriterionScore;
WeightedSum += WeightedScore;
} }
/***** Write total row *****/ /***** Write total row *****/
@ -989,50 +1006,119 @@ static void RubCri_WriteTotalValue (double Total)
/*****************************************************************************/ /*****************************************************************************/
/********** Recursive function to compute the score of a criterion ***********/ /********** Recursive function to compute the score of a criterion ***********/
/*****************************************************************************/ /*****************************************************************************/
// Return true if rubric tree is recursive
static double RubCri_ComputeScore (long PrjCod, static bool RubCri_ComputeRubricScore (long PrjCod,struct Node **TOS,long RubCod,
const struct RubCri_Criterion *Criterion) double *RubricScore)
{ {
bool RecursiveTree;
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
unsigned NumCriteria; unsigned NumCriteria;
unsigned NumCriterion; unsigned NumCriterion;
struct RubCri_Criterion CriterionChild; struct RubCri_Criterion Criterion;
double ScoreChild; double CriterionScore;
double Score;
switch (Criterion->Link.Type) /***** Initialize rubric score *****/
*RubricScore = 0.0;
/***** Check that rubric is not yet in the stack *****/
RecursiveTree = Rub_FindRubCodInStack (*TOS,RubCod);
if (!RecursiveTree)
{ {
case Rsc_NONE: /***** Push rubric code in stack *****/
Score = Prj_DB_GetScore (PrjCod,Criterion->CriCod); Rub_PushRubCod (TOS,RubCod);
break;
case Rsc_RUBRIC:
Score = 0.0;
/***** Get data of rubric criteria from database *****/ /***** Get data of rubric criteria from database *****/
NumCriteria = Rub_DB_GetCriteria (&mysql_res,Criterion->Link.Cod); NumCriteria = Rub_DB_GetCriteria (&mysql_res,RubCod);
for (NumCriterion = 0; for (NumCriterion = 0;
NumCriterion < NumCriteria; NumCriterion < NumCriteria;
NumCriterion++) NumCriterion++)
{ {
/***** Get criterion data *****/ /***** Get criterion data *****/
RubCri_GetCriterionDataFromRow (mysql_res,&CriterionChild); RubCri_GetCriterionDataFromRow (mysql_res,&Criterion);
/* Get/compute criterion score */
CriterionScore = 0.0;
switch (Criterion.Link.Type)
{
case Rsc_NONE:
CriterionScore = Prj_DB_GetScore (PrjCod,Criterion.CriCod);
break;
case Rsc_RUBRIC:
if (RubCri_ComputeRubricScore (PrjCod,TOS,Criterion.Link.Cod,
&CriterionScore))
RecursiveTree = true;
break;
default:
break;
}
/***** Compute score of this criterion in the child rubric *****/ /***** Compute score of this criterion in the child rubric *****/
ScoreChild = RubCri_ComputeScore (PrjCod,&CriterionChild); *RubricScore += Criterion.Weight * CriterionScore; // Update weighted sum
/***** Update weighted sum *****/
Score += CriterionChild.Weight * ScoreChild;
} }
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
break;
default: /***** Pop rubric code from stack *****/
Score = 0.0; Rub_PopRubCod (TOS);
break;
} }
return Score; return RecursiveTree;
}
/*****************************************************************************/
/********************** Push/pop rubric code in stack ************************/
/*****************************************************************************/
void Rub_PushRubCod (struct Node **TOS,long RubCod)
{
struct Node *Node;
/***** Save current top of stack *****/
Node = *TOS;
/***** Create top of stack node *****/
if ((*TOS = malloc (sizeof (struct Node))) == NULL)
Err_NotEnoughMemoryExit ();
(*TOS)->RubCod = RubCod;
(*TOS)->Prev = Node; // Link to previous top of stack
}
void Rub_PopRubCod (struct Node **TOS)
{
struct Node *Node;
if (*TOS)
{
/***** Save current top of stack *****/
Node = (*TOS)->Prev;
/***** Free current top of stack node *****/
free (*TOS);
/***** Assign new top of stack *****/
*TOS = Node;
}
}
/*****************************************************************************/
/************************ Find rubric code in stack **************************/
/*****************************************************************************/
// Return true if found
bool Rub_FindRubCodInStack (const struct Node *TOS,long RubCod)
{
while (TOS)
{
if (TOS->RubCod == RubCod)
return true;
TOS = TOS->Prev;
}
return false;
} }
/*****************************************************************************/ /*****************************************************************************/

View File

@ -47,6 +47,10 @@ void RubCri_ListCriteriaForEdition (struct Rub_Rubrics *Rubrics);
void RubCri_ListCriteriaInProject (struct Prj_Projects *Projects,long RubCod, void RubCri_ListCriteriaInProject (struct Prj_Projects *Projects,long RubCod,
bool ICanFill); bool ICanFill);
void Rub_PushRubCod (struct Node **TOS,long RubCod);
void Rub_PopRubCod (struct Node **TOS);
bool Rub_FindRubCodInStack (const struct Node *TOS,long RubCod);
double RubCri_GetParScore (void); double RubCri_GetParScore (void);
void RubCri_GetCriterionDataFromRow (MYSQL_RES *mysql_res, void RubCri_GetCriterionDataFromRow (MYSQL_RES *mysql_res,