From 910ec94fd85468bbc794ffd2959c53c0a0c10eaa Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 6 Dec 2018 22:18:08 +0100 Subject: [PATCH] Add a new setting to don't count same responses in scores --- admin/api/settings.go | 1 + admin/static/views/settings.html | 7 +++++++ backend/main.go | 1 + libfic/db.go | 5 +++++ libfic/exercice.go | 14 ++++++++++++-- libfic/stats.go | 10 +++++++++- libfic/team.go | 9 +++++++-- settings/settings.go | 2 ++ 8 files changed, 44 insertions(+), 5 deletions(-) diff --git a/admin/api/settings.go b/admin/api/settings.go index a5767c99..a8610624 100644 --- a/admin/api/settings.go +++ b/admin/api/settings.go @@ -54,6 +54,7 @@ func ApplySettings(config settings.FICSettings) { fic.UnlockedChallenges = !config.EnableExerciceDepend fic.FirstBlood = config.FirstBlood fic.SubmissionCostBase = config.SubmissionCostBase + fic.SubmissionUniqueness = config.SubmissionUniqueness } func reset(_ httprouter.Params, body []byte) (interface{}, error) { diff --git a/admin/static/views/settings.html b/admin/static/views/settings.html index 0808cb31..fbebb8ef 100644 --- a/admin/static/views/settings.html +++ b/admin/static/views/settings.html @@ -116,6 +116,13 @@ +
+ +
+ diff --git a/backend/main.go b/backend/main.go index 2b7e9ee7..b6250798 100644 --- a/backend/main.go +++ b/backend/main.go @@ -54,6 +54,7 @@ func reloadSettings(config settings.FICSettings) { fic.FirstBlood = config.FirstBlood fic.SubmissionCostBase = config.SubmissionCostBase + fic.SubmissionUniqueness = config.SubmissionUniqueness log.Println("Generating files...") go func() { diff --git a/libfic/db.go b/libfic/db.go index f8c452e9..9beef4bc 100644 --- a/libfic/db.go +++ b/libfic/db.go @@ -346,7 +346,12 @@ CREATE TABLE IF NOT EXISTS claim_descriptions( ) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; `); err != nil { return err +} + + if _, err := db.Exec("CREATE OR REPLACE VIEW exercice_distinct_tries AS SELECT id_exercice, id_team, MAX(time) AS time, cksum, nbdiff FROM exercice_tries GROUP BY id_team, id_exercice, cksum;"); err != nil { + return err } + return nil } diff --git a/libfic/exercice.go b/libfic/exercice.go index e0877f40..6c05dc96 100644 --- a/libfic/exercice.go +++ b/libfic/exercice.go @@ -343,8 +343,13 @@ func (e Exercice) SolvedCount() int64 { // TriedTeamCount returns the number of Team that attempted to solve the exercice. func (e Exercice) TriedTeamCount() int64 { + tries_table := "exercice_tries" + if SubmissionUniqueness { + tries_table = "exercice_distinct_tries" + } + var nb int64 - if err := DBQueryRow("SELECT COUNT(DISTINCT id_team) FROM exercice_tries WHERE id_exercice = ?", e.Id).Scan(&nb); err != nil { + if err := DBQueryRow("SELECT COUNT(DISTINCT id_team) FROM " + tries_table + " WHERE id_exercice = ?", e.Id).Scan(&nb); err != nil { return 0 } else { return nb @@ -353,8 +358,13 @@ func (e Exercice) TriedTeamCount() int64 { // TriedCount returns the number of cumulative attempts, all Team combined, for the exercice. func (e Exercice) TriedCount() int64 { + tries_table := "exercice_tries" + if SubmissionUniqueness { + tries_table = "exercice_distinct_tries" + } + var nb int64 - if err := DBQueryRow("SELECT COUNT(id_team) FROM exercice_tries WHERE id_exercice = ?", e.Id).Scan(&nb); err != nil { + if err := DBQueryRow("SELECT COUNT(id_team) FROM " + tries_table + " WHERE id_exercice = ?", e.Id).Scan(&nb); err != nil { return 0 } else { return nb diff --git a/libfic/stats.go b/libfic/stats.go index 9d801f61..fff01e09 100644 --- a/libfic/stats.go +++ b/libfic/stats.go @@ -12,12 +12,20 @@ var FirstBlood = 0.12 // SubmissionCostBase is the basis amount of point lost per submission var SubmissionCostBase = 0.5 +// SubmissionUniqueness don't count multiple times identical tries. +var SubmissionUniqueness = false + func exoptsQuery(whereExo string) string { + tries_table := "exercice_tries" + if SubmissionUniqueness { + tries_table = "exercice_distinct_tries" + } + return `SELECT S.id_team, S.time, E.gain AS points, coeff FROM ( SELECT id_team, id_exercice, MIN(time) AS time, ` + fmt.Sprintf("%f", FirstBlood) + ` AS coeff FROM exercice_solved GROUP BY id_exercice UNION SELECT id_team, id_exercice, time, coefficient AS coeff FROM exercice_solved ) S INNER JOIN exercices E ON S.id_exercice = E.id_exercice ` + whereExo + ` 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 FROM exercice_tries S ` + whereExo + ` GROUP BY id_exercice, id_team` + 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 FROM ` + tries_table + ` S ` + whereExo + ` GROUP BY id_exercice, id_team` } func rankQuery(whereTeam string) string { diff --git a/libfic/team.go b/libfic/team.go index 62c3697f..b455bc96 100644 --- a/libfic/team.go +++ b/libfic/team.go @@ -145,12 +145,17 @@ func (t Team) CanSeeFlag(k Flag) bool { // NbTry retrieves the number of attempts made by the Team to the given challenge. func NbTry(t *Team, e Exercice) int { + tries_table := "exercice_tries" + if SubmissionUniqueness { + tries_table = "exercice_distinct_tries" + } + var cnt *int if t != nil { - DBQueryRow("SELECT COUNT(*) FROM exercice_tries WHERE id_team = ? AND id_exercice = ?", t.Id, e.Id).Scan(&cnt) + DBQueryRow("SELECT COUNT(*) FROM " + tries_table + " WHERE id_team = ? AND id_exercice = ?", t.Id, e.Id).Scan(&cnt) } else { - DBQueryRow("SELECT COUNT(*) FROM exercice_tries WHERE id_exercice = ?", e.Id).Scan(&cnt) + DBQueryRow("SELECT COUNT(*) FROM " + tries_table + " WHERE id_exercice = ?", e.Id).Scan(&cnt) } if cnt == nil { diff --git a/settings/settings.go b/settings/settings.go index 30e3161e..700bb9c1 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -49,6 +49,8 @@ type FICSettings struct { PartialValidation bool `json:"partialValidation"` // EnableExerciceDepend don't show (or permit to solve) to team challenges they are not unlocked through dependancies. EnableExerciceDepend bool `json:"enableExerciceDepend"` + // SubmissionUniqueness don't count multiple times identical tries. + SubmissionUniqueness bool `json:"submissionUniqueness"` } // ExistsSettings checks if the settings file can by found at the given path.