mirror of https://github.com/dirtbags/moth.git
251 lines
6.5 KiB
Awk
Executable File
251 lines
6.5 KiB
Awk
Executable File
#! /bin/awk -f
|
|
|
|
##
|
|
##
|
|
## I'm not super happy with how this code looks. Rest assured, though,
|
|
## the C version would look far, far worse.
|
|
##
|
|
##
|
|
|
|
function qsort(A, left, right, i, last) {
|
|
if (left >= right)
|
|
return
|
|
swap(A, left, left+int((right-left+1)*rand()))
|
|
last = left
|
|
for (i = left+1; i <= right; i++)
|
|
if (A[i] < A[left])
|
|
swap(A, ++last, i)
|
|
swap(A, left, last)
|
|
qsort(A, left, last-1)
|
|
qsort(A, last+1, right)
|
|
}
|
|
function swap(A, i, j, t) {
|
|
t = A[i]; A[i] = A[j]; A[j] = t
|
|
}
|
|
|
|
function escape(s) {
|
|
gsub("&", "&", s)
|
|
gsub("<", "<", s)
|
|
gsub(">", ">", s)
|
|
return s
|
|
}
|
|
|
|
function print_bar(cat, teamid, teamname, n, d) {
|
|
printf("<div class=\"t%s score\"" \
|
|
" style=\"height: %.2f%%;\"" \
|
|
" onmouseover=\"highlight('%s')\"" \
|
|
" onmouseout=\"restore('%s')\">\n" \
|
|
"<!-- %s --> %s: %s\n" \
|
|
"</div>",
|
|
teamid,
|
|
100 * n / d,
|
|
teamid,
|
|
teamid,
|
|
cat, escape(name), n)
|
|
}
|
|
|
|
function output( t, c) {
|
|
for (t in teams) {
|
|
score = 0;
|
|
for (c in points_by_cat) {
|
|
if (points_by_cat[c] > 0) {
|
|
score += points_by_cat_team[c, t] / points_by_cat[c];
|
|
}
|
|
}
|
|
if (score > maxscore) {
|
|
maxscore = score
|
|
}
|
|
if (score > maxscores_by_team[t]) {
|
|
maxscores_by_team[t] = score
|
|
}
|
|
scores_by_team_time[t, lasttime] = score
|
|
}
|
|
timestamps[tslen++] = lasttime
|
|
}
|
|
|
|
BEGIN {
|
|
base = ENVIRON["CTF_BASE"]
|
|
|
|
# Only display two decimal places
|
|
CONVFMT = "%.2f"
|
|
|
|
# New point at least every 2.5 minutes
|
|
interval = 150
|
|
tslen = 0
|
|
|
|
nteams = 0;
|
|
}
|
|
|
|
# MAINLOOP
|
|
{
|
|
time = $1
|
|
team = $2
|
|
cat = $3
|
|
points = int($4)
|
|
|
|
if (! start) {
|
|
start = time
|
|
}
|
|
|
|
if (time > (outtime + interval)) {
|
|
outtime = time
|
|
output()
|
|
}
|
|
lasttime = time
|
|
|
|
teams[team] = nteams++
|
|
points_by_cat[cat] += points
|
|
points_by_cat_team[cat, team] += points
|
|
}
|
|
|
|
END {
|
|
output()
|
|
|
|
# Get team colors and names
|
|
for (team in teams) {
|
|
# Busybox awk segfaults if you try to close a file that didn't
|
|
# exist. We work around it by calling cat.
|
|
cmd = sprintf("cat %s/state/teams/colors/%s", base, team)
|
|
color = "444444";
|
|
cmd | getline color
|
|
colors_by_team[team] = color
|
|
close(cmd)
|
|
|
|
cmd = sprintf("cat %s/state/teams/names/%s", base, team)
|
|
name = "Phantoms"
|
|
cmd | getline name
|
|
names_by_team[team] = name
|
|
close(cmd)
|
|
}
|
|
|
|
# Sort categories
|
|
ncats = 0
|
|
for (cat in points_by_cat) {
|
|
cats[ncats++] = cat
|
|
}
|
|
qsort(cats, 0, ncats-1)
|
|
|
|
# Create a sorted list of scores
|
|
nteams = 0
|
|
for (team in teams) {
|
|
scores[nteams++] = scores_by_team_time[team, lasttime]
|
|
}
|
|
qsort(scores, 0, nteams-1)
|
|
|
|
|
|
# Now we can start writing the document
|
|
print "<!DOCTYPE html>"
|
|
print "<html class=\"scoreboard\">"
|
|
print " <head>"
|
|
print " <title>Scoreboard</title>"
|
|
print " <link rel=\"stylesheet\" href=\"ctf.css\" type=\"text/css\">"
|
|
print " <script type=\"application/javascript\" src=\"scoreboard.js\"></script>"
|
|
|
|
# Provide raw data for the chart
|
|
print " <script type=\"application/javascript\">"
|
|
print "function init() {"
|
|
printf(" plot(\"chart\", %d, %.2f, {\n", tslen, maxscore)
|
|
c = 0
|
|
for (team in teams) {
|
|
if (maxscores_by_team[team] / maxscore < 0.01) continue
|
|
printf(" \"%s\": [\"#%s\",[", teams[team], colors_by_team[team])
|
|
for (i = 1; i < tslen; i += 1) {
|
|
time = timestamps[i]
|
|
printf("[%d,%.2f],",
|
|
i, scores_by_team_time[team, time])
|
|
}
|
|
printf("]],\n");
|
|
}
|
|
print " });"
|
|
print " if (location.hash) {"
|
|
print " cycle();"
|
|
print " setInterval(cycle, 10000);"
|
|
print " }"
|
|
print "}"
|
|
print "window.onload = init;"
|
|
print " </script>"
|
|
|
|
# Reload every minute
|
|
print " <meta http-equiv=\"refresh\" content=\"60\">"
|
|
|
|
# Set up team colors and a few page-specific styles
|
|
print " <style type=\"text/css\">"
|
|
print " body { width: 100%; }"
|
|
print " .score { overflow: hidden; color: black; }"
|
|
for (team in teams) {
|
|
printf(" .t%s { background-color: #%s; }\n",
|
|
teams[team], colors_by_team[team])
|
|
}
|
|
print " </style>"
|
|
|
|
print " </head>"
|
|
print " <body>"
|
|
print " <h1>Scoreboard</h1>"
|
|
print " <p id=\"debug\"></p>"
|
|
print " <img src=\"backup.png?" NR "\" alt=\"\" style=\"display: none;\" height=\"1\" width=\"1\">"
|
|
print " <table id=\"scoreboard\">"
|
|
print " <tr>"
|
|
print " <th>Overall</th>"
|
|
|
|
# Print out category names
|
|
for (i = 0; i < ncats; i += 1) {
|
|
cat = cats[i]
|
|
points = points_by_cat[cat]
|
|
if (0 == points) continue
|
|
printf("<th>%s (%d)</th>\n", cat, points)
|
|
}
|
|
|
|
print " </tr>"
|
|
print " <tr>"
|
|
|
|
# Print out teams, ranked by score
|
|
print " <td>"
|
|
for (i = 0; i < nteams; i += 1) {
|
|
if (scores[i] == scores[i-1]) continue;
|
|
for (team in teams) {
|
|
if (scores[i] == scores_by_team_time[team, lasttime]) {
|
|
name = names_by_team[team]
|
|
print_bar("total", teams[team], name, scores[i], ncats)
|
|
}
|
|
}
|
|
}
|
|
print " </td>"
|
|
|
|
# Print out scores within each category
|
|
for (i = 0; i < ncats; i += 1) {
|
|
cat = cats[i]
|
|
points = points_by_cat[cat]
|
|
if (0 == points) break;
|
|
|
|
print "<td>"
|
|
|
|
# Create sorted list of scores in this category
|
|
n = 0
|
|
for (team in teams) {
|
|
l[n++] = points_by_cat_team[cat, team];
|
|
}
|
|
qsort(l, 0, n-1)
|
|
|
|
# Print out teams, ranked by points
|
|
for (j = 0; j < n; j += 1) {
|
|
if (l[j] == l[j-1]) continue;
|
|
if (0 == l[j]) continue;
|
|
for (team in teams) {
|
|
points = points_by_cat_team[cat, team]
|
|
if (l[j] == points) {
|
|
name = names_by_team[team]
|
|
print_bar(cat, teams[team], name, points, points_by_cat[cat])
|
|
}
|
|
}
|
|
}
|
|
|
|
print "</td>"
|
|
}
|
|
print " </tr>"
|
|
|
|
print " </table>"
|
|
print " <canvas id=\"chart\" width=\"1024\" height=\"240\"></canvas>"
|
|
print " </body>"
|
|
print "</html>"
|
|
}
|