#! /usr/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, team, n, d) { printf("
\n" \ " %s: %s\n" \ "
", team, 100 * n / d, team, team, cat, escape(names_by_team[team]), 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"] if (! base) { base = "/var/lib/ctf" } # Only display two decimal places CONVFMT = "%.2f" # New point at least every 2.5 minutes interval = 150 tslen = 0 nteams = 0; while (1 == getline) { 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 } 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/teams/colors/%s", base, team) cmd | getline color if (! color) color = "cccccc"; colors_by_team[team] = color close(cmd) cmd = sprintf("cat %s/teams/names/%s", base, team) cmd | getline name if (! name) name = "Avengers" 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 "" print "" print " " print " Scoreboard" print " " print " " # Provide raw data for the chart print " " # Reload every minute print " " # Set up team colors and a few page-specific styles print " " print " " print " " print "

Scoreboard

" print "

" print " " print " " print " " # Print out category names for (i = 0; i < ncats; i += 1) { cat = cats[i] points = points_by_cat[cat] if (0 == points) continue printf("\n", cat, points) } print " " print " " # Print out teams, ranked by score print " " # 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 "" } print " " print "
Overall%s (%d)
" 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], scores[i], ncats) } } } print " " # 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]) break; 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], points, points_by_cat[cat]) } } } print "
" print " " print "

About scoring

" print " " print "" }