mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-11-22 14:48:41 +00:00
refactor(web/problem): Codeforces 风格的题目难度评价系统 (#21)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Co-authored-by: Fengyu Xie <63272948+Ignotus0@users.noreply.github.com> Co-authored-by: Jiaxi Li <91811830+RevolutionBP@users.noreply.github.com> Co-authored-by: Wenkuo Yu <82705676+youwike@users.noreply.github.com> Co-authored-by: Haosen Li <91672298+Johnsonloy@users.noreply.github.com> Co-authored-by: Baoshuo Ren <47095648+renbaoshuo@users.noreply.github.com>
This commit is contained in:
commit
3f2a6feea2
@ -54,7 +54,7 @@ function getProblemTR($info) {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$html .= HTML::tag('td', [], UOJProblem::getDifficultyHTML($problem->info['difficulty']));
|
$html .= HTML::tag('td', [], $problem->getDifficultyHTML());
|
||||||
$html .= HTML::tag('td', [], ClickZans::getCntBlock($problem->info['zan']));
|
$html .= HTML::tag('td', [], ClickZans::getCntBlock($problem->info['zan']));
|
||||||
$html .= HTML::tag_end('tr');
|
$html .= HTML::tag_end('tr');
|
||||||
return $html;
|
return $html;
|
||||||
@ -66,7 +66,7 @@ $header .= '<th>' . UOJLocale::get('problems::problem') . '</th>';
|
|||||||
if (isset($_COOKIE['show_submit_mode'])) {
|
if (isset($_COOKIE['show_submit_mode'])) {
|
||||||
$header .= '<th class="text-center" style="width:125px;">' . UOJLocale::get('problems::ac ratio') . '</th>';
|
$header .= '<th class="text-center" style="width:125px;">' . UOJLocale::get('problems::ac ratio') . '</th>';
|
||||||
}
|
}
|
||||||
$header .= '<th class="text-center" style="width:8em;">' . UOJLocale::get('problems::difficulty') . '</th>';
|
$header .= '<th class="text-center" style="width:4em;">' . UOJLocale::get('problems::difficulty') . '</th>';
|
||||||
$header .= '<th class="text-center" style="width:50px;">' . UOJLocale::get('appraisal') . '</th>';
|
$header .= '<th class="text-center" style="width:50px;">' . UOJLocale::get('appraisal') . '</th>';
|
||||||
$header .= '</tr>';
|
$header .= '</tr>';
|
||||||
|
|
||||||
|
@ -390,7 +390,7 @@ if (UOJContest::cur()) {
|
|||||||
</li>
|
</li>
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
<span>难度</span>
|
<span>难度</span>
|
||||||
<span><?= UOJProblem::getDifficultyHTML(UOJProblem::info('difficulty')) ?></span>
|
<span><?= UOJProblem::cur()->getDifficultyHTML() ?></span>
|
||||||
</li>
|
</li>
|
||||||
<?php if (Auth::check()) : ?>
|
<?php if (Auth::check()) : ?>
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
@ -553,29 +553,6 @@ $solution_view_type_form->handle = function () {
|
|||||||
};
|
};
|
||||||
$solution_view_type_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100 mt-2';
|
$solution_view_type_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100 mt-2';
|
||||||
|
|
||||||
$difficulty_form = new UOJBs4Form('difficulty');
|
|
||||||
$difficulty_form->addVInput(
|
|
||||||
'difficulty',
|
|
||||||
'text',
|
|
||||||
'难度系数',
|
|
||||||
$problem_extra_config['difficulty'],
|
|
||||||
function ($str) {
|
|
||||||
if (!is_numeric($str)) {
|
|
||||||
return '难度系数必须是一个数字';
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
null
|
|
||||||
);
|
|
||||||
$difficulty_form->handle = function () {
|
|
||||||
global $problem, $problem_extra_config;
|
|
||||||
$config = $problem_extra_config;
|
|
||||||
$config['difficulty'] = $_POST['difficulty'] + 0;
|
|
||||||
$esc_config = DB::escape(json_encode($config));
|
|
||||||
DB::query("update problems set extra_config = '$esc_config' where id = '{$problem['id']}'");
|
|
||||||
};
|
|
||||||
$difficulty_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100 mt-2';
|
|
||||||
|
|
||||||
if ($problem['hackable']) {
|
if ($problem['hackable']) {
|
||||||
$test_std_form = new UOJBs4Form('test_std');
|
$test_std_form = new UOJBs4Form('test_std');
|
||||||
$test_std_form->handle = function () use ($problem, $data_disp) {
|
$test_std_form->handle = function () use ($problem, $data_disp) {
|
||||||
@ -643,7 +620,6 @@ if ($problem['hackable']) {
|
|||||||
$hackable_form->runAtServer();
|
$hackable_form->runAtServer();
|
||||||
$view_type_form->runAtServer();
|
$view_type_form->runAtServer();
|
||||||
$solution_view_type_form->runAtServer();
|
$solution_view_type_form->runAtServer();
|
||||||
$difficulty_form->runAtServer();
|
|
||||||
$data_form->runAtServer();
|
$data_form->runAtServer();
|
||||||
$clear_data_form->runAtServer();
|
$clear_data_form->runAtServer();
|
||||||
$rejudge_form->runAtServer();
|
$rejudge_form->runAtServer();
|
||||||
@ -803,13 +779,6 @@ $info_form->runAtServer();
|
|||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<button type="button" class="btn d-block w-100 btn-primary" data-bs-toggle="modal" data-bs-target="#ProblemSettingsFileModal">试题配置</button>
|
<button type="button" class="btn d-block w-100 btn-primary" data-bs-toggle="modal" data-bs-target="#ProblemSettingsFileModal">试题配置</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-2">
|
|
||||||
<button id="button-difficulty" type="button" class="btn d-block w-100 btn-primary" onclick="$('#div-difficulty').toggle('fast');">难度系数</button>
|
|
||||||
<div class="mt-2" id="div-difficulty" style="display:none; padding-left:5px; padding-right:5px;">
|
|
||||||
<?php $difficulty_form->printHTML(); ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ function getProblemTR($info) {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$html .= HTML::tag('td', [], UOJProblem::getDifficultyHTML($problem->info['difficulty']));
|
$html .= HTML::tag('td', [], $problem->getDifficultyHTML());
|
||||||
$html .= HTML::tag('td', [], ClickZans::getCntBlock($problem->info['zan']));
|
$html .= HTML::tag('td', [], ClickZans::getCntBlock($problem->info['zan']));
|
||||||
$html .= HTML::tag_end('tr');
|
$html .= HTML::tag_end('tr');
|
||||||
return $html;
|
return $html;
|
||||||
@ -177,8 +177,12 @@ if (Auth::check() && isset($_GET['my'])) {
|
|||||||
$cond['problems.uploader'] = Auth::id();
|
$cond['problems.uploader'] = Auth::id();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_GET['difficulty']) && $_GET['difficulty']) {
|
if (isset($_GET['min_difficulty']) && $_GET['min_difficulty']) {
|
||||||
$cond['problems.difficulty'] = $_GET['difficulty'];
|
$cond[] = ['problems.difficulty', '>=', $_GET['min_difficulty']];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['max_difficulty']) && $_GET['max_difficulty']) {
|
||||||
|
$cond[] = ['problems.difficulty', '<=', $_GET['max_difficulty']];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($cond)) {
|
if (empty($cond)) {
|
||||||
@ -191,7 +195,7 @@ $header .= '<th>' . UOJLocale::get('problems::problem') . '</th>';
|
|||||||
if (isset($_COOKIE['show_submit_mode'])) {
|
if (isset($_COOKIE['show_submit_mode'])) {
|
||||||
$header .= '<th class="text-center" style="width:125px;">' . UOJLocale::get('problems::ac ratio') . '</th>';
|
$header .= '<th class="text-center" style="width:125px;">' . UOJLocale::get('problems::ac ratio') . '</th>';
|
||||||
}
|
}
|
||||||
$header .= '<th class="text-center" style="width:8em;">' . UOJLocale::get('problems::difficulty') . '</th>';
|
$header .= '<th class="text-center" style="width:4em;">' . UOJLocale::get('problems::difficulty') . '</th>';
|
||||||
$header .= '<th class="text-center" style="width:50px;">' . UOJLocale::get('appraisal') . '</th>';
|
$header .= '<th class="text-center" style="width:50px;">' . UOJLocale::get('appraisal') . '</th>';
|
||||||
$header .= '</tr>';
|
$header .= '</tr>';
|
||||||
|
|
||||||
@ -247,8 +251,7 @@ $pag = new Paginator([
|
|||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-md-9">
|
||||||
|
|
||||||
<!-- title -->
|
<!-- title -->
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
<h1>
|
<h1>
|
||||||
@ -335,8 +338,7 @@ $pag = new Paginator([
|
|||||||
<!-- end left col -->
|
<!-- end left col -->
|
||||||
|
|
||||||
<!-- right col -->
|
<!-- right col -->
|
||||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
<aside class="col-md-3 mt-3 mt-md-0">
|
||||||
|
|
||||||
<!-- search bar -->
|
<!-- search bar -->
|
||||||
<form method="get" class="mb-3" id="form-problem_search">
|
<form method="get" class="mb-3" id="form-problem_search">
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
@ -363,15 +365,20 @@ $pag = new Paginator([
|
|||||||
</div>
|
</div>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mt-3">
|
|
||||||
<label class="col-sm-3 col-form-label" for="input-difficulty">难度</label>
|
<div class="card mt-3">
|
||||||
<div class="col-sm-9">
|
<div class="card-header fw-bold">
|
||||||
<select id="input-difficulty" name="difficulty" class="form-select">
|
题目难度
|
||||||
<option value="">全部</option>
|
</div>
|
||||||
<?php foreach (UOJProblem::$difficulty as $opt_name => $opt_value) : ?>
|
<div class="card-body">
|
||||||
<?= HTML::option($opt_name, $opt_value, $opt_name == $_GET['difficulty']) ?>
|
<div class="input-group input-group-sm">
|
||||||
<?php endforeach ?>
|
<input type="text" class="form-control" name="min_difficulty" id="input-min_difficulty" maxlength="4" style="width:4em" placeholder="800" value="<?= HTML::escape($_GET['min_difficulty']) ?>" autocomplete="off" />
|
||||||
</select>
|
<span class="input-group-text">~</span>
|
||||||
|
<input type="text" class="form-control" name="max_difficulty" id="input-max_difficulty" maxlength="4" style="width:4em" placeholder="3500" value="<?= HTML::escape($_GET['max_difficulty']) ?>" autocomplete="off" />
|
||||||
|
<button type="submit" class="btn btn-outline-secondary">
|
||||||
|
<i class="bi bi-funnel"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -253,7 +253,7 @@ $pag = new Paginator($pag_config);
|
|||||||
</li>
|
</li>
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
<span>难度</span>
|
<span>难度</span>
|
||||||
<span><?= UOJProblem::getDifficultyHTML(UOJProblem::info('difficulty')) ?></span>
|
<span><?= UOJProblem::cur()->getDifficultyHTML() ?></span>
|
||||||
</li>
|
</li>
|
||||||
<?php if (Auth::check()) : ?>
|
<?php if (Auth::check()) : ?>
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
@ -65,7 +65,7 @@ $problem_editor->runAtServer();
|
|||||||
|
|
||||||
$difficulty_form = new UOJForm('difficulty');
|
$difficulty_form = new UOJForm('difficulty');
|
||||||
$difficulty_form->addSelect('difficulty', [
|
$difficulty_form->addSelect('difficulty', [
|
||||||
'options' => UOJProblem::$difficulty,
|
'options' => array_combine(UOJProblem::$difficulty, UOJProblem::$difficulty),
|
||||||
'default_value' => UOJProblem::info('difficulty'),
|
'default_value' => UOJProblem::info('difficulty'),
|
||||||
]);
|
]);
|
||||||
$difficulty_form->handle = function () {
|
$difficulty_form->handle = function () {
|
||||||
@ -183,4 +183,4 @@ $difficulty_form->runAtServer();
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
@ -325,7 +325,7 @@ $submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']
|
|||||||
</li>
|
</li>
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
<span>难度</span>
|
<span>难度</span>
|
||||||
<span><?= UOJProblem::getDifficultyHTML(UOJProblem::info('difficulty')) ?></span>
|
<span><?= UOJProblem::cur()->getDifficultyHTML() ?></span>
|
||||||
</li>
|
</li>
|
||||||
<?php if (Auth::check()) : ?>
|
<?php if (Auth::check()) : ?>
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
@ -9,25 +9,45 @@ class UOJProblem {
|
|||||||
use UOJArticleTrait;
|
use UOJArticleTrait;
|
||||||
|
|
||||||
public static array $difficulty = [
|
public static array $difficulty = [
|
||||||
-1 => '暂无评定',
|
800,
|
||||||
1 => '入门',
|
1000,
|
||||||
2 => '普及-',
|
1200,
|
||||||
3 => '普及/提高-',
|
1400,
|
||||||
4 => '普及+/提高',
|
1600,
|
||||||
6 => '提高+/省选-',
|
1800,
|
||||||
8 => '省选/NOI-',
|
1900,
|
||||||
10 => 'NOI/NOI+/CTSC',
|
2000,
|
||||||
|
2100,
|
||||||
|
2200,
|
||||||
|
2300,
|
||||||
|
2400,
|
||||||
|
2500,
|
||||||
|
2700,
|
||||||
|
2900,
|
||||||
|
3100,
|
||||||
|
3300,
|
||||||
|
3500,
|
||||||
];
|
];
|
||||||
|
|
||||||
public static array $difficulty_color = [
|
public static array $difficulty_color = [
|
||||||
-1 => '#bfbfbf',
|
800 => '#008000',
|
||||||
1 => '#fe4c61',
|
1000 => '#008000',
|
||||||
2 => '#f39c11',
|
1200 => '#00c0c0',
|
||||||
3 => '#ffc116',
|
1400 => '#00c0c0',
|
||||||
4 => '#52c41a',
|
1600 => '#0000ff',
|
||||||
6 => '#3498db',
|
1800 => '#0000ff',
|
||||||
8 => '#9d3dcf',
|
1900 => '#0000ff',
|
||||||
10 => '#0e1d69',
|
2000 => '#c0c000',
|
||||||
|
2100 => '#c0c000',
|
||||||
|
2200 => '#c0c000',
|
||||||
|
2300 => '#c0c000',
|
||||||
|
2400 => '#ff8000',
|
||||||
|
2500 => '#ff8000',
|
||||||
|
2700 => '#ff8000',
|
||||||
|
2900 => '#ff0000',
|
||||||
|
3100 => '#ff0000',
|
||||||
|
3300 => '#aa0000',
|
||||||
|
3500 => '#aa0000',
|
||||||
];
|
];
|
||||||
|
|
||||||
public static function query($id) {
|
public static function query($id) {
|
||||||
@ -78,14 +98,6 @@ class UOJProblem {
|
|||||||
return isSuperUser($user) || UOJUser::checkPermission($user, 'problems.create');
|
return isSuperUser($user) || UOJUser::checkPermission($user, 'problems.create');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getDifficultyHTML($difficulty = -1) {
|
|
||||||
$difficulty = (int)$difficulty;
|
|
||||||
$difficulty_text = self::$difficulty[$difficulty] ?: self::$difficulty[-1];
|
|
||||||
$difficulty_color = self::$difficulty_color[$difficulty] ?: self::$difficulty_color[-1];
|
|
||||||
|
|
||||||
return HTML::tag('span', ['class' => 'uoj-difficulty', 'style' => "color: $difficulty_color"], $difficulty_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __construct($info) {
|
public function __construct($info) {
|
||||||
$this->info = $info;
|
$this->info = $info;
|
||||||
}
|
}
|
||||||
@ -128,6 +140,14 @@ class UOJProblem {
|
|||||||
return UOJUser::getLink($this->info['uploader'] ?: "root");
|
return UOJUser::getLink($this->info['uploader'] ?: "root");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDifficultyHTML() {
|
||||||
|
$difficulty = (int)$this->info['difficulty'];
|
||||||
|
$difficulty_text = in_array($difficulty, static::$difficulty) ? $difficulty : '-';
|
||||||
|
$difficulty_color = in_array($difficulty, static::$difficulty) ? static::$difficulty_color[$difficulty] : '#7e7e7e';
|
||||||
|
|
||||||
|
return HTML::tag('span', ['class' => 'uoj-difficulty', 'style' => "color: $difficulty_color"], $difficulty_text);
|
||||||
|
}
|
||||||
|
|
||||||
public function findInContests() {
|
public function findInContests() {
|
||||||
$res = DB::selectAll([
|
$res = DB::selectAll([
|
||||||
"select contest_id from contests_problems",
|
"select contest_id from contests_problems",
|
||||||
|
43
web/app/upgrade/21_problem_difficulty/upgrade.php
Normal file
43
web/app/upgrade/21_problem_difficulty/upgrade.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return function ($type) {
|
||||||
|
if ($type == 'up') {
|
||||||
|
DB::init();
|
||||||
|
|
||||||
|
$problems = DB::selectAll("select * from problems");
|
||||||
|
|
||||||
|
foreach ($problems as $info) {
|
||||||
|
$problem = new UOJProblem($info);
|
||||||
|
|
||||||
|
$difficulty = -1;
|
||||||
|
$extra_config = $problem->getExtraConfig();
|
||||||
|
|
||||||
|
if (isset($extra_config['difficulty'])) {
|
||||||
|
$old_difficulty = (float)$extra_config['difficulty'];
|
||||||
|
|
||||||
|
$difficulty = (int)(3.0 * $old_difficulty + 5) * 100;
|
||||||
|
$difficulty = (function ($search, $arr) {
|
||||||
|
$closest = null;
|
||||||
|
foreach ($arr as $item) {
|
||||||
|
if ($closest === null || abs($search - $closest) > abs($item - $search)) {
|
||||||
|
$closest = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $closest;
|
||||||
|
})($difficulty, UOJProblem::$difficulty);
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::update([
|
||||||
|
"update problems",
|
||||||
|
"set", [
|
||||||
|
"difficulty" => $difficulty,
|
||||||
|
],
|
||||||
|
"where", [
|
||||||
|
"id" => $problem->info['id'],
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
echo "Problem: {$problem->info['id']} ({$difficulty})\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user