Skip to content
This repository has been archived by the owner on Mar 30, 2020. It is now read-only.

Commit

Permalink
leagues in relative winrates
Browse files Browse the repository at this point in the history
  • Loading branch information
maddyblue committed Oct 1, 2018
1 parent 49cbf0c commit 31dbfe9
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 47 deletions.
2 changes: 1 addition & 1 deletion cron.go
Expand Up @@ -45,7 +45,7 @@ func (h *hotsContext) cron() error {
case "/api/get-winrates":
res, err = h.GetWinrates(ctx, req)
case "/api/get-hero-data":
res, err = h.GetHero(ctx, req)
res, err = h.GetRelativeWinrates(ctx, req)
case "/api/get-build-winrates":
res, err = h.GetBuildWinrates(ctx, req)
case "/api/get-compare-hero":
Expand Down
16 changes: 15 additions & 1 deletion frontend/src/Hero.js
@@ -1,5 +1,12 @@
import React, { Component } from 'react';
import { Fetch, pct, toLength, BuildsOpts, HeroHeader } from './common';
import {
Fetch,
pct,
toLength,
BuildsOpts,
HeroHeader,
skillBands,
} from './common';
import SortedTable from './SortedTable';

class Hero extends Component {
Expand Down Expand Up @@ -146,6 +153,12 @@ class Hero extends Component {
</tbody>
</table>
<table className="sorted">
{this.makeTable(
'League',
'Leagues',
basewr,
v => skillBands[v - 1]
)}
{this.makeTable('Map', 'Maps', basewr)}
{this.makeTable(
'Game Mode',
Expand Down Expand Up @@ -186,6 +199,7 @@ class Hero extends Component {
title={this.props}
/>
<p>
<a href="#leagues">[leagues]</a>
<a href="#maps">[maps]</a> <a href="#modes">[game modes]</a>{' '}
<a href="#lengths">[game lengths]</a>{' '}
<a href="#levels">[hero levels]</a>
Expand Down
136 changes: 91 additions & 45 deletions main.go
Expand Up @@ -238,7 +238,7 @@ func main() {
mux.Handle("/api/get-build-winrates", wrap(h.GetBuildWinrates))
mux.Handle("/api/get-compare-hero", wrap(h.GetCompareHero))
mux.Handle("/api/get-game-data", wrap(h.GetGameData))
mux.Handle("/api/get-hero-data", wrap(h.GetHero))
mux.Handle("/api/get-hero-data", wrap(h.GetRelativeWinrates))
mux.Handle("/api/get-leaderboard", wrap(h.GetLeaderboard))
mux.Handle("/api/get-player-by-name", wrap(h.GetPlayerName))
mux.Handle("/api/get-player-games", wrap(h.GetPlayerGames))
Expand Down Expand Up @@ -1387,26 +1387,29 @@ type heroRelativeData struct {
Levels map[string]Total
Maps map[string]Total
Modes map[string]Total
Leagues map[string]Total
}

func (h *hotsContext) GetHero(ctx context.Context, r *http.Request) (interface{}, error) {
func (h *hotsContext) GetRelativeWinrates(
ctx context.Context, r *http.Request,
) (interface{}, error) {
init := h.getInit()
build := init.config.build(r.FormValue("build"))
hero := init.config.hero(r.FormValue("hero"))
build := r.FormValue("build")
hero := r.FormValue("hero")
var res struct {
Current heroRelativeData
Previous heroRelativeData
}
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error {
var err error
res.Current, err = h.getHero(ctx, init, build, hero)
res.Current, err = h.getRelativeWinrates(ctx, init, build, hero)
return errors.Wrap(err, "getHero current build")
})
g.Go(func() error {
if prevBuild, ok := h.getBuildBefore(init, r.FormValue("build")); ok {
if prevBuild, ok := h.getBuildBefore(init, build); ok {
var err error
res.Previous, err = h.getHero(ctx, init, init.config.build(prevBuild), hero)
res.Previous, err = h.getRelativeWinrates(ctx, init, prevBuild, hero)
return errors.Wrap(err, "getHero previous build")
}
return nil
Expand All @@ -1415,23 +1418,23 @@ func (h *hotsContext) GetHero(ctx context.Context, r *http.Request) (interface{}
return res, err
}

func (h *hotsContext) getHero(
func (h *hotsContext) getRelativeWinrates(
ctx context.Context, init initData, build, hero string,
) (heroRelativeData, error) {
params := []interface{}{
build,
hero,
init.config.build(build),
init.config.hero(hero),
}
var res heroRelativeData
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error {
var err error
res.Base, err = h.countWins(ctx, nil, `
SELECT COUNT(*) count, winner, '' counter
FROM players
WHERE build = $1 AND hero = $2
GROUP BY winner
`, params)
SELECT COUNT(*) count, winner, '' counter
FROM players
WHERE build = $1 AND hero = $2
GROUP BY winner
`, params)
if res.Base != nil && len(res.Base) == 0 {
res.Base[""] = Total{}
}
Expand All @@ -1440,55 +1443,98 @@ func (h *hotsContext) getHero(
g.Go(func() error {
var err error
res.Maps, err = h.countWins(ctx, init.lookups["map"], `
SELECT COUNT(*) count, winner, map counter
FROM players
WHERE build = $1 AND hero = $2
GROUP BY winner, map
`, params)
SELECT COUNT(*) count, winner, map counter
FROM players
WHERE build = $1 AND hero = $2
GROUP BY winner, map
`, params)
return errors.Wrap(err, "maps")
})
g.Go(func() error {
var err error
res.Modes, err = h.countWins(ctx, nil, `
SELECT COUNT(*) count, winner, mode counter
FROM players
WHERE build = $1 AND hero = $2
GROUP BY winner, mode
`, params)
SELECT COUNT(*) count, winner, mode counter
FROM players
WHERE build = $1 AND hero = $2
GROUP BY winner, mode
`, params)
return errors.Wrap(err, "modes")
})
g.Go(func() error {
var err error
// Group hero levels by 5s.
res.Levels, err = h.countWins(ctx, nil, `
SELECT
count(*) AS count,
winner,
greatest(1, counter * 5) AS counter
FROM
(
SELECT winner, hero_level // 5 AS counter
FROM players
WHERE build = $1 AND hero = $2
)
GROUP BY winner, counter
`, params)
SELECT
count(*) AS count,
winner,
greatest(1, counter * 5) AS counter
FROM
(
SELECT winner, hero_level // 5 AS counter
FROM players
WHERE build = $1 AND hero = $2
)
GROUP BY winner, counter
`, params)
return errors.Wrap(err, "hero level")
})
g.Go(func() error {
var err error
// Group game lengths in 5 minute blocks.
res.Lengths, err = h.countWins(ctx, nil, `
SELECT count(*) count, winner, counter * 60 * 5 as counter
FROM (
SELECT winner, round(length / 60 / 5) as counter
FROM players
WHERE build = $1 AND hero = $2
)
GROUP BY winner, counter
`, params)
SELECT count(*) count, winner, counter * 60 * 5 as counter
FROM (
SELECT winner, round(length / 60 / 5) as counter
FROM players
WHERE build = $1 AND hero = $2
)
GROUP BY winner, counter
`, params)
return errors.Wrap(err, "length")
})
g.Go(func() error {
modes, ok := init.BuildStats[build]
if !ok {
return errors.Errorf("unknown build: %s", build)
}
var sb strings.Builder
sb.WriteString("case\n")
for m := range init.Modes {
quantiles := modes[m].Quantile
if quantiles[99] == 0 {
continue
}
for i := 1; i <= len(skillQuantiles); i++ {
fmt.Fprintf(&sb, "WHEN mode = %d", m)
if i > 1 {
fmt.Fprintf(&sb, " AND skill > %f", quantiles[skillQuantiles[i-1]])
}
if i < len(skillQuantiles) {
fmt.Fprintf(&sb, " AND skill <= %f", quantiles[skillQuantiles[i]])
}
fmt.Fprintf(&sb, " THEN %d\n", i)
}
}
sb.WriteString("\nend")

var err error
res.Leagues, err = h.countWins(ctx, nil, fmt.Sprintf(`
SELECT
count(*) AS count, winner, counter
FROM
(
SELECT
winner, %s AS counter
FROM
players
WHERE
build = $1 AND hero = $2
)
GROUP BY
winner, counter
`, sb.String()), params)
return errors.Wrap(err, "league")
})
err := g.Wait()
return res, err
}
Expand Down

0 comments on commit 31dbfe9

Please sign in to comment.