new problem and deleted the obsolete problem loader

This commit is contained in:
2025-08-16 20:44:47 +02:00
parent e97dde65fb
commit 68b7b81741
7 changed files with 363 additions and 370 deletions

View File

@@ -23,6 +23,12 @@
}
#rankInfoBtn.active { color: #2563eb; cursor:pointer; transition: transform 0.3s ease; }
#rankInfoBtn.active { transform: rotate(90deg); }
/* Highlight top rank */
.rank-1 { background-color: #f0fff0; }
.rank-1 td:first-child { font-weight: bold; color: #2e7d32; }
.sort-asc::after { content: " ↑"; }
.sort-desc::after { content: " ↓"; }
</style>
</head>
<body>
@@ -86,7 +92,7 @@
<td>{{ entry[0] }}</td>
<td>
<a href="/problem/{{ problem_titles.get(entry[1], 'Unknown') }}"
style="color: #0077ff; text-decoration: none;"
style="color:#2563eb; text-decoration: none;"
onmouseover="this.style.textDecoration='underline';"
onmouseout="this.style.textDecoration='none';">
{{ problem_titles.get(entry[1], 'Unknown') }}
@@ -125,111 +131,6 @@
</section>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Problem search
const problemSearch = document.getElementById('problemSearch');
const problemsContainer = document.getElementById('problemsContainer');
const problemItems = problemsContainer?.querySelectorAll('.problem-item') || [];
problemSearch?.addEventListener('input', () => {
const term = problemSearch.value.toLowerCase();
problemItems.forEach(item => {
const name = item.dataset.name?.toLowerCase()||'';
const desc = item.dataset.desc?.toLowerCase()||'';
item.style.display = (name.includes(term) || desc.includes(term)) ? '' : 'none';
});
});
// Leaderboard
const problemFilter = document.getElementById('problemFilter');
const runtimeFilter = document.getElementById('runtimeFilter');
const leaderboardBody = document.getElementById('leaderboardBody');
const sortableHeaders = document.querySelectorAll('.sortable');
function calculateOverallRank() {
const rows = Array.from(leaderboardBody.querySelectorAll('tr')).filter(r => r.style.display !== 'none');
const runtimes = rows.map(r => parseFloat(r.dataset.runtime)||Infinity);
const memories = rows.map(r => parseFloat(r.dataset.memory)||Infinity);
const minRuntime = Math.min(...runtimes);
const minMemory = Math.min(...memories);
rows.forEach(row => {
const runtimeScore = (parseFloat(row.dataset.runtime)||Infinity)/minRuntime;
const memoryScore = (parseFloat(row.dataset.memory)||Infinity)/minMemory;
row.dataset.overallScore = runtimeScore*0.7 + memoryScore*0.3;
});
rows.sort((a,b)=>parseFloat(a.dataset.overallScore)-parseFloat(b.dataset.overallScore));
rows.forEach((row,i)=>row.cells[0].textContent = i+1);
}
function filterLeaderboard() {
const problemTerm = problemFilter.value.toLowerCase();
const runtimeType = runtimeFilter.value;
const rows = Array.from(leaderboardBody.querySelectorAll('tr'));
rows.forEach(row => {
const problem = row.dataset.problem.toLowerCase();
const runtime = parseFloat(row.dataset.runtime);
let show = problem.includes(problemTerm);
if(runtimeType==='best'){
const userRows = rows.filter(r=>r.dataset.user===row.dataset.user && r.dataset.problem===row.dataset.problem);
show = show && runtime===Math.min(...userRows.map(r=>parseFloat(r.dataset.runtime)));
} else if(runtimeType==='worst'){
const userRows = rows.filter(r=>r.dataset.user===row.dataset.user && r.dataset.problem===row.dataset.problem);
show = show && runtime===Math.max(...userRows.map(r=>parseFloat(r.dataset.runtime)));
}
row.style.display = show?'':'none';
});
calculateOverallRank();
}
problemFilter?.addEventListener('input', filterLeaderboard);
runtimeFilter?.addEventListener('change', filterLeaderboard);
function getCellValue(row, column){
const index = Array.from(document.querySelectorAll('th')).findIndex(th=>th.dataset.sort===column);
let val = row.cells[index]?.textContent?.trim();
if(['runtime','memory','rank'].includes(column)) return parseFloat(val)||0;
if(column==='timestamp') return new Date(val).getTime();
return val.toLowerCase();
}
function compareValues(a,b,direction){
if(typeof a==='number' && typeof b==='number') return direction==='asc'?a-b:b-a;
if(a<b) return direction==='asc'?-1:1;
if(a>b) return direction==='asc'?1:-1;
return 0;
}
function sortLeaderboard(column,direction){
const rows = Array.from(leaderboardBody.querySelectorAll('tr'));
if(column==='rank'){
calculateOverallRank();
} else {
rows.sort((a,b)=>compareValues(getCellValue(a,column),getCellValue(b,column),direction));
rows.forEach(r=>leaderboardBody.appendChild(r));
}
}
let currentSort={column:null,direction:'asc'};
sortableHeaders.forEach(header=>{
header.addEventListener('click',()=>{
const column=header.dataset.sort;
sortableHeaders.forEach(h=>h.classList.remove('sort-asc','sort-desc'));
if(currentSort.column===column) currentSort.direction=currentSort.direction==='asc'?'desc':'asc';
else { currentSort.column=column; currentSort.direction='asc'; currentSort.column=column; }
header.classList.add(`sort-${currentSort.direction}`);
sortLeaderboard(column,currentSort.direction);
});
});
// Rank info popout
const rankInfoBtn = document.getElementById('rankInfoBtn');
const rankingExplanation = document.getElementById('rankingExplanation');
rankInfoBtn?.addEventListener('click',()=>{
rankingExplanation.classList.toggle('active');
rankInfoBtn.classList.toggle('active');
});
// Initial calculation
calculateOverallRank();
});
</script>
<script src="./script.js"></script>
</body>
</html>
</html>