From 6bb4eed3301918bbb6b1bf00dc8a977d954500ed Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Wed, 30 Sep 2020 07:08:48 +0200 Subject: [PATCH 1/9] update gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index ab03117..eb4df03 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.swp +*.sqlite config.py *.txt *.ncsv @@ -11,3 +12,5 @@ __pychache__/ build/ configparse_wrapper/ static/bootstrap/ +static/moment.js +*.exe From 498892158bc21ab6e75690385c64205ee0a4638b Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Wed, 30 Sep 2020 07:09:21 +0200 Subject: [PATCH 2/9] update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2e7c983..06308da 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ The system was developed to be used with the [skillbird-framwork](https://github - [MDB Jquery](https://mdbootstrap.com/docs/jquery/getting-started/download/) (unpack to ./static/bootstrap/) - [Fontawesome](https://fontawesome.com/download) (move to static/boostrap/fontawesome.css) - ``python3 -m pip install -r req.txt`` +- [Moment.js](https://momentjs.com/downloads/moment.js) (directly into static/) # How to run From 08d3a5ae1b5bb6eea8beb71875f4aa4835d0efae Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Wed, 30 Sep 2020 07:09:44 +0200 Subject: [PATCH 3/9] extract header to extra template --- templates/default_head_content.html | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 templates/default_head_content.html diff --git a/templates/default_head_content.html b/templates/default_head_content.html new file mode 100644 index 0000000..c04c996 --- /dev/null +++ b/templates/default_head_content.html @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 530624ffe8696f2396f562d342d67879afd657d6 Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Wed, 30 Sep 2020 07:10:17 +0200 Subject: [PATCH 4/9] various visual and performance updates --- Round.py | 14 +++-- database.py | 28 ++++++++-- player.py | 9 ++-- server.py | 35 ++++++++----- templates/base.html | 18 +------ templates/navbar.html | 5 +- templates/navbar_leaderboard.html | 5 +- templates/player.html | 43 ++++++++-------- templates/rounds.html | 51 +++++++++--------- templates/single_round.html | 86 ++++++++++++++++++++++--------- 10 files changed, 181 insertions(+), 113 deletions(-) diff --git a/Round.py b/Round.py index 209ce30..b1a132d 100644 --- a/Round.py +++ b/Round.py @@ -12,8 +12,9 @@ class Round: losersParsed = json.loads(losers) self.startTime = startTime - self.winners = [ player.playerFromDict(wp) for wp in winnersParsed ] - self.losers = [ player.playerFromDict(lp) for lp in losersParsed ] + self.id = int(float(timestamp)) + self.winners = [ player.playerFromDict(wp, int(duration)) for wp in winnersParsed ] + self.losers = [ player.playerFromDict(lp, int(duration)) for lp in losersParsed ] self.winnerSide = winnerSide self.duration = datetime.timedelta(seconds=int(duration)) @@ -28,10 +29,13 @@ class Round: else: self.mapName = "unavailiable" - self.confidence = int(confidence * 100) - if prediction == 0: + self.confidence = (int(confidence * 100) - 50)*2 + self.quality = int(150 - self.confidence) + if self.confidence < 50: + self.prediction = "-" + elif prediction == 0: self.prediction = self.winnerSideString elif prediction == 1: self.prediction = self.loserSideString else: - self.prediction = "Error" + self.prediction = "Error" \ No newline at end of file diff --git a/database.py b/database.py index 327e251..ca2df5c 100644 --- a/database.py +++ b/database.py @@ -101,8 +101,7 @@ class DatabaseConnection: cursor.execute("SELECT * FROM players WHERE name LIKE ?", (playerNamePrepared,)) playerRow = cursor.fetchone() if not playerRow: - conn.close() - return (None, None) + return None playerInLeaderboard = player.PlayerInLeaderboard(playerRow) playerInLeaderboard.rank = self.getPlayerRank(playerInLeaderboard) @@ -127,6 +126,7 @@ class DatabaseConnection: cursor = self.connRounds.cursor() cursor.execute('''SELECT * FROM rounds WHERE timestamp between ? and ? + AND duration > 120.0 order by timestamp DESC''', (start.timestamp(), end.timestamp())) rounds = [] @@ -139,6 +139,14 @@ class DatabaseConnection: cursorHist = self.connHistorical.cursor() for p in roundObj.winners + roundObj.losers: + cursorHist.execute('''SELECT count(*) FROM playerHistoricalData + WHERE timestamp < ? AND id = ?''', + (roundObj.startTime.timestamp(), p.playerId)) + + if(cursorHist.fetchone()[0] < 10): + p.ratingChangeString = "Placements" + continue + cursorHist.execute('''SELECT mu,sima FROM playerHistoricalData WHERE timestamp < ? AND id = ? LIMIT 1 ''', (roundObj.startTime.timestamp(), p.playerId)) @@ -154,7 +162,21 @@ class DatabaseConnection: p.sigma = sigmaPrev p.muChange = muAfter - muPrev p.sigmaChange = sigmaAfter - sigmaPrev - p.ratingChangeString = str( ( muAfter-2*sigmaAfter ) - ( muPrev-2*sigmaPrev) ) + ratingChange = int( (muAfter-muPrev) - 2*(sigmaAfter-sigmaPrev) ) + if(ratingChange < 0): + p.ratingChangeString = "-  {:x>5}".format(abs(ratingChange)) + else: + p.ratingChangeString = "+ {:x>5}".format(ratingChange) + p.ratingChangeString = p.ratingChangeString.replace("x", " ") + + roundObj.winnerRatingTotal = sum([p.mu - 2*p.sigma for p in roundObj.winners]) + roundObj.losersRatingTotal = sum([p.mu - 2*p.sigma for p in roundObj.losers]) + higher = max(roundObj.winnerRatingTotal, roundObj.losersRatingTotal) + lower = min(roundObj.winnerRatingTotal, roundObj.losersRatingTotal) + if higher/lower > 2.1: + roundObj.invalid = "Not rated because of team imbalance." + else: + roundObj.invalid = "" return roundObj diff --git a/player.py b/player.py index 088e95c..2a40f9c 100644 --- a/player.py +++ b/player.py @@ -1,8 +1,10 @@ #!/usr/bin/python3 import flask -def playerFromDict(d): - return PlayerInLeaderboard([d["id"], d["name"], None, 0, 0, 0, 0]) +def playerFromDict(d, duration): + p = PlayerInLeaderboard([d["id"], d["name"], None, 0, 0, 0, 0]) + p.participation = min(int(d["active_time"]/duration*100), 100) + return p class PlayerInLeaderboard: def __init__(self, dbRow): @@ -21,10 +23,11 @@ class PlayerInLeaderboard: self.loses = self.games - self.wins self.rank = None self.lastGame = lastGame + self.participation = -1 self.muChange = None self.sigmaChange = None - self.ratingChangeString = "--" + self.ratingChangeString = "N/A" # determine winratio # if self.games == 0: diff --git a/server.py b/server.py index 8e8ce2a..8358406 100755 --- a/server.py +++ b/server.py @@ -34,14 +34,21 @@ def singleRound(): timestamp = flask.request.args.get("id") if not timestamp: - return ("", 404) + return ("ID Missing", 404) + if not timestamp.endswith(".0"): + timestamp = timestamp + ".0" db = DatabaseConnection(app.config["DB_PATH"]) r = db.getRoundByTimestamp(timestamp) + if not r: + return ("Round not found", 404) r = db.calcRatingChanges(r) if not r: return ("", 404) + r.winners = sorted(r.winners, key=lambda p: p.participation, reverse=True) + r.losers = sorted(r.losers, key=lambda p: p.participation, reverse=True) + return flask.render_template("single_round.html", r=r) @app.route("/rounds-by-timestamp") @@ -53,7 +60,7 @@ def rounds(): end = flask.request.args.get("end") if not start or not end: - start = datetime.datetime.now() - datetime.timedelta(days=4000) + start = datetime.datetime.now() - datetime.timedelta(days=7) end = datetime.datetime.now() else: start = datetime.datetime.fromtimestamp(start) @@ -97,15 +104,19 @@ def player(): if histData: datapoints = histData[playerId] if datapoints: + + tickCounter = 10 for dpk in datapoints.keys(): - - ratingString = str(int(datapoints[dpk]["mu"]) - 2*int(datapoints[dpk]["sigma"])) - ratingAmored = '"' + ratingString + '"' - csv_ratings += [ratingAmored] t = datetime.datetime.fromtimestamp(int(float(dpk))) - tString = t.strftime("%m %Y") - tStringAmored = '"' + tString + '"' - csv_month_year += [tStringAmored] + tsMs = str(int(t.timestamp() * 1000)) + ratingString = str(int(datapoints[dpk]["mu"]) - 2*int(datapoints[dpk]["sigma"])) + ratingAmored = '{ x : ' + tsMs + ', y : ' + ratingString + '}' + csv_ratings += [ratingAmored] + + tickCounter -= 1 + if tickCounter <= 0: + tickCounter = 10 + csv_month_year += ['new Date({})'.format(tsMs)] minRating = min(minRating, int(ratingString)) maxRating = max(maxRating, int(ratingString)) @@ -145,13 +156,13 @@ def leaderboard(): if playerName: playerInLeaderboard = db.findPlayerByName(playerName) - if(playerInLeaderboard.games < 10): - return flask.redirect("/player?id={}".format(playerInLeaderboard.playerId)) - rank = playerInLeaderboard.rank if not playerInLeaderboard: cannotFindPlayer = flask.Markup("
No player of that name
") start = 0 else: + rank = playerInLeaderboard.rank + if(playerInLeaderboard.games < 10): + return flask.redirect("/player?id={}".format(playerInLeaderboard.playerId)) searchName = playerInLeaderboard.name start = rank - (rank % SEGMENT) diff --git a/templates/base.html b/templates/base.html index 3462f0d..c7886c2 100644 --- a/templates/base.html +++ b/templates/base.html @@ -2,23 +2,9 @@ Leaderboard - - + - - - - - - - - - - - - - - + {% include "default_head_content.html" %} {% include 'navbar_leaderboard.html' %} diff --git a/templates/navbar.html b/templates/navbar.html index 1e140ff..54f7bc2 100644 --- a/templates/navbar.html +++ b/templates/navbar.html @@ -10,7 +10,10 @@ diff --git a/templates/navbar_leaderboard.html b/templates/navbar_leaderboard.html index 7694a43..591c37a 100644 --- a/templates/navbar_leaderboard.html +++ b/templates/navbar_leaderboard.html @@ -20,8 +20,11 @@