mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-11-26 07:08:41 +00:00
128 lines
3.4 KiB
PHP
128 lines
3.4 KiB
PHP
<?php
|
|
define("CONTEST_NOT_STARTED", 0);
|
|
define("CONTEST_IN_PROGRESS", 1);
|
|
define("CONTEST_PENDING_FINAL_TEST", 2);
|
|
define("CONTEST_TESTING", 10);
|
|
define("CONTEST_FINISHED", 20);
|
|
|
|
function calcRating($standings, $K = 400) {
|
|
$DELTA = 500;
|
|
|
|
$n = count($standings);
|
|
|
|
$rating = array();
|
|
for ($i = 0; $i < $n; ++$i) {
|
|
$rating[$i] = $standings[$i][2][1];
|
|
}
|
|
|
|
$rank = array();
|
|
$foot = array();
|
|
for ($i = 0; $i < $n; ) {
|
|
$j = $i;
|
|
while ($j + 1 < $n && $standings[$j + 1][3] == $standings[$j][3]) {
|
|
++$j;
|
|
}
|
|
$our_rk = 0.5 * (($i + 1) + ($j + 1));
|
|
while ($i <= $j) {
|
|
$rank[$i] = $our_rk;
|
|
$foot[$i] = $n - $rank[$i];
|
|
$i++;
|
|
}
|
|
}
|
|
|
|
$weight = array();
|
|
for ($i = 0; $i < $n; ++$i) {
|
|
$weight[$i] = pow(7, $rating[$i] / $DELTA);
|
|
}
|
|
$exp = array_fill(0, $n, 0);
|
|
for ($i = 0; $i < $n; ++$i)
|
|
for ($j = 0; $j < $n; ++$j)
|
|
if ($j != $i) {
|
|
$exp[$i] += $weight[$i] / ($weight[$i] + $weight[$j]);
|
|
}
|
|
|
|
$new_rating = array();
|
|
for ($i = 0; $i < $n; $i++) {
|
|
$new_rating[$i] = $rating[$i];
|
|
$new_rating[$i] += ceil($K * ($foot[$i] - $exp[$i]) / ($n - 1));
|
|
}
|
|
|
|
for ($i = $n - 1; $i >= 0; $i--) {
|
|
if ($i + 1 < $n && $standings[$i][3] != $standings[$i + 1][3]) {
|
|
break;
|
|
}
|
|
if ($new_rating[$i] > $rating[$i]) {
|
|
$new_rating[$i] = $rating[$i];
|
|
}
|
|
}
|
|
|
|
for ($i = 0; $i < $n; $i++) {
|
|
if ($new_rating[$i] < 0) {
|
|
$new_rating[$i] = 0;
|
|
}
|
|
}
|
|
|
|
return $new_rating;
|
|
}
|
|
|
|
function calcRatingSelfTest() {
|
|
$tests = [
|
|
[[1500, 1], [1500, 1]],
|
|
[[1500, 1], [1600, 1]],
|
|
[[1500, 1], [1600, 2], [1600, 2]],
|
|
[[1500, 1], [200, 2], [100, 2]],
|
|
[[1500, 1], [100, 2], [200, 2]],
|
|
[[1500, 1], [100, 2], [200, 3]],
|
|
[[1500, 1], [200, 2], [100, 3]],
|
|
[[1500, 1], [3000, 2], [1500, 3]],
|
|
[[1500, 1], [3000, 2], [1500, 3], [1500, 3]],
|
|
[[1500, 1], [1500, 2], [1500, 3], [3000, 4]],
|
|
[[1500, 1], [1500, 2], [10, 3], [1, 4]]
|
|
];
|
|
foreach ($tests as $test_num => $test) {
|
|
print "test #{$test_num}\n";
|
|
|
|
$standings = array();
|
|
$n = count($test);
|
|
for ($i = 0; $i < $n; $i++) {
|
|
$standings[] = [0, 0, [(string)$i, $test[$i][0]], $test[$i][1]];
|
|
}
|
|
$new_rating = calcRating($standings);
|
|
|
|
for ($i = 0; $i < $n; $i++) {
|
|
printf("%3d: %4d -> %4d delta: %+4d\n", $test[$i][1], $test[$i][0], $new_rating[$i], $new_rating[$i] - $test[$i][0]);
|
|
}
|
|
print "\n";
|
|
}
|
|
}
|
|
|
|
function genMoreContestInfo(&$contest) {
|
|
$contest['start_time_str'] = $contest['start_time'];
|
|
$contest['start_time'] = new DateTime($contest['start_time']);
|
|
$contest['end_time'] = clone $contest['start_time'];
|
|
$contest['end_time']->add(new DateInterval("PT${contest['last_min']}M"));
|
|
|
|
if ($contest['status'] == 'unfinished') {
|
|
if (UOJTime::$time_now < $contest['start_time']) {
|
|
$contest['cur_progress'] = CONTEST_NOT_STARTED;
|
|
} else if (UOJTime::$time_now < $contest['end_time']) {
|
|
$contest['cur_progress'] = CONTEST_IN_PROGRESS;
|
|
} else {
|
|
$contest['cur_progress'] = CONTEST_PENDING_FINAL_TEST;
|
|
}
|
|
} else if ($contest['status'] == 'testing') {
|
|
$contest['cur_progress'] = CONTEST_TESTING;
|
|
} else if ($contest['status'] == 'finished') {
|
|
$contest['cur_progress'] = CONTEST_FINISHED;
|
|
}
|
|
$contest['extra_config'] = json_decode($contest['extra_config'], true);
|
|
|
|
if (!isset($contest['extra_config']['standings_version'])) {
|
|
$contest['extra_config']['standings_version'] = 2;
|
|
}
|
|
}
|
|
|
|
function updateContestPlayerNum($contest) {
|
|
DB::update("update contests set player_num = (select count(*) from contests_registrants where contest_id = {$contest['id']}) where id = {$contest['id']}");
|
|
}
|