CoolFace
Apppublic

guyar/terra_faction_bot

sourceHugging Faceupdated 3y agoView on Hugging Face
0likes
app.py304 linesDownload Raw Back to root
1import gradio as gr2import random3import matplotlib4import matplotlib.pyplot as plt5import pandas as pd6import shap7import lightgbm as lgb8import yaml9import numpy as np10import os11 12from visualisations import terravisualisation as tmvis13 14matplotlib.use("Agg")15 16bontiledict = {'SPD + 2C':'BON1', 17               'cult + 4C':'BON2', 18               '+6C':'BON3', 19               '+3pw 1 ship':'BON4', 20               '+1W + 3PW':'BON5', 21               'pass-vp:SA/SH*4 + 2W':'BON6', 22               'pass-vp:TP*2 + 1W':'BON7', 23               '+1P':'BON8', 24               'pass-vp:D*1 + 2C':'BON9', 25               'pass-vp: ship*3 + 3pw':'BON10' 26                }27 28bontiledict_reverse = {'BON1': 'SPD + 2C',29               'BON2': 'cult + 4C',30               'BON3': '+6C',31               'BON4': '+3pw 1 ship',32               'BON5': '+1W + 3PW',33               'BON6': 'pass-vp:SA/SH*4 + 2W',34               'BON7': 'pass-vp:TP*2 + 1W',35               'BON8': '+1P',36               'BON9': 'pass-vp:D*1 + 2C',37               'BON10': 'pass-vp: ship*3 + 3pw'      38                }39 40round_tiles_dict = {'SPADE >> 2':'SCORE1',41                    'TOWN >> 5':'SCORE2',42                    'D >> 2':'SCORE3',43                    'SA/SH >> 5':'SCORE4',44                    'D >> 2':'SCORE5',45                    'TP >> 3':'SCORE6',46                    'SA/SH >> 5':'SCORE7',47                    'TP >> 3':'SCORE8',48                    'TE >> 4':'SCORE9'}49 50round_tiles_dict_reverse = {'SCORE1': 'SPADE >> 2',  51                    'SCORE2': 'TOWN >> 5',  52                    'SCORE3': 'D >> 2',  53                    'SCORE4': 'SA/SH >> 5',  54                    'SCORE5': 'D >> 2',  55                    'SCORE6': 'TP >> 3',  56                    'SCORE7': 'SA/SH >> 5',  57                    'SCORE8': 'TP >> 3',  58                    'SCORE9': 'TE >> 4'}59 60 61round_tiles = list(round_tiles_dict.keys())62round6_tiles = round_tiles.copy()63round6_tiles.remove('SPADE >> 2')64bontiles = list(bontiledict.keys())65 66factions = ['Witches', 'Auren', 'Giants', 'Chaos Magicians', 'Darklings', 'Alchemists',67            'Swarmlings', 'Mermaids', 'Fakirs', 'Nomads', 'Engineers', 'Dwarves', 'Halflings', 'Cultists']68 69players = ['2players', '3players', '4players', '5players']70 71maps = ['map1', 'map2', 'map3']72 73faction_cols = ['Yellow', 'Red', 'Grey', 'Black', 'Blue', 'Green', 'Brown']74 75with open('params.yaml', 'r') as fd:76    params = yaml.safe_load(fd)77 78vpdfdir = params['prepare']['vp-data-dir']79featdfdir = params['prepare']['feature-data-dir']80pickledir = params['prepare-step2']['pickle-dir']81 82feature_columns = ['x0_SCORE1', 'x0_SCORE2', 'x0_SCORE3', 'x0_SCORE4', 'x0_SCORE5',83       'x0_SCORE6', 'x0_SCORE7', 'x0_SCORE8', 'x0_SCORE9', 'x1_SCORE1',84       'x1_SCORE2', 'x1_SCORE3', 'x1_SCORE4', 'x1_SCORE5', 'x1_SCORE6',85       'x1_SCORE7', 'x1_SCORE8', 'x1_SCORE9', 'x2_SCORE1', 'x2_SCORE2',86       'x2_SCORE3', 'x2_SCORE4', 'x2_SCORE5', 'x2_SCORE6', 'x2_SCORE7',87       'x2_SCORE8', 'x2_SCORE9', 'x3_SCORE1', 'x3_SCORE2', 'x3_SCORE3',88       'x3_SCORE4', 'x3_SCORE5', 'x3_SCORE6', 'x3_SCORE7', 'x3_SCORE8',89       'x3_SCORE9', 'x4_SCORE1', 'x4_SCORE2', 'x4_SCORE3', 'x4_SCORE4',90       'x4_SCORE5', 'x4_SCORE6', 'x4_SCORE7', 'x4_SCORE8', 'x4_SCORE9',91       'x5_SCORE2', 'x5_SCORE3', 'x5_SCORE4', 'x5_SCORE5', 'x5_SCORE6',92       'x5_SCORE7', 'x5_SCORE8', 'x5_SCORE9', 'BON1', 'BON2', 'BON3', 'BON4',93       'BON5', 'BON6', 'BON7', 'BON8', 'BON9', 'BON10', 'no_players', 'red',94       'blue', 'green', 'black', 'grey', 'yellow', 'brown', 'x0_map1',95       'x0_map2', 'x0_map3']96 97 98 99def args_to_features(*args):100    # round1, round2, round3, round4, round5, round6, faction, map, playerschosen, bon_tiles, fac_cols = args101    Xdata = pd.DataFrame(data=np.zeros((1, len(feature_columns))), columns=feature_columns)102 103    for arg_no, user_input in enumerate(args):104        if  arg_no in range(6):  # if it's a round105            # map back to col name106            feat_label_name = f'x{arg_no}_{round_tiles_dict[user_input]}'107            Xdata[feat_label_name].iloc[0] = 1108        elif arg_no == 6:109            faction = user_input110            if faction == 'Chaos Magicians':111                faction = 'chaosmagicians'112        elif arg_no == 7: # map 113            feat_label_name = f'x0_{user_input}'114            Xdata[feat_label_name].iloc[0] = 1115        elif arg_no == 8: # playerschosen116            Xdata['no_players'].iloc[0] = int(user_input[0])117        elif arg_no == 9: # bon_tiles118            for bon_tile in user_input:119                Xdata[bontiledict[bon_tile]].iloc[0] = 1120        elif arg_no == 9: # fac_cols121            for fac_col in user_input:122                Xdata[fac_col.lower()].iloc[0] = 1123 124    return Xdata, faction125 126def display_map(faction, map):127    map_fig = plt.figure(tight_layout=True)128 129    x, y = tmvis.display_map(faction, plot=False)130    a = map_fig.add_subplot(111)131    a.hexbin(x, y, gridsize=(19, 9), cmap='magma')132    a.axis('off')133    return map_fig134 135 136def predict(*args):137    Xdata, faction = args_to_features(*args)138 139    modelfile = f'{os.getcwd()}/data/faction-picker-bot/models/{faction.lower()}_model.txt'140    bst = lgb.Booster(model_file=modelfile)141 142    return f'Final score: {round(bst.predict(Xdata)[0])}'143 144 145def interpret(*args):146    Xdata, faction = args_to_features(*args)147    modelfile = f'{os.getcwd()}/data/faction-picker-bot/models/{faction.lower()}_model.txt'148    bst = lgb.Booster(model_file=modelfile)149    bst.params["objective"] = "regression"150    explainer = shap.Explainer(bst)151 152    copycols = []153    for ii, column in enumerate(Xdata.columns):154        if column[-6:] in round_tiles_dict_reverse.keys():155            copycols.append(column[:3] + round_tiles_dict_reverse[column[-6:]])156        elif column in bontiledict_reverse.keys():157            copycols.append(bontiledict_reverse[column])158        else:159            copycols.append(column)160        161    Xdata.columns = copycols162 163    shap_values = explainer(Xdata)164    fig_m = plt.figure(tight_layout=True, facecolor=(0.125,0.172,0.203))165    ax = plt.gca()166    ax.set_facecolor((0.125,0.172,0.203))167    matplotlib.rcParams['axes.labelcolor'] = 'w'168    shap.plots.waterfall(shap_values[0])169    # shap.initjs()170    # shap.plots.force(shap_values[0])171    return fig_m172 173 174 175with gr.Blocks() as demo:176    gr.Markdown("""177    **Predict final faction score given the initial board setup ๐Ÿ’ฐ**:  This model uses an lightgbm regression to make prediction. 178    The [source code for this work is here](https://github.com/guyreading/terrabot/blob/main/app.py).179    """)180    with gr.Row():181        with gr.Column():182            faction = gr.Dropdown(183                label="Faction",184                choices=factions,185                value=lambda: random.choice(factions),186            )187 188            round1_tile = gr.Dropdown(189                label="Round 1 tile",190                choices=round_tiles,191                value=lambda: random.choice(round_tiles),192            )193 194            round2_tile = gr.Dropdown(195                label="Round 2 tile",196                choices=round_tiles,197                value=lambda: random.choice(round_tiles),198            )199 200            round3_tile = gr.Dropdown(201                label="Round 3 tile",202                choices=round_tiles,203                value=lambda: random.choice(round_tiles),204            )205 206            round4_tile = gr.Dropdown(207                label="Round 4 tile",208                choices=round_tiles,209                value=lambda: random.choice(round_tiles),210            )211 212            round5_tile = gr.Dropdown(213                label="Round 5 tile",214                choices=round_tiles,215                value=lambda: random.choice(round_tiles),216            )217 218            round6_tile = gr.Dropdown(219                label="Round 6 tile",220                choices=round6_tiles,221                value=lambda: random.choice(round6_tiles),222            )223 224            bon_tiles_gr = gr.CheckboxGroup(label='Bonus tiles present', choices=list(bontiledict.keys()))225        226            map = gr.Dropdown(227                label="Map",228                choices=maps,229                value=lambda: random.choice(maps),230            )231 232            playerschosen = gr.Dropdown(233                label="No. Of Players",234                choices=players,235                value=lambda: random.choice(players),236            )237 238            fac_cols_gr = gr.CheckboxGroup(label='Other faction colours present', choices=faction_cols)239 240 241        with gr.Column():242            map_plot = gr.Plot(label='Distance from home terrain: darker is further')243 244            with gr.Row():245                predict_btn = gr.Button(value="Predict")246                interpret_btn = gr.Button(value="Explain")247 248            label = gr.Label(label=f'Prediction of final VP for faction:')249            plot = gr.Plot(label=f'Breakdown of prediction for faction:')250 251    predict_btn.click(252        predict,253        inputs=[254            round1_tile,255            round2_tile,256            round3_tile,257            round4_tile,258            round5_tile,259            round6_tile,260            faction,261            map,262            playerschosen,263            bon_tiles_gr,264            fac_cols_gr265        ],266        outputs=[label],267    )268    interpret_btn.click(269        interpret,270        inputs=[271            round1_tile,272            round2_tile,273            round3_tile,274            round4_tile,275            round5_tile,276            round6_tile,277            faction,278            map,279            playerschosen,280            bon_tiles_gr,281            fac_cols_gr282        ],283        outputs=[plot],284    )285 286    faction.change(287        display_map,288        inputs=[289            faction,290            map,291        ],292        outputs=[map_plot],293    )294 295    map.change(296        display_map,297        inputs=[298            faction,299            map,300        ],301        outputs=[map_plot],302    )303 304demo.launch()