Skip to content

Instantly share code, notes, and snippets.

@gmalysa
Created May 26, 2021 20:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gmalysa/902614b497e281d5c21d7a485344f4db to your computer and use it in GitHub Desktop.
Save gmalysa/902614b497e281d5c21d7a485344f4db to your computer and use it in GitHub Desktop.
FHDL Player and Captain Analysis
#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