$ cd ../
$ cat /backups/brain/
0036CTFTime automatic points calculationAutomatically calculate CTFTime Rating points manually (scorebard not ready
yet) or automatically from a CTFTime entry (for re-calculation or export).
Possible improvements:
- Proper HTML better parsing or use an API if available
- Support CTFd scoreboards
Usage:
1
2
3
ctf-points CTFTIME_URL # Calculate it automatically from CTFTime (LosFuzzys)
ctf-points CTFTIME_URL TEAM_ID # Calculate it automatically from CTFTime
ctf-points # Calculate it manually
Sample output:
1
2
3
4
5
6
7
8
[ecomaikgolf@laptop ../.local/bin/]$ ctf-points https://ctftime.org/event/2273 8323
[+] Team points: 5206.0
[+] Best points: 20412.0
[+] Team place: 7
[+] Weight: 24.5
[+] Final rating: 9.749
- Part of points: 6.249
- Part of placement: 3.500
Source (so vulnerable to malicious team names it ain’t even funny lol):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#!/usr/bin/env -S uv run --script
# /// script
# dependencies = [
# "requests"
# ]
# ///
import sys
import requests
def lookup(s, start, end):
w_s = s.find(start) + len(start)
w_e = s[w_s:].find(end) + w_s
return s[w_s:w_e]
def calculate(team_points, best_points, team_place, weight):
# Calculate coefficients
points_coef = team_points / best_points
place_coef = 1 / team_place
# Calculate and display rating
if points_coef > 0:
e_rating = (points_coef + place_coef) * weight
print(f"[+] Final rating: {e_rating:.3f}")
print(f" - Part of points: {points_coef * weight:.3f}")
print(f" - Part of placement: {place_coef * weight:.3f}")
else:
print("[!] No points")
def manual():
# Get user inputs
team_points = float(input("[>] Team points: "))
best_points = float(input("[>] Best points: "))
team_place = float(input("[>] Team place: "))
weight = float(input("[>] Weight: "))
calculate(team_points, best_points, team_place, weight)
def automatic(url):
response = requests.get(url)
if response.status_code != 200:
print("[!] Error fetching CTFTime event page")
exit(1)
raw = response.text
weight = float(lookup(raw, "Rating weight:", " ").strip())
table = lookup(raw, "<table class=\"table table-striped past_event_rating\">", "</table>").split("<tr>")[2:]
bt = None
lf = None
teams = [None] * len(table)
i = 0
for t in table:
if(t.strip() == ""):
continue
t = t.replace("</td><td class=\"place leader\">", "")
t = t.replace("</td><td class=\"place\">", "")
place = int(lookup(t, "<td class=\"place_ico\">", "</td>"))
points = float(lookup(t, "<td class=\"points\">", "</td>"))
rating = float(lookup(t, "</td><td>", "</td>"))
id = int(lookup(t, "<a href=\"/team/", "\">"))
name = lookup(t, f"<a href=\"/team/{id}\">", "</a>")
assert teams[i] is None
teams[i] = {
"place": place,
"points": points,
"rating": rating,
"id": id,
"name": name,
}
if id == ID :
lf = teams[i]
if place == 1:
bt = teams[i]
i += 1
if lf is None:
print(f"[!] Couldn't find requested Team ID: {ID}")
exit(1)
print(f"[+] Team points: {lf["points"]}")
print(f"[+] Best points: {bt["points"]}")
print(f"[+] Team place: {lf["place"]}")
print(f"[+] Weight: {weight}")
calculate(lf["points"], bt["points"], lf["place"], weight)
ID = 8323 # LosFuzzys
URL = None
if len(sys.argv) >= 2:
URL = sys.argv[1]
if len(sys.argv) >= 3:
ID = int(sys.argv[2])
if URL is None:
manual()
else:
automatic(URL)
# vim: filetype=python
$ cd ../