/** * Scoreboard */ function scoreboard($args) { global $DB, $api, $cdatas, $cids; if (isset($args['cid'])) { $cid = safe_int($args['cid']); } else { if (count($cids) == 1) { $cid = reset($cids); } else { $api->createError("No contest ID specified but active contest is ambiguous."); } } $filter = array(); if (array_key_exists('category', $args)) { $filter['categoryid'] = array($args['category']); } if (array_key_exists('country', $args)) { $filter['country'] = array($args['country']); } if (array_key_exists('affiliation', $args)) { $filter['affilid'] = array($args['affiliation']); } $scoreboard = genScoreBoard($cdatas[$cid], !$args['public'], $filter); $prob2label = $DB->q('KEYVALUETABLE SELECT probid, shortname FROM contestproblem WHERE cid = %i', $cid); $res = array(); foreach ($scoreboard['scores'] as $teamid => $data) { $row = array('rank' => $data['rank'], 'team' => $teamid); $row['score'] = array('num_solved' => safe_int($data['num_points']), 'total_time' => safe_int($data['total_time'])); $row['problems'] = array(); foreach ($scoreboard['matrix'][$teamid] as $probid => $pdata) { $prob = array('label' => $prob2label[$probid], 'num_judged' => safe_int($pdata['num_submissions']), 'num_pending' => safe_int($pdata['num_pending']), 'solved' => safe_bool($pdata['is_correct'])); if ($prob['solved']) { $prob['time'] = scoretime($pdata['time']); $first = first_solved($pdata['time'], $scoreboard['summary']['problems'][$probid]['best_time_sort'][$data['sortorder']]); $prob['first_to_solve'] = safe_bool($first); } $row['problems'][] = $prob; } usort($row['problems'], 'cmp_prob_label'); $res[] = $row; } return $res; }
/** * Output the general scoreboard based on the cached data in table * 'scorecache'. $myteamid can be passed to highlight a * specific row. * If this function is called while IS_JURY is defined, the scoreboard * will always be current, regardless of the freezetime setting in the * contesttable. * $static generates output suitable for standalone static html pages, * that is without references/links to other parts of the DOMjudge * interface. * $limitteams is an array of teamid's whose rows will be the only * ones displayed. The function still needs the complete scoreboard * data or it will not know the rank. * if $displayrank is false the first column will not display the * team's current rank but a question mark. */ function renderScoreBoardTable($sdata, $myteamid = null, $static = FALSE, $limitteams = null, $displayrank = TRUE, $center = FALSE, $showlegends = TRUE) { // 'unpack' the scoreboard data: $scores = $sdata['scores']; $matrix = $sdata['matrix']; $summary = $sdata['summary']; $teams = $sdata['teams']; $probs = $sdata['problems']; $categs = $sdata['categories']; unset($sdata); // configuration $SHOW_AFFILIATIONS = dbconfig_get('show_affiliations', 1); $SHOW_PENDING = dbconfig_get('show_pending', 0); // Do not show points if they are all 1 $showpoints = FALSE; foreach ($probs as $pr) { if ($pr['points'] != 1) { $showpoints = TRUE; break; } } echo '<table class="scoreboard' . (IS_JURY ? ' scoreboard_jury' : '') . ($center ? ' center' : '') . "\">\n"; // output table column groups (for the styles) echo '<colgroup><col id="scorerank" />' . ($SHOW_AFFILIATIONS ? '<col id="scoreaffil" />' : '') . '<col id="scoreteamname" /></colgroup><colgroup><col id="scoresolv" />' . "<col id=\"scoretotal\" /></colgroup>\n<colgroup>" . str_repeat('<col class="scoreprob" />', count($probs)) . "</colgroup>\n"; // column headers echo "<thead>\n"; echo '<tr class="scoreheader">' . '<th title="rank" scope="col">' . jurylink(null, 'rank') . '</th>' . '<th title="team name" scope="col"' . ($SHOW_AFFILIATIONS ? ' colspan="2"' : '') . '>' . jurylink(null, 'team') . '</th>' . '<th title="# solved / penalty time" colspan="2" scope="col">' . jurylink(null, 'score') . '</th>' . "\n"; foreach ($probs as $pr) { echo '<th title="problem \'' . specialchars($pr['name']) . '\'" scope="col">'; $str = specialchars($pr['shortname']) . (!empty($pr['color']) ? ' <div class="circle" style="background: ' . specialchars($pr['color']) . ';"></div>' : ''); if (!$static && (IS_JURY || $pr['hastext'] > 0)) { echo '<a href="problem.php?id=' . urlencode($pr['probid']) . '">' . $str . '</a>'; } else { echo '<a>' . $str . '</a>'; } if ($showpoints) { $points = $pr['points']; $pts = $points == 1 ? '1 point' : "{$points} points"; echo "<span class='problempoints'>[{$pts}]</span>"; } echo '</th>'; } echo "</tr>\n</thead>\n\n<tbody>\n"; // print the main scoreboard rows $prevsortorder = -1; foreach ($scores as $team => $totals) { // skip if we have limitteams and the team is not listed if (!empty($limitteams) && !in_array($team, $limitteams)) { continue; } // rank, team name, total points, total time echo '<tr'; $classes = array(); if ($totals['sortorder'] != $prevsortorder) { $classes[] = "sortorderswitch"; $prevsortorder = $totals['sortorder']; $prevteam = null; } // check whether this is us, otherwise use category colour if (@$myteamid == $team) { $classes[] = "scorethisisme"; unset($color); } else { $color = $teams[$team]['color']; } if (count($classes) > 0) { echo ' class="' . implode(' ', $classes) . '"'; } echo ' id="team:' . $teams[$team]['teamid'] . '"'; echo '><td class="scorepl">'; // Only print rank when score is different from the previous team if (!$displayrank) { echo jurylink(null, '?'); } elseif (!isset($prevteam) || $scores[$prevteam]['rank'] != $totals['rank']) { echo jurylink(null, $totals['rank']); } else { echo jurylink(null, ''); } $prevteam = $team; echo '</td>'; if ($SHOW_AFFILIATIONS) { echo '<td class="scoreaf">'; if (isset($teams[$team]['affilid'])) { if (IS_JURY) { echo '<a href="team_affiliation.php?id=' . urlencode($teams[$team]['affilid']) . '">'; } if (isset($teams[$team]['country'])) { $countryflag = '../images/countries/' . urlencode($teams[$team]['country']) . '.png'; echo ' '; if (is_readable($countryflag)) { echo '<img src="' . $countryflag . '"' . ' alt="' . specialchars($teams[$team]['country']) . '"' . ' title="' . specialchars($teams[$team]['country']) . '" />'; } else { echo specialchars($teams[$team]['country']); } } if (IS_JURY) { echo '</a>'; } } echo '</td>'; } $affilname = ''; if ($SHOW_AFFILIATIONS && isset($teams[$team]['affilid'])) { $affilname = specialchars($teams[$team]['affilname']); } echo '<td class="scoretn"' . (!empty($color) ? ' style="background: ' . $color . ';"' : '') . (IS_JURY ? ' title="' . specialchars($team) . '"' : '') . '>' . ($static ? '' : '<a href="team.php?id=' . urlencode($team) . '">') . specialchars($teams[$team]['name']) . ($SHOW_AFFILIATIONS ? '<br /><span class="univ">' . $affilname . '</span>' : '') . ($static ? '' : '</a>') . '</td>'; echo '<td class="scorenc">' . jurylink(null, $totals['num_points']) . '</td>' . '<td class="scorett">' . jurylink(null, $totals['total_time']) . '</td>'; // for each problem foreach (array_keys($probs) as $prob) { echo '<td class='; // CSS class for correct/incorrect/neutral results if ($matrix[$team][$prob]['is_correct']) { echo '"score_correct' . (first_solved($matrix[$team][$prob]['time'], @$summary['problems'][$prob]['best_time_sort'][$totals['sortorder']]) ? ' score_first' : '') . '"'; } elseif ($matrix[$team][$prob]['num_pending'] > 0 && $SHOW_PENDING) { echo '"score_pending"'; } elseif ($matrix[$team][$prob]['num_submissions'] > 0) { echo '"score_incorrect"'; } else { echo '"score_neutral"'; } // number of submissions for this problem $str = $matrix[$team][$prob]['num_submissions']; // add pending submissions if ($matrix[$team][$prob]['num_pending'] > 0 && $SHOW_PENDING) { $str .= ' + ' . $matrix[$team][$prob]['num_pending']; } // if correct, print time scored if ($matrix[$team][$prob]['is_correct']) { $str .= '/' . scoretime($matrix[$team][$prob]['time']); } echo '>' . jurylink('team.php?id=' . urlencode($team) . '&restrict=probid:' . urlencode($prob), $str) . '</td>'; } echo "</tr>\n"; } echo "</tbody>\n\n"; if (empty($limitteams)) { // print a summaryline. Exclude the "total solved" cell if using // perproblem points as it's actually total points and not useful if (!$showpoints) { $totalCell = '<td title="total solved" class="scorenc">' . jurylink(null, $summary['num_points']) . '</td>'; } else { $totalCell = '<td class="scorenc" title=" "></td>'; // Empty } echo '<tbody><tr id="scoresummary" title="#submitted / #correct">' . '<td title="total teams">' . jurylink(null, count($matrix)) . '</td>' . ($SHOW_AFFILIATIONS ? '<td class="scoreaffil" title="#affiliations / #countries">' . jurylink('team_affiliations.php', count($summary['affils']) . ' / ' . count($summary['countries'])) . '</td>' : '') . '<td title=" ">' . jurylink(null, 'Summary') . '</td>' . $totalCell . '<td title=" "></td>'; foreach (array_keys($probs) as $prob) { $str = $summary['problems'][$prob]['num_submissions'] . '/' . $summary['problems'][$prob]['num_correct']; echo '<td>' . jurylink('problem.php?id=' . urlencode($prob), $str) . '</td>'; } echo "</tr>\n</tbody>\n"; } echo "</table>\n\n"; if ($showlegends) { echo "<p><br /><br /></p>\n"; // only print legend when there's more than one category if (empty($limitteams) && count($categs) > 1) { echo "<table id=\"categ_legend\" class=\"scoreboard scorelegend" . (IS_JURY ? ' scoreboard_jury' : '') . "\">\n" . "<thead><tr><th scope=\"col\">" . jurylink('team_categories.php', 'Categories') . "</th></tr></thead>\n<tbody>\n"; foreach ($categs as $cat) { echo '<tr' . (!empty($cat['color']) ? ' style="background: ' . $cat['color'] . ';"' : '') . '>' . '<td>' . jurylink('team_category.php?id=' . urlencode($cat['categoryid']), specialchars($cat['name'])) . "</td></tr>\n"; } echo "</tbody>\n</table>\n \n"; } // print legend of scorecell colors $cellcolors = array('first' => 'Solved first', 'correct' => 'Solved', 'incorrect' => 'Tried, incorrect', 'pending' => 'Tried, pending', 'neutral' => 'Untried'); echo "<table id=\"cell_legend\" class=\"scoreboard scorelegend" . (IS_JURY ? ' scoreboard_jury' : '') . "\">\n" . "<thead><tr><th scope=\"col\">" . jurylink(null, 'Cell colours') . "</th></tr></thead>\n<tbody>\n"; foreach ($cellcolors as $color => $desc) { if ($color == 'pending' && !dbconfig_get('show_pending', 0)) { continue; } echo '<tr class="score_' . $color . '">' . '<td>' . jurylink(null, $desc) . "</td></tr>\n"; } echo "</tbody>\n</table>\n\n"; } return; }