diff --git a/admin/api/team.go b/admin/api/team.go index 0755468b..bb4ca9f5 100644 --- a/admin/api/team.go +++ b/admin/api/team.go @@ -45,6 +45,10 @@ func init() { func(team fic.Team, _ []byte) (interface{}, error) { return team.Delete() }))) + router.GET("/api/teams/:tid/score-grid.json", apiHandler(teamHandler( + func(team fic.Team, _ []byte) (interface{}, error) { + return team.ScoreGrid() + }))) router.GET("/api/teams/:tid/my.json", apiHandler(teamPublicHandler( func(team *fic.Team, _ []byte) (interface{}, error) { return fic.MyJSONTeam(team, true) diff --git a/libfic/stats.go b/libfic/stats.go index fff01e09..774b74d6 100644 --- a/libfic/stats.go +++ b/libfic/stats.go @@ -21,21 +21,55 @@ func exoptsQuery(whereExo string) string { 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 + return `SELECT S.id_team, S.time, E.gain AS points, coeff, S.reason, S.id_exercice FROM ( + SELECT id_team, id_exercice, MIN(time) AS time, ` + fmt.Sprintf("%f", FirstBlood) + ` AS coeff, "First blood" AS reason FROM exercice_solved GROUP BY id_exercice UNION + SELECT id_team, id_exercice, time, coefficient AS coeff, "Validation" AS reason 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 ` + tries_table + ` 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, "Tries" AS reason, id_exercice FROM ` + tries_table + ` S ` + whereExo + ` GROUP BY id_exercice, id_team` +} + +func teamptsQuery() string { + return exoptsQuery("") + ` UNION ALL + SELECT D.id_team, D.time, H.cost AS points, -1.0 AS coeff, "Hint" AS reason, H.id_exercice FROM team_hints D INNER JOIN exercice_hints H ON H.id_hint = D.id_hint HAVING points != 0 UNION ALL + SELECT W.id_team, W.time, F.choices_cost AS points, -1.0 AS coeff, "Display choices" AS reason, F.id_exercice FROM team_wchoices W INNER JOIN exercice_flags F ON F.id_flag = W.id_flag HAVING points != 0` } func rankQuery(whereTeam string) string { return `SELECT A.id_team, SUM(A.points * A.coeff) AS score, MAX(A.time) AS time FROM ( - ` + exoptsQuery("") + ` UNION ALL - SELECT D.id_team, D.time, H.cost AS points, -1.0 AS coeff FROM team_hints D INNER JOIN exercice_hints H ON H.id_hint = D.id_hint HAVING points != 0 UNION ALL - SELECT W.id_team, W.time, F.choices_cost AS points, -1.0 AS coeff FROM team_wchoices W INNER JOIN exercice_flags F ON F.id_flag = W.id_flag HAVING points != 0 + ` + teamptsQuery() + ` ) A ` + whereTeam + ` GROUP BY A.id_team ORDER BY score DESC, time ASC` } +func (t Team) ScoreGrid() (grid []map[string]interface{}, err error) { + q := "SELECT G.reason, G.id_exercice, G.time, G.points, G.coeff FROM (" + teamptsQuery() + ") AS G WHERE G.id_team = ? AND G.points != 0" + if rows, err := DBQuery(q, t.Id); err != nil { + return nil, err + } else { + defer rows.Close() + + for rows.Next() { + var reason string + var exercice int64 + var time time.Time + var points float64 + var coeff float64 + + if err := rows.Scan(&reason, &exercice, &time, &points, &coeff); err != nil { + return nil, err + } + + grid = append(grid, map[string]interface{}{ + "reason": reason, + "id_exercice": exercice, + "time": time, + "points": points, + "coeff": coeff, + }) + } + } + return +} + // Points // EstimateGain calculates the amount of point the Team has (or could have, if not already solved) won.