a geicko-2 based round robin ranking system designed to test c++ battleship submissions battleship.dunkirk.sh
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add failed section

+130 -19
+130 -19
internal/server/web.go
··· 525 525 flex-shrink: 0; 526 526 } 527 527 528 + .collapsible-section { 529 + margin-top: 2rem; 530 + background: #1e293b; 531 + border: 1px solid #334155; 532 + border-radius: 0.75rem; 533 + overflow: hidden; 534 + } 535 + 536 + .collapsible-header { 537 + padding: 1rem 1.5rem; 538 + cursor: pointer; 539 + display: flex; 540 + justify-content: space-between; 541 + align-items: center; 542 + background: #1e293b; 543 + border-bottom: 1px solid #334155; 544 + transition: background 0.2s; 545 + } 546 + 547 + .collapsible-header:hover { 548 + background: #334155; 549 + } 550 + 551 + .collapsible-title { 552 + font-size: 1rem; 553 + font-weight: 600; 554 + color: #e2e8f0; 555 + display: flex; 556 + align-items: center; 557 + gap: 0.5rem; 558 + } 559 + 560 + .collapsible-count { 561 + background: rgba(239, 68, 68, 0.2); 562 + color: #ef4444; 563 + padding: 0.25rem 0.5rem; 564 + border-radius: 0.375rem; 565 + font-size: 0.875rem; 566 + } 567 + 568 + .collapsible-arrow { 569 + transition: transform 0.2s; 570 + color: #94a3b8; 571 + } 572 + 573 + .collapsible-content { 574 + max-height: 0; 575 + overflow: hidden; 576 + transition: max-height 0.3s ease-out; 577 + } 578 + 579 + .collapsible-content.open { 580 + max-height: 1000px; 581 + } 582 + 528 583 @media (max-width: 768px) { 529 584 h1 { font-size: 2rem; } 530 585 .subtitle { font-size: 1rem; } ··· 703 758 console.error('Failed to copy:', err); 704 759 }); 705 760 } 761 + 762 + function toggleCollapsible() { 763 + const content = document.getElementById('collapsible-content'); 764 + const arrow = document.getElementById('collapsible-arrow'); 765 + 766 + if (content.classList.contains('open')) { 767 + content.classList.remove('open'); 768 + arrow.textContent = '▼'; 769 + } else { 770 + content.classList.add('open'); 771 + arrow.textContent = '▲'; 772 + } 773 + } 706 774 </script> 707 775 </head> 708 776 <body> ··· 748 816 <tbody> 749 817 {{if .Entries}} 750 818 {{range $i, $e := .Entries}} 751 - <tr{{if $e.IsPending}} class="pending"{{else if $e.IsBroken}} class="broken"{{end}}> 752 - <td class="rank rank-{{add $i 1}}">{{if $e.IsBroken}}💥{{else if $e.IsPending}}⏳{{else if lt $i 3}}{{medal $i}}{{else}}{{add $i 1}}{{end}}</td> 753 - <td class="player-name"><a href="/user/{{$e.Username}}" style="color: inherit; text-decoration: none;">{{$e.Username}}{{if $e.IsPending}} <span style="font-size: 0.8em;">(pending)</span>{{else if $e.IsBroken}} <span style="font-size: 0.8em; color: #ef4444;" title="{{$e.FailureMessage}}">(failed)</span>{{end}}</a></td> 754 - <td>{{if or $e.IsPending $e.IsBroken}}-{{else}}<strong>{{$e.Rating}}</strong> <span style="color: #94a3b8; font-size: 0.85em;">±{{$e.RD}}</span>{{end}}</td> 755 - <td>{{if or $e.IsPending $e.IsBroken}}-{{else}}{{$e.Wins}}{{end}}</td> 756 - <td>{{if or $e.IsPending $e.IsBroken}}-{{else}}{{$e.Losses}}{{end}}</td> 757 - <td>{{if or $e.IsPending $e.IsBroken}}-{{else}}<span class="win-rate {{winRateClass $e}}">{{winRate $e}}%</span>{{end}}</td> 758 - <td>{{if or $e.IsPending $e.IsBroken}}-{{else}}{{printf "%.1f" $e.AvgMoves}}{{end}}</td> 759 - <td style="color: #64748b;">{{if $e.IsPending}}Waiting...{{else if $e.IsBroken}}<span title="{{$e.FailureMessage}}">Failed</span>{{else}}{{$e.LastPlayed.Format "Jan 2, 3:04 PM"}}{{end}}</td> 819 + <tr{{if $e.IsPending}} class="pending"{{end}}> 820 + <td class="rank rank-{{add $i 1}}">{{if $e.IsPending}}⏳{{else if lt $i 3}}{{medal $i}}{{else}}{{add $i 1}}{{end}}</td> 821 + <td class="player-name"><a href="/user/{{$e.Username}}" style="color: inherit; text-decoration: none;">{{$e.Username}}{{if $e.IsPending}} <span style="font-size: 0.8em;">(pending)</span>{{end}}</a></td> 822 + <td>{{if $e.IsPending}}-{{else}}<strong>{{$e.Rating}}</strong> <span style="color: #94a3b8; font-size: 0.85em;">±{{$e.RD}}</span>{{end}}</td> 823 + <td>{{if $e.IsPending}}-{{else}}{{$e.Wins}}{{end}}</td> 824 + <td>{{if $e.IsPending}}-{{else}}{{$e.Losses}}{{end}}</td> 825 + <td>{{if $e.IsPending}}-{{else}}<span class="win-rate {{winRateClass $e}}">{{winRate $e}}%</span>{{end}}</td> 826 + <td>{{if $e.IsPending}}-{{else}}{{printf "%.1f" $e.AvgMoves}}{{end}}</td> 827 + <td style="color: #64748b;">{{if $e.IsPending}}Waiting...{{else}}{{$e.LastPlayed.Format "Jan 2, 3:04 PM"}}{{end}}</td> 760 828 </tr> 761 829 {{end}} 762 830 {{else}} ··· 772 840 </tbody> 773 841 </table> 774 842 </div> 843 + 844 + {{if .BrokenEntries}} 845 + <div class="collapsible-section"> 846 + <div class="collapsible-header" onclick="toggleCollapsible()"> 847 + <div class="collapsible-title"> 848 + 💥 Failed Submissions 849 + <span class="collapsible-count">{{len .BrokenEntries}}</span> 850 + </div> 851 + <span class="collapsible-arrow" id="collapsible-arrow">▼</span> 852 + </div> 853 + <div class="collapsible-content" id="collapsible-content"> 854 + <table> 855 + <tbody> 856 + {{range $e := .BrokenEntries}} 857 + <tr class="broken"> 858 + <td class="rank">💥</td> 859 + <td class="player-name"><a href="/user/{{$e.Username}}" style="color: inherit; text-decoration: none;">{{$e.Username}}</a></td> 860 + <td>-</td> 861 + <td>-</td> 862 + <td>-</td> 863 + <td>-</td> 864 + <td>-</td> 865 + <td style="color: #64748b;"><span title="{{$e.FailureMessage}}" style="cursor: help;">{{$e.FailureMessage}}</span></td> 866 + </tr> 867 + {{end}} 868 + </tbody> 869 + </table> 870 + </div> 871 + </div> 872 + {{end}} 775 873 776 874 <div class="info-card"> 777 875 <h3>📤 How to Submit</h3> ··· 876 974 entries = []storage.LeaderboardEntry{} 877 975 } 878 976 977 + // Split entries into working and broken 978 + var workingEntries []storage.LeaderboardEntry 979 + var brokenEntries []storage.LeaderboardEntry 980 + for _, e := range entries { 981 + if e.IsBroken { 982 + brokenEntries = append(brokenEntries, e) 983 + } else { 984 + workingEntries = append(workingEntries, e) 985 + } 986 + } 987 + 879 988 // Get matches for bracket 880 989 matches, err := storage.GetAllMatches() 881 990 if err != nil { ··· 883 992 } 884 993 885 994 data := struct { 886 - Entries []storage.LeaderboardEntry 887 - Matches []storage.MatchResult 888 - TotalPlayers int 889 - TotalGames int 890 - ServerURL string 995 + Entries []storage.LeaderboardEntry 996 + BrokenEntries []storage.LeaderboardEntry 997 + Matches []storage.MatchResult 998 + TotalPlayers int 999 + TotalGames int 1000 + ServerURL string 891 1001 }{ 892 - Entries: entries, 893 - Matches: matches, 894 - TotalPlayers: len(entries), 895 - TotalGames: calculateTotalGames(entries), 896 - ServerURL: GetServerURL(), 1002 + Entries: workingEntries, 1003 + BrokenEntries: brokenEntries, 1004 + Matches: matches, 1005 + TotalPlayers: len(workingEntries), 1006 + TotalGames: calculateTotalGames(workingEntries), 1007 + ServerURL: GetServerURL(), 897 1008 } 898 1009 899 1010 if err := tmpl.Execute(w, data); err != nil {