2016-12-27 20:12:17 +00:00
package fic
import (
"database/sql"
2016-12-30 11:45:14 +00:00
"fmt"
2016-12-27 20:12:17 +00:00
"time"
)
2018-03-09 18:07:08 +00:00
// FirstBlood is the coefficient added to the challenge coefficient when a Team is the first to solve a challenge.
2016-12-30 11:45:14 +00:00
var FirstBlood = 0.12
2018-03-09 18:07:08 +00:00
// SubmissionCostBase is the basis amount of point lost per submission
2016-12-30 11:45:14 +00:00
var SubmissionCostBase = 0.5
2017-01-16 11:08:15 +00:00
func exoptsQuery ( whereExo string ) string {
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"
}
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) A " + whereTeam + " GROUP BY A.id_team ORDER BY score DESC, time ASC"
}
2016-12-27 20:12:17 +00:00
// Points
2018-03-09 18:07:08 +00:00
// EstimateGain calculates the amount of point the Team has (or could have, if not already solved) won.
2017-01-16 11:08:15 +00:00
func ( e Exercice ) EstimateGain ( t Team , solved bool ) ( float64 , error ) {
var pts float64
err := DBQueryRow ( "SELECT SUM(A.points * A.coeff) AS score FROM (" + exoptsQuery ( "WHERE S.id_team = ? AND S.id_exercice = ?" ) + ") A GROUP BY id_team" , t . Id , e . Id , t . Id , e . Id ) . Scan ( & pts )
if solved {
return pts , err
} else {
pts += float64 ( e . Gain ) * e . Coefficient
if e . SolvedCount ( ) <= 0 {
pts += float64 ( e . Gain ) * FirstBlood
}
return pts , nil
}
}
2018-03-09 18:07:08 +00:00
// GetPoints returns the score for the Team.
2017-01-12 10:52:51 +00:00
func ( t Team ) GetPoints ( ) ( float64 , error ) {
2017-01-16 11:08:15 +00:00
var tid * int64
2017-01-12 10:52:51 +00:00
var nb * float64
2017-01-16 11:08:15 +00:00
var tzzz * time . Time
err := DBQueryRow ( rankQuery ( "WHERE A.id_team = ?" ) , t . Id ) . Scan ( & tid , & nb , & tzzz )
2016-12-27 20:12:17 +00:00
if nb != nil {
return * nb , err
} else {
return 0 , err
}
}
2018-03-09 18:07:08 +00:00
// GetRank returns a map which associates team ID their rank.
2016-12-27 20:12:17 +00:00
func GetRank ( ) ( map [ int64 ] int , error ) {
2017-01-16 11:08:15 +00:00
if rows , err := DBQuery ( rankQuery ( "" ) ) ; err != nil {
2016-12-27 20:12:17 +00:00
return nil , err
} else {
defer rows . Close ( )
rank := map [ int64 ] int { }
nteam := 0
for rows . Next ( ) {
nteam += 1
var tid int64
2017-01-12 10:52:51 +00:00
var score float64
2016-12-27 20:12:17 +00:00
var tzzz time . Time
if err := rows . Scan ( & tid , & score , & tzzz ) ; err != nil {
return nil , err
}
rank [ tid ] = nteam
}
if err := rows . Err ( ) ; err != nil {
return nil , err
}
return rank , nil
}
}
2018-03-09 18:07:08 +00:00
// Attempts
2016-12-27 20:12:17 +00:00
2018-03-09 18:07:08 +00:00
// GetTries retrieves all attempts made by the matching Team or challenge (both can be nil to not filter).
func GetTries ( t * Team , e * Exercice ) ( times [ ] time . Time , err error ) {
2016-12-27 20:12:17 +00:00
var rows * sql . Rows
if t == nil {
if e == nil {
rows , err = DBQuery ( "SELECT time FROM exercice_tries ORDER BY time ASC" )
} else {
rows , err = DBQuery ( "SELECT time FROM exercice_tries WHERE id_exercice = ? ORDER BY time ASC" , e . Id )
}
} else {
if e == nil {
rows , err = DBQuery ( "SELECT time FROM exercice_tries WHERE id_team = ? ORDER BY time ASC" , t . Id )
} else {
rows , err = DBQuery ( "SELECT time FROM exercice_tries WHERE id_team = ? AND id_exercice = ? ORDER BY time ASC" , t . Id , e . Id )
}
}
if err != nil {
2018-03-09 18:07:08 +00:00
return
2016-12-27 20:12:17 +00:00
} else {
defer rows . Close ( )
for rows . Next ( ) {
var tm time . Time
2018-03-09 18:07:08 +00:00
if err = rows . Scan ( & tm ) ; err != nil {
return
2016-12-27 20:12:17 +00:00
}
times = append ( times , tm )
}
2018-03-09 18:07:08 +00:00
err = rows . Err ( )
return
2016-12-27 20:12:17 +00:00
}
}
2018-03-09 18:07:08 +00:00
// GetTryRank generates a special rank based on number of attempts
2016-12-27 20:12:17 +00:00
func GetTryRank ( ) ( [ ] int64 , error ) {
if rows , err := DBQuery ( "SELECT id_team, COUNT(*) AS score FROM exercice_tries GROUP BY id_team HAVING score > 0 ORDER BY score DESC" ) ; err != nil {
return nil , err
} else {
defer rows . Close ( )
rank := make ( [ ] int64 , 0 )
for rows . Next ( ) {
var tid int64
var score int64
if err := rows . Scan ( & tid , & score ) ; err != nil {
return nil , err
}
rank = append ( rank , tid )
}
if err := rows . Err ( ) ; err != nil {
return nil , err
}
return rank , nil
}
}