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
|
||||
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():
|
||||
res = requests.get("https://botbattle.be/api/leaderboard")
|
||||
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):
|
||||
data = sorted(data, key=lambda x: x["elo"], reverse=True)
|
||||
filtered = list(filter(lambda x: x["username"] in users.keys(), data))
|
||||
[dict.update(item, position=index + 1, name=users[item["username"]]) for index, item in enumerate(filtered)]
|
||||
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
|
||||
|
||||
|
||||
|
@ -29,9 +81,12 @@ def index():
|
|||
@app.route("/leaderboard")
|
||||
def leaderboard():
|
||||
data = get_data()
|
||||
filtered = filter_date(data)
|
||||
return jsonify(filtered)
|
||||
return jsonify(filter_date(data))
|
||||
|
||||
@app.route("/graph")
|
||||
def graph():
|
||||
data = get_game_data()
|
||||
return jsonify(process_game_data(data))
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
|
|
|
@ -1,8 +1,21 @@
|
|||
{% extends "header.html" %} {% block content %}
|
||||
<header>
|
||||
<h1 class="title">Leaderboard</h1>
|
||||
</header>
|
||||
<table class="table">
|
||||
<div class="card m-5">
|
||||
<div class="card-content is-size-2 has-text-centered">
|
||||
Zeus Leaderboard - CeneBotBattle
|
||||
</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>
|
||||
<tr>
|
||||
<th>Position</th>
|
||||
|
@ -14,19 +27,27 @@
|
|||
<tbody id="leaderboard-body">
|
||||
{% for row in data %}
|
||||
<tr>
|
||||
<td>{{ row['position'] }}</td>
|
||||
<td>{{ row['global_position'] }}</td>
|
||||
<td>{{ row['name'] }}</td>
|
||||
<td>{{ row['elo'] }}</td>
|
||||
<td>{{ row['username'] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
async function fetchLeaderboardData() {
|
||||
try {
|
||||
const response = await fetch("http://localhost:5000/leaderboard");
|
||||
const response = await fetch("/leaderboard");
|
||||
if (!response.ok) return;
|
||||
|
||||
const data = await response.json();
|
||||
|
@ -38,10 +59,10 @@
|
|||
data.forEach((row) => {
|
||||
const tr = document.createElement("tr");
|
||||
tr.innerHTML = `
|
||||
<td>${row.position}</td>
|
||||
<td>${row.global_position}</td>
|
||||
<td>${row.name}</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);
|
||||
});
|
||||
|
@ -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
|
||||
setInterval(fetchLeaderboardData, 5000);
|
||||
setInterval(draw_graph, 5000);
|
||||
|
||||
// Initial load
|
||||
fetchLeaderboardData();
|
||||
draw_graph();
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in a new issue