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 compilation failed status

+50 -16
+1
internal/runner/runner.go
··· 309 309 #define %s 310 310 311 311 #include "memory.h" 312 + #include "battleship_light.h" 312 313 #include <string> 313 314 314 315 void initMemory%s(ComputerMemory &memory);
+2 -1
internal/runner/worker.go
··· 61 61 62 62 if err := CompileSubmission(sub, uploadDir); err != nil { 63 63 log.Printf("❌ Compilation failed for %s: %v", sub.Username, err) 64 - storage.UpdateSubmissionStatus(sub.ID, "failed") 64 + storage.UpdateSubmissionStatus(sub.ID, "compilation_failed") 65 + notifyFunc() 65 66 continue 66 67 } 67 68
+22 -9
internal/server/web.go
··· 181 181 color: #64748b !important; 182 182 } 183 183 184 + tbody tr.broken { 185 + opacity: 0.6; 186 + color: #ef4444; 187 + } 188 + 189 + tbody tr.broken .player-name { 190 + color: #f87171; 191 + } 192 + 193 + tbody tr.broken .rank { 194 + color: #ef4444 !important; 195 + } 196 + 184 197 tbody tr:hover { 185 198 background: rgba(59, 130, 246, 0.05); 186 199 } ··· 735 748 <tbody> 736 749 {{if .Entries}} 737 750 {{range $i, $e := .Entries}} 738 - <tr{{if $e.IsPending}} class="pending"{{end}}> 739 - <td class="rank rank-{{add $i 1}}">{{if $e.IsPending}}⏳{{else if lt $i 3}}{{medal $i}}{{else}}{{add $i 1}}{{end}}</td> 740 - <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> 741 - <td>{{if $e.IsPending}}-{{else}}<strong>{{$e.Rating}}</strong> <span style="color: #94a3b8; font-size: 0.85em;">±{{$e.RD}}</span>{{end}}</td> 742 - <td>{{if $e.IsPending}}-{{else}}{{$e.Wins}}{{end}}</td> 743 - <td>{{if $e.IsPending}}-{{else}}{{$e.Losses}}{{end}}</td> 744 - <td>{{if $e.IsPending}}-{{else}}<span class="win-rate {{winRateClass $e}}">{{winRate $e}}%</span>{{end}}</td> 745 - <td>{{if $e.IsPending}}-{{else}}{{printf "%.1f" $e.AvgMoves}}{{end}}</td> 746 - <td style="color: #64748b;">{{if $e.IsPending}}Waiting...{{else}}{{$e.LastPlayed.Format "Jan 2, 3:04 PM"}}{{end}}</td> 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;">(compilation 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}}Failed{{else}}{{$e.LastPlayed.Format "Jan 2, 3:04 PM"}}{{end}}</td> 747 760 </tr> 748 761 {{end}} 749 762 {{else}}
+25 -6
internal/storage/database.go
··· 21 21 Stage string 22 22 LastPlayed time.Time 23 23 IsPending bool 24 + IsBroken bool 24 25 } 25 26 26 27 type Submission struct { ··· 199 200 SUM(CASE WHEN m.player1_id = s.id THEN m.player2_wins WHEN m.player2_id = s.id THEN m.player1_wins ELSE 0 END) as total_losses, 200 201 AVG(CASE WHEN m.player1_id = s.id THEN m.player1_moves ELSE m.player2_moves END) as avg_moves, 201 202 MAX(m.timestamp) as last_played, 202 - 0 as is_pending 203 + 0 as is_pending, 204 + 0 as is_broken 203 205 FROM submissions s 204 206 LEFT JOIN matches m ON (m.player1_id = s.id OR m.player2_id = s.id) AND m.is_valid = 1 205 - WHERE s.is_active = 1 207 + WHERE s.is_active = 1 AND s.status NOT IN ('compilation_failed') 206 208 GROUP BY s.username, s.glicko_rating, s.glicko_rd 207 209 HAVING COUNT(m.id) > 0 208 210 ··· 216 218 0 as total_losses, 217 219 0.0 as avg_moves, 218 220 s.upload_time as last_played, 219 - 1 as is_pending 221 + 1 as is_pending, 222 + 0 as is_broken 220 223 FROM submissions s 221 224 LEFT JOIN matches m ON (m.player1_id = s.id OR m.player2_id = s.id) AND m.is_valid = 1 222 225 WHERE s.is_active = 1 AND s.status IN ('pending', 'testing', 'completed') 223 226 GROUP BY s.username, s.upload_time 224 227 HAVING COUNT(m.id) = 0 225 228 226 - ORDER BY is_pending ASC, rating DESC, total_wins DESC 229 + UNION ALL 230 + 231 + SELECT 232 + s.username, 233 + 0 as rating, 234 + 0 as rd, 235 + 0 as total_wins, 236 + 0 as total_losses, 237 + 0.0 as avg_moves, 238 + s.upload_time as last_played, 239 + 0 as is_pending, 240 + 1 as is_broken 241 + FROM submissions s 242 + WHERE s.is_active = 1 AND s.status = 'compilation_failed' 243 + 244 + ORDER BY is_broken ASC, is_pending ASC, rating DESC, total_wins DESC 227 245 LIMIT ? 228 246 ` 229 247 ··· 238 256 var e LeaderboardEntry 239 257 var lastPlayed string 240 258 var rating, rd float64 241 - var isPending int 242 - err := rows.Scan(&e.Username, &rating, &rd, &e.Wins, &e.Losses, &e.AvgMoves, &lastPlayed, &isPending) 259 + var isPending, isBroken int 260 + err := rows.Scan(&e.Username, &rating, &rd, &e.Wins, &e.Losses, &e.AvgMoves, &lastPlayed, &isPending, &isBroken) 243 261 if err != nil { 244 262 return nil, err 245 263 } ··· 247 265 e.Rating = int(rating) 248 266 e.RD = int(rd) 249 267 e.IsPending = isPending == 1 268 + e.IsBroken = isBroken == 1 250 269 251 270 totalGames := e.Wins + e.Losses 252 271 if totalGames > 0 {