Created
May 26, 2021 20:48
-
-
Save gmalysa/902614b497e281d5c21d7a485344f4db to your computer and use it in GitHub Desktop.
FHDL Player and Captain Analysis
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
struct team { | |
const char *captain; | |
int32_t cap_mmr; | |
int32_t cash; | |
}; | |
struct player { | |
struct team *team; | |
int32_t cost; | |
const char *name; | |
int32_t mmr; | |
}; | |
static struct team yumi = {"Yumi", 3500, 1020}; | |
static struct team yop = {"yop", 4370, 720}; | |
static struct team waffz = {"waffz", 3970, 860}; | |
static struct team stonks = {"stonks", 4460, 690}; | |
static struct team lava = {"Lava", 3990, 850}; | |
static struct team firery = {"Fireryman", 3500, 1020}; | |
static struct team clare = {"Clare", 4350, 725}; | |
static struct team bibleman = {"Bibleman", 3820, 910}; | |
static struct team *teams[] = { | |
&yumi, &yop, &waffz, &stonks, | |
&lava, &firery, &clare, &bibleman | |
}; | |
static struct player players[] = { | |
{&yumi, 470, "Roar", 4470}, | |
{&yumi, 400, "Princess", 3760}, | |
{&yumi, 0, "SnowStorm", 3200}, | |
{&yumi, 100, "Woh", 3150}, | |
{&yop, 311, "teekay", 4100}, | |
{&yop, 90, "SorryBoutiT", 3590}, | |
{&yop, 55, "Mr.Child", 3400}, | |
{&yop, 264, "Crypt1c", 2750}, | |
{&waffz, 545, "Skroomlite", 4520}, | |
{&waffz, 155, "ChairmanMeow", 3500}, | |
{&waffz, 77, "MegaloMaNiAC", 2470}, | |
{&waffz, 46, "rogueandtasty", 1620}, | |
{&stonks, 270, "TheDude", 3900}, | |
{&stonks, 336, "Jackman", 3380}, | |
{&stonks, 3, "Level7", 2700}, | |
{&stonks, 81, "Quill", 2390}, | |
{&lava, 275, "FJFJFJJ", 4500}, | |
{&lava, 420, "ButteryGreg", 3930}, | |
{&lava, 80, "JBay7", 3370}, | |
{&lava, 75, "2000boxes", 2600}, | |
{&firery, 250, "yolksoup", 4620}, | |
{&firery, 580, "ad4m", 4020}, | |
{&firery, 165, "GSP", 3600}, | |
{&firery, 25, "WeeLickham", 3100}, | |
{&clare, 599, "ThePhantom", 4080}, | |
{&clare, 126, "EleM", 3400}, | |
{&clare, 0, "Reedy", 2920}, | |
{&clare, 0, "Korgoth", 2820}, | |
{&bibleman, 325, "Pingaling", 4000}, | |
{&bibleman, 90, "Cerys", 3450}, | |
{&bibleman, 375, "C9Lovell", 3300}, | |
{&bibleman, 120, "Debnis", 2700}, | |
}; | |
int get_team_id(struct team *t) { | |
int i = 0; | |
for (i = 0; i < 8; ++i) { | |
if (teams[i] == t) | |
return i; | |
} | |
return -1; | |
} | |
void v1(void); | |
void v2(void); | |
int main(int argc, char **argv) { | |
v1(); | |
v2(); | |
return 0; | |
} | |
/** | |
* "version 1" calculation, linear fit by mmr to cost assuming the lowest mmr is worth $0 | |
* These are pretty worthless but fun to look at. | |
*/ | |
void v1(void) { | |
int32_t dollars = 0; | |
int32_t mmr = 0; | |
int32_t min_mmr = 5000; | |
float s; | |
int i; | |
printf("v1:\n"); | |
for (i = 0; i < 8; ++i) { | |
dollars += teams[i]->cash; | |
} | |
for (i = 0; i < 32; ++i) { | |
mmr += players[i].mmr; | |
if (players[i].mmr < min_mmr) | |
min_mmr = players[i].mmr; | |
} | |
s = ((float)dollars) / (mmr - (32*min_mmr)); | |
printf("s = %f\n", s); | |
printf("min_mmr = %d\n", min_mmr); | |
printf("Expected prices:\n"); | |
for (i = 0; i < 32; ++i) { | |
int32_t expected = (int) (s*(players[i].mmr - min_mmr)); | |
printf("%s (%d) expected $%d actual $%d delta $%d\n", | |
players[i].name, players[i].mmr, expected, players[i].cost, players[i].cost - expected); | |
} | |
} | |
/** | |
* "version 2" calculation, assume that captain mmr converts to $ and that captain mmr $ + $ available | |
* for the team is a constant over all teams. | |
* These differ structurally from the method described in the medium.com post due to the use of the | |
* captain min mmr as an intermediate offset. Because the calculations are linear, that becomes | |
* part of the final offset anyway and matches exactly, but the code was developed this way. | |
* The analysis is easier to understand without formulating it in this way. | |
*/ | |
void v2(void) { | |
int i, j; | |
int count = 0; | |
int min_mmr = 5000; | |
int offset = 0; | |
float r = 0.0f; | |
int team_value[8] = {0}; | |
printf("v2:\n"); | |
for (i = 0; i < 8; ++i) { | |
// Record min captain mmr | |
if (teams[i]->cap_mmr < min_mmr) | |
min_mmr = teams[i]->cap_mmr; | |
// Get r value for a particular pairing of teams | |
for (j = i+1; j < 8; ++j) { | |
int cashdiff = teams[j]->cash - teams[i]->cash; | |
int mmrdiff = teams[i]->cap_mmr - teams[j]->cap_mmr; | |
if (mmrdiff != 0) { | |
r += ((float) cashdiff)/mmrdiff; | |
count += 1; | |
} | |
} | |
} | |
r = r / count; | |
printf("r = %f\n", r); | |
printf("min_mmr = %d\n", min_mmr); | |
printf("Team scores:\n"); | |
for (i = 0; i < 8; ++i) { | |
int add = (int) ((teams[i]->cap_mmr - min_mmr) * r); | |
printf("%s is %d + %d = %d\n", | |
teams[i]->captain, teams[i]->cash, add, teams[i]->cash + add); | |
} | |
// Find price offset so that sum(r*mmr - offset) = total cash | |
for (i = 0; i < 32; ++i) { | |
offset += (int) (r*(players[i].mmr - min_mmr)); | |
} | |
for (i = 0; i < 8; ++i) { | |
offset -= teams[i]->cash; | |
} | |
printf("Excess cash: %d\n", offset); | |
offset = offset / 32; | |
printf("Offset per person: %d\n", offset); | |
printf("Expected prices:\n"); | |
for (i = 0; i < 32; ++i) { | |
// With how offset is used, min_mmr is necessary here. Can eliminate both and roll min_mmr | |
// into offset directly, but the results should be the same (apart from a potential rounding) | |
int32_t expected = (int) (r*(players[i].mmr - min_mmr)) - offset; | |
int team_id = get_team_id(players[i].team); | |
team_value[team_id] += expected; | |
printf("%s (%d) expected $%d actual $%d delta $%d\n", | |
players[i].name, players[i].mmr, expected, players[i].cost, players[i].cost - expected); | |
} | |
printf("Team summaries: (total score = player score + captain score)\n"); | |
for (i = 0; i < 8; ++i) { | |
int add = (int) ((teams[i]->cap_mmr - min_mmr) * r); | |
printf("%s total expected value: %d = %d + %d\n", teams[i]->captain, team_value[i] + add, team_value[i], add); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment