forked from Kelder/ceneka-bot-battle
add graph
This commit is contained in:
parent
228a069bf3
commit
8d38b87989
2 changed files with 156 additions and 31 deletions
65
main.py
65
main.py
|
@ -1,18 +1,70 @@
|
||||||
import requests
|
import requests
|
||||||
from flask import Flask, jsonify, render_template
|
from flask import Flask, jsonify, render_template
|
||||||
|
|
||||||
users = {"local_klink": "Francis"}
|
users = {
|
||||||
|
"local_klink": "Francis",
|
||||||
|
"awful_lickilicky": "geen-zeuser",
|
||||||
|
"decisive_grookey": "geen",
|
||||||
|
"sweet_munna": "geen",
|
||||||
|
"lazy_pichu": "geen",
|
||||||
|
"stupid_magikarp": "geen",
|
||||||
|
"superficial_gigalith": "geen",
|
||||||
|
"ugly_kingdra": "geen",
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_game_data():
|
||||||
|
res = requests.get("https://botbattle.be/api/games")
|
||||||
|
return sorted(res.json(), key=lambda x: x['gid'])
|
||||||
|
|
||||||
def get_data():
|
def get_data():
|
||||||
res = requests.get("https://botbattle.be/api/leaderboard")
|
res = requests.get("https://botbattle.be/api/leaderboard")
|
||||||
return res.json()
|
return res.json()
|
||||||
|
|
||||||
|
def process_game_data(game_data):
|
||||||
|
bots: dict[str, dict] = {}
|
||||||
|
|
||||||
|
min_elo: int | None = None
|
||||||
|
max_elo: int | None = None
|
||||||
|
|
||||||
|
for game in game_data:
|
||||||
|
for user in game['users']:
|
||||||
|
username = user['username']
|
||||||
|
if username in users:
|
||||||
|
if username not in bots:
|
||||||
|
if min_elo is None:
|
||||||
|
min_elo = user['elo']
|
||||||
|
max_elo = user['elo']
|
||||||
|
bots[username] = {'x': [], 'y': [], 'color_ring': user['color_ring'], 'color_body': user['color_body']}
|
||||||
|
|
||||||
|
if user['elo'] < min_elo:
|
||||||
|
min_elo = user['elo']
|
||||||
|
elif user['elo'] > max_elo:
|
||||||
|
max_elo = user['elo']
|
||||||
|
|
||||||
|
bots[username]['x'].append(game['gid'])
|
||||||
|
bots[username]['y'].append(user['elo'])
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
'bots': bots,
|
||||||
|
'min_elo': min_elo,
|
||||||
|
'max_elo': max_elo,
|
||||||
|
'game': game_data[-1]['gid'],
|
||||||
|
}
|
||||||
|
|
||||||
def filter_date(data):
|
def filter_date(data):
|
||||||
data = sorted(data, key=lambda x: x["elo"], reverse=True)
|
data = sorted(data, key=lambda x: x["elo"], reverse=True)
|
||||||
filtered = list(filter(lambda x: x["username"] in users.keys(), data))
|
filtered = []
|
||||||
[dict.update(item, position=index + 1, name=users[item["username"]]) for index, item in enumerate(filtered)]
|
|
||||||
|
for i, user in enumerate(data):
|
||||||
|
user["global_position"] = i + 1
|
||||||
|
|
||||||
|
if user['username'] not in users:
|
||||||
|
continue
|
||||||
|
|
||||||
|
filtered.append(user)
|
||||||
|
user['name'] = users[user['username']]
|
||||||
|
|
||||||
return filtered
|
return filtered
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,9 +81,12 @@ def index():
|
||||||
@app.route("/leaderboard")
|
@app.route("/leaderboard")
|
||||||
def leaderboard():
|
def leaderboard():
|
||||||
data = get_data()
|
data = get_data()
|
||||||
filtered = filter_date(data)
|
return jsonify(filter_date(data))
|
||||||
return jsonify(filtered)
|
|
||||||
|
|
||||||
|
@app.route("/graph")
|
||||||
|
def graph():
|
||||||
|
data = get_game_data()
|
||||||
|
return jsonify(process_game_data(data))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run()
|
app.run()
|
||||||
|
|
|
@ -1,8 +1,21 @@
|
||||||
{% extends "header.html" %} {% block content %}
|
{% extends "header.html" %} {% block content %}
|
||||||
<header>
|
<div class="card m-5">
|
||||||
<h1 class="title">Leaderboard</h1>
|
<div class="card-content is-size-2 has-text-centered">
|
||||||
</header>
|
Zeus Leaderboard - CeneBotBattle
|
||||||
<table class="table">
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="columns m-5 is-gapless">
|
||||||
|
<div class="column">
|
||||||
|
<div class="card ">
|
||||||
|
<div class="card-content" style="height: 1000px">
|
||||||
|
<canvas id="le_graph" width="300" height="150" style="height: 100%;width:100%"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="column ml-5 is-one-third">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-content">
|
||||||
|
<table class="table is-fullwidth is-size-4">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Position</th>
|
<th>Position</th>
|
||||||
|
@ -14,7 +27,7 @@
|
||||||
<tbody id="leaderboard-body">
|
<tbody id="leaderboard-body">
|
||||||
{% for row in data %}
|
{% for row in data %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ row['position'] }}</td>
|
<td>{{ row['global_position'] }}</td>
|
||||||
<td>{{ row['name'] }}</td>
|
<td>{{ row['name'] }}</td>
|
||||||
<td>{{ row['elo'] }}</td>
|
<td>{{ row['elo'] }}</td>
|
||||||
<td>{{ row['username'] }}</td>
|
<td>{{ row['username'] }}</td>
|
||||||
|
@ -23,10 +36,18 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
async function fetchLeaderboardData() {
|
async function fetchLeaderboardData() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("http://localhost:5000/leaderboard");
|
const response = await fetch("/leaderboard");
|
||||||
if (!response.ok) return;
|
if (!response.ok) return;
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
@ -38,10 +59,10 @@
|
||||||
data.forEach((row) => {
|
data.forEach((row) => {
|
||||||
const tr = document.createElement("tr");
|
const tr = document.createElement("tr");
|
||||||
tr.innerHTML = `
|
tr.innerHTML = `
|
||||||
<td>${row.position}</td>
|
<td>${row.global_position}</td>
|
||||||
<td>${row.name}</td>
|
<td>${row.name}</td>
|
||||||
<td>${row.elo}</td>
|
<td>${row.elo}</td>
|
||||||
<td>${row.username}</td>
|
<td><span class="tag is-large" style="background-color: ${row.color_ring}">${row.username}</span></td>
|
||||||
`;
|
`;
|
||||||
tableBody.appendChild(tr);
|
tableBody.appendChild(tr);
|
||||||
});
|
});
|
||||||
|
@ -50,11 +71,60 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getX(width, margin, min_game, max_game, game) {
|
||||||
|
return ((game - min_game) / (max_game - min_game) * (width - margin * 2)) + margin
|
||||||
|
}
|
||||||
|
|
||||||
|
function getY(height, margin, min_elo, max_elo, elo) {
|
||||||
|
return (height - ((elo - min_elo) / (max_elo - min_elo) * (height - margin * 2))) - margin
|
||||||
|
}
|
||||||
|
|
||||||
|
async function draw_graph() {
|
||||||
|
let canvas = document.getElementById('le_graph')
|
||||||
|
let ctx = canvas.getContext("2d")
|
||||||
|
|
||||||
|
try {
|
||||||
|
let res = await fetch("/graph")
|
||||||
|
let graph_data = await res.json()
|
||||||
|
|
||||||
|
let bots = graph_data.bots
|
||||||
|
|
||||||
|
resizeToParent(canvas)
|
||||||
|
|
||||||
|
const width = canvas.width
|
||||||
|
const height = canvas.height
|
||||||
|
const margin = 20
|
||||||
|
|
||||||
|
for (const [_, bot] of Object.entries(bots)) {
|
||||||
|
console.log(bot)
|
||||||
|
ctx.lineWidth = 4
|
||||||
|
ctx.strokeStyle = bot.color_ring
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(getX(width, margin, 0, graph_data.game, bot.x[0]), getY(height, margin, graph_data.min_elo, graph_data.max_elo, bot.y[0]))
|
||||||
|
for (let i = 1; i < bot.x.length; i++) {
|
||||||
|
ctx.lineTo(getX(width, margin, 0, graph_data.game, bot.x[i]), getY(height, margin, graph_data.min_elo, graph_data.max_elo, bot.y[i]))
|
||||||
|
}
|
||||||
|
console.log("stroking")
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Failed to fetch graph data:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resizeToParent(canvas) {
|
||||||
|
/* https://stackoverflow.com/questions/70128894/how-to-force-a-canvas-size-to-real-size-of-a-window-in-pixels-disregarding-the */
|
||||||
|
canvas.width = canvas.clientWidth * window.devicePixelRatio;
|
||||||
|
canvas.height = canvas.clientHeight * window.devicePixelRatio;
|
||||||
|
}
|
||||||
|
|
||||||
// Poll the server every 5 seconds
|
// Poll the server every 5 seconds
|
||||||
setInterval(fetchLeaderboardData, 5000);
|
setInterval(fetchLeaderboardData, 5000);
|
||||||
|
setInterval(draw_graph, 5000);
|
||||||
|
|
||||||
// Initial load
|
// Initial load
|
||||||
fetchLeaderboardData();
|
fetchLeaderboardData();
|
||||||
|
draw_graph();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
Loading…
Reference in a new issue