<?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']}"); }