diff --git a/atcoder-problems-backend/sql-client/src/problem_info.rs b/atcoder-problems-backend/sql-client/src/problem_info.rs index 2af948db..d4434990 100644 --- a/atcoder-problems-backend/sql-client/src/problem_info.rs +++ b/atcoder-problems-backend/sql-client/src/problem_info.rs @@ -27,6 +27,16 @@ impl ProblemInfoUpdater for PgPool { Ok(()) } + /// 各問題の点数を計算して更新する。 + /// + /// ある問題への提出のうち、 __コンテスト開始後の提出__ における最も大きい得点がその問題の点数となる。 + /// + /// コンテスト開始前、writerなどが仮の点数が付けられている問題をACすることがあり、 + /// 仮の点数がコンテストでの正式な点数より大きかった場合には、仮の点数がAtCoder Problemsでの正式な点数とされてしまう。 + /// これを防ぐために、コンテスト開始前の提出は点数計算で考慮しないようにしている。 + /// + /// 「コンテスト開始前にwriterがACしているが、コンテスト開始以降に一人もACできていない」場合は点数が + /// 計算されないという問題があるが、現時点ではその問題は発生していないため対応は保留されている。 async fn update_problem_points(&self) -> Result<()> { sqlx::query( r" @@ -35,6 +45,7 @@ impl ProblemInfoUpdater for PgPool { FROM submissions INNER JOIN contests ON contests.id = submissions.contest_id WHERE contests.start_epoch_second >= $1 + AND submissions.epoch_second >= contests.start_epoch_second AND contests.rate_change != '-' GROUP BY submissions.problem_id ON CONFLICT (problem_id) DO UPDATE diff --git a/atcoder-problems-backend/sql-client/tests/test_problem_info.rs b/atcoder-problems-backend/sql-client/tests/test_problem_info.rs index e7951aaa..408ec6c3 100644 --- a/atcoder-problems-backend/sql-client/tests/test_problem_info.rs +++ b/atcoder-problems-backend/sql-client/tests/test_problem_info.rs @@ -87,7 +87,7 @@ async fn test_update_problem_points() { let pool = utils::initialize_and_connect_to_test_sql().await; pool.insert_contests(&[Contest { id: contest_id.to_string(), - start_epoch_second: 1468670400, + start_epoch_second: 1687608000, // 2023/06/24 21:00:00 JST rate_change: "All".to_string(), duration_second: 0, @@ -98,33 +98,42 @@ async fn test_update_problem_points() { assert!(get_points(&pool).await.is_empty()); + // コンテスト開始前の提出 pool.update_submissions(&[Submission { id: 0, - point: 0.0, + point: 625.0, // コンテスト開始前にwriterが設定することがある仮の得点 problem_id: problem_id.to_string(), contest_id: contest_id.to_string(), + epoch_second: 1687208168, // 2023/06/20 05:56:08 JST ..Default::default() }]) .await .unwrap(); - pool.update_problem_points().await.unwrap(); - assert_eq!( - get_points(&pool).await, - vec![("problem".to_string(), Some(0.0))] - ); - pool.update_submissions(&[Submission { - id: 1, - point: 100.0, - problem_id: problem_id.to_string(), - contest_id: contest_id.to_string(), - ..Default::default() - }]) + // コンテスト開始後の提出 + pool.update_submissions(&[ + Submission { + id: 1, + point: 100.0, + problem_id: problem_id.to_string(), + contest_id: contest_id.to_string(), + epoch_second: 1687608000, // 2023/07/08 21:00:00 JST + ..Default::default() + }, + Submission { + id: 2, + point: 550.0, // こっちが正式な得点 + problem_id: problem_id.to_string(), + contest_id: contest_id.to_string(), + epoch_second: 1687608000, // 2023/07/08 21:00:00 JST + ..Default::default() + }, + ]) .await .unwrap(); pool.update_problem_points().await.unwrap(); assert_eq!( get_points(&pool).await, - vec![("problem".to_string(), Some(100.0))] + vec![("problem".to_string(), Some(550.0))] ); }