admin: Can gain points for each question answered // partial exercice solved
This commit is contained in:
parent
4ca2bc106a
commit
8e196136c3
@ -310,6 +310,7 @@ func ApplySettings(config *settings.Settings) {
|
||||
fic.SubmissionCostBase = config.SubmissionCostBase
|
||||
fic.SubmissionUniqueness = config.SubmissionUniqueness
|
||||
fic.CountOnlyNotGoodTries = config.CountOnlyNotGoodTries
|
||||
fic.QuestionGainRatio = config.QuestionGainRatio
|
||||
|
||||
if config.DiscountedFactor != fic.DiscountedFactor {
|
||||
fic.DiscountedFactor = config.DiscountedFactor
|
||||
@ -329,6 +330,7 @@ func ResetSettings() error {
|
||||
WChoiceCurCoefficient: 1,
|
||||
GlobalScoreCoefficient: 1,
|
||||
DiscountedFactor: 0,
|
||||
QuestionGainRatio: 0,
|
||||
UnlockedStandaloneExercices: 10,
|
||||
UnlockedStandaloneExercicesByThemeStepValidation: 1,
|
||||
UnlockedStandaloneExercicesByStandaloneExerciceValidation: 0,
|
||||
|
@ -104,6 +104,12 @@
|
||||
<input type="text" class="form-control form-control-sm" id="submissionCostBase" ng-model="config.submissionCostBase" float ng-class="{'border-primary': config.submissionCostBase != dist_config.submissionCostBase}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm row" title="Accorder des points aux exercices partiellement résolu, par questions validée. Ce champ est le pourcentage de points que peut rapporter la complétion de toutes les questions d'un exercice. Par exemple avec 25%, un exercice avec 10 questions, chaque question validée rapportera GAIN * 25% / 10">
|
||||
<label for="questionGainRatio" class="col-sm-8 col-form-label col-form-label-sm text-right text-truncate" ng-class="{'text-primary font-weight-bold': config.questionGainRatio != dist_config.questionGainRatio}">Gain par questions</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control form-control-sm" id="questionGainRatio" ng-model="config.questionGainRatio" float ng-class="{'border-primary': config.questionGainRatio != dist_config.questionGainRatio}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
@ -13,7 +13,7 @@
|
||||
<th>Date</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="row in scores | filter: query | orderBy:'time'" ng-class="{'bg-danger': row.reason == 'Bonus flag', 'bg-ffound': row.reason == 'First blood', 'bg-wchoices': row.reason == 'Display choices', 'bg-success': row.reason == 'Validation', 'bg-info': row.reason == 'Hint', 'bg-warning': row.reason == 'Tries'}">
|
||||
<tr ng-repeat="row in scores | filter: query | orderBy:'time'" ng-class="{'bg-danger': row.reason == 'Bonus flag', 'bg-ffound': row.reason == 'First blood', 'bg-wchoices': row.reason == 'Display choices', 'bg-success': row.reason == 'Validation', 'bg-info': row.reason == 'Hint', 'bg-secondary': row.reason.startsWith('Response '), 'bg-warning': row.reason == 'Tries'}">
|
||||
<td>
|
||||
<a ng-repeat="exercice in exercices" ng-if="exercice.id == row.id_exercice" href="exercices/{{ row.id_exercice }}">{{ exercice.title }}</a>
|
||||
</td>
|
||||
@ -23,9 +23,12 @@
|
||||
<td>
|
||||
{{ row.points * row.coeff }}
|
||||
</td>
|
||||
<td>
|
||||
<td ng-if="!row.reason.startsWith('Response ')">
|
||||
{{ row.points }} * {{ row.coeff }}
|
||||
</td>
|
||||
<td ng-if="row.reason.startsWith('Response ')">
|
||||
{{ row.points }} * {{ settings.questionGainRatio }} / {{ settings.questionGainRatio / row.coeff }}
|
||||
</td>
|
||||
<td>
|
||||
<nobr title="{{ row.time }}">{{ row.time | date:"mediumTime" }}</nobr>
|
||||
</td>
|
||||
|
@ -90,6 +90,7 @@ func reloadSettings(config *settings.Settings) {
|
||||
fic.GlobalScoreCoefficient = config.GlobalScoreCoefficient
|
||||
fic.CountOnlyNotGoodTries = config.CountOnlyNotGoodTries
|
||||
fic.DiscountedFactor = config.DiscountedFactor
|
||||
fic.QuestionGainRatio = config.QuestionGainRatio
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@ -10,6 +10,7 @@
|
||||
import DateFormat from '$lib/components/DateFormat.svelte';
|
||||
|
||||
import { my } from '$lib/stores/my.js';
|
||||
import { settings } from '$lib/stores/settings.js';
|
||||
import { themes, exercices_idx } from '$lib/stores/themes.js';
|
||||
|
||||
let req = null;
|
||||
@ -55,6 +56,10 @@
|
||||
{:else if row.reason == "Display choices"}
|
||||
<Badge color="secondary"><Icon name="info-square" /></Badge>
|
||||
Échange champ de texte contre liste de choix
|
||||
{:else if row.reason.startsWith("Response ")}
|
||||
{@const fields = row.reason.split(" ")}
|
||||
<Badge color="secondary"><Icon name="clipboard2-check" /></Badge>
|
||||
Validation {fields[1]}
|
||||
{:else}
|
||||
<Badge color="primary"><Icon name="question" /></Badge>
|
||||
{row.reason}
|
||||
@ -66,7 +71,7 @@
|
||||
{/if}
|
||||
</Column>
|
||||
<Column header="Détail">
|
||||
<span title="Valeur initiale (cette valeur est fixe)">{Math.trunc(10*row.points)/10}</span> × <span title="Coefficient multiplicateur (il varie selon les événements en cours sur la plateforme)">{row.coeff}</span>
|
||||
<span title="Valeur initiale (cette valeur est fixe)">{Math.trunc(10*row.points)/10}</span> × {#if row.reason.startsWith("Response ")}<span title="Pourcentage des points accordés pour avoir répondu aux questions d'un défi, sans avoir validé entièrement le défi">{$settings.questionGainRatio}</span> ÷ <span title="Nombre de questions du défi">{$settings.questionGainRatio / row.coeff}</span>{:else}<span title="Coefficient multiplicateur (il varie selon les événements en cours sur la plateforme)">{row.coeff}</span>{/if}
|
||||
</Column>
|
||||
<Column header="Points">
|
||||
{Math.trunc(10*row.points * row.coeff)/10}
|
||||
|
@ -30,7 +30,7 @@ func reloadSettings(config *settings.Settings) {
|
||||
fic.WChoiceCoefficient = config.WChoiceCurCoefficient
|
||||
fic.ExerciceCurrentCoefficient = config.ExerciceCurCoefficient
|
||||
ChStarted = config.Start.Unix() > 0 && time.Since(config.Start) >= 0
|
||||
if allowRegistration != config.AllowRegistration || fic.PartialValidation != config.PartialValidation || fic.UnlockedChallengeDepth != config.UnlockedChallengeDepth || fic.UnlockedStandaloneExercices != config.UnlockedStandaloneExercices || fic.UnlockedStandaloneExercicesByThemeStepValidation != config.UnlockedStandaloneExercicesByThemeStepValidation || fic.UnlockedStandaloneExercicesByStandaloneExerciceValidation != config.UnlockedStandaloneExercicesByStandaloneExerciceValidation || fic.UnlockedChallengeUpTo != config.UnlockedChallengeUpTo || fic.DisplayAllFlags != config.DisplayAllFlags || fic.FirstBlood != config.FirstBlood || fic.SubmissionCostBase != config.SubmissionCostBase || fic.SubmissionUniqueness != config.SubmissionUniqueness || fic.DiscountedFactor != config.DiscountedFactor || fic.HideCaseSensitivity != config.HideCaseSensitivity {
|
||||
if allowRegistration != config.AllowRegistration || fic.PartialValidation != config.PartialValidation || fic.UnlockedChallengeDepth != config.UnlockedChallengeDepth || fic.UnlockedStandaloneExercices != config.UnlockedStandaloneExercices || fic.UnlockedStandaloneExercicesByThemeStepValidation != config.UnlockedStandaloneExercicesByThemeStepValidation || fic.UnlockedStandaloneExercicesByStandaloneExerciceValidation != config.UnlockedStandaloneExercicesByStandaloneExerciceValidation || fic.UnlockedChallengeUpTo != config.UnlockedChallengeUpTo || fic.DisplayAllFlags != config.DisplayAllFlags || fic.FirstBlood != config.FirstBlood || fic.SubmissionCostBase != config.SubmissionCostBase || fic.SubmissionUniqueness != config.SubmissionUniqueness || fic.DiscountedFactor != config.DiscountedFactor || fic.QuestionGainRatio != config.QuestionGainRatio || fic.HideCaseSensitivity != config.HideCaseSensitivity {
|
||||
allowRegistration = config.AllowRegistration
|
||||
|
||||
fic.PartialValidation = config.PartialValidation
|
||||
@ -48,6 +48,7 @@ func reloadSettings(config *settings.Settings) {
|
||||
fic.CountOnlyNotGoodTries = config.CountOnlyNotGoodTries
|
||||
fic.HideCaseSensitivity = config.HideCaseSensitivity
|
||||
fic.DiscountedFactor = config.DiscountedFactor
|
||||
fic.QuestionGainRatio = config.QuestionGainRatio
|
||||
|
||||
if !skipInitialGeneration {
|
||||
log.Println("Generating files...")
|
||||
|
@ -23,6 +23,9 @@ var CountOnlyNotGoodTries = false
|
||||
// DiscountedFactor stores the percentage of the exercice's gain lost on each validation.
|
||||
var DiscountedFactor = 0.0
|
||||
|
||||
// QuestionGainRatio is the ratio given to a partially solved exercice in the final scoreboard.
|
||||
var QuestionGainRatio = 0.0
|
||||
|
||||
func exoptsQuery(whereExo string) string {
|
||||
tries_table := "exercice_tries"
|
||||
if SubmissionUniqueness {
|
||||
@ -39,8 +42,10 @@ func exoptsQuery(whereExo string) string {
|
||||
}
|
||||
|
||||
query := `SELECT S.id_team, S.time, E.gain AS points, coeff, S.reason, S.id_exercice FROM (
|
||||
SELECT id_team, F.id_exercice AS id_exercice, time, ` + fmt.Sprintf("%f", QuestionGainRatio) + ` / (COALESCE(T.total_flags, 0) + COALESCE(TMCQ.total_mcqs, 0)) AS coeff, CONCAT("Response flag ", F.id_flag) AS reason FROM flag_found B INNER JOIN exercice_flags F ON F.id_flag = B.id_flag LEFT JOIN (SELECT id_exercice, COUNT(*) AS total_flags FROM exercice_flags GROUP BY id_exercice) T ON F.id_exercice = T.id_exercice LEFT JOIN (SELECT id_exercice, COUNT(*) AS total_mcqs FROM exercice_mcq GROUP BY id_exercice) TMCQ ON F.id_exercice = TMCQ.id_exercice WHERE F.bonus_gain = 0 UNION
|
||||
SELECT id_team, F.id_exercice AS id_exercice, time, ` + fmt.Sprintf("%f", QuestionGainRatio) + ` / (COALESCE(T.total_flags, 0) + COALESCE(TMCQ.total_mcqs, 0)) AS coeff, CONCAT("Response MCQ ", F.id_mcq) AS reason FROM mcq_found B INNER JOIN exercice_mcq F ON F.id_mcq = B.id_mcq LEFT JOIN (SELECT id_exercice, COUNT(*) AS total_flags FROM exercice_flags GROUP BY id_exercice) T ON F.id_exercice = T.id_exercice LEFT JOIN (SELECT id_exercice, COUNT(*) AS total_mcqs FROM exercice_mcq GROUP BY id_exercice) TMCQ ON F.id_exercice = TMCQ.id_exercice UNION
|
||||
SELECT id_team, id_exercice, time, ` + fmt.Sprintf("%f", FirstBlood) + ` AS coeff, "First blood" AS reason FROM exercice_solved JOIN (SELECT id_exercice, MIN(time) time FROM exercice_solved GROUP BY id_exercice) d1 USING (id_exercice, time) UNION
|
||||
SELECT id_team, id_exercice, time, coefficient AS coeff, "Validation" AS reason FROM exercice_solved
|
||||
SELECT id_team, id_exercice, time, coefficient - ` + fmt.Sprintf("%f", QuestionGainRatio) + ` AS coeff, "Validation" AS reason FROM exercice_solved
|
||||
) S INNER JOIN ` + exercices_table + ` E ON S.id_exercice = E.id_exercice UNION ALL
|
||||
SELECT B.id_team, B.time, F.bonus_gain AS points, 1 AS coeff, "Bonus flag" AS reason, F.id_exercice FROM flag_found B INNER JOIN exercice_flags F ON F.id_flag = B.id_flag WHERE F.bonus_gain != 0 HAVING points != 0 UNION ALL
|
||||
SELECT id_team, MAX(time) AS time, (FLOOR(COUNT(*)/10 - 1) * (FLOOR(COUNT(*)/10)))/0.2 + (FLOOR(COUNT(*)/10) * (COUNT(*)%10)) AS points, ` + fmt.Sprintf("%f", SubmissionCostBase*-1) + ` AS coeff, "Tries" AS reason, id_exercice FROM ` + tries_table + ` S GROUP BY id_exercice, id_team`
|
||||
|
@ -46,6 +46,8 @@ type Settings struct {
|
||||
GlobalScoreCoefficient float64 `json:"globalScoreCoefficient"`
|
||||
// DiscountedFactor stores the percentage of the exercice's gain lost on each validation.
|
||||
DiscountedFactor float64 `json:"discountedFactor,omitempty"`
|
||||
// QuestionGainRatio is the ratio given to a partially solved exercice in the final scoreboard.
|
||||
QuestionGainRatio float64 `json:"questionGainRatio,omitempty"`
|
||||
|
||||
// AllowRegistration permits unregistered Team to register themselves.
|
||||
AllowRegistration bool `json:"allowRegistration,omitempty"`
|
||||
|
Loading…
x
Reference in New Issue
Block a user