Source code for pgnhelper.utility

"""Helps build the round-robin result table.
"""


from typing import List
import pandas as pd
from pathlib import Path


[docs]def get_encounter_score(df: pd.DataFrame, p: str, op: str, winpoint: float = 1.0, drawpoint: float = 0.5, winpointarm: float = 1.0, losspointarm: float = 0.0) -> List[float]: """Calculates the scores between the player p and op. Args: df: A pandas dataframe containing players match results. p: A player name. op: Opponent of player p. winpoint: The point when player wins. drawpoint: The point when player draws. winpointarm: The point when player wins in armageddon game. losspointarm: The point when player loses in armageddon game. Returns: A list of score for p and op, score[<p score>, <op score>]. """ is_arm = True if 1 in df.Arm.unique() else False score = [0, 0] dfw = df[(df.White == p) & (df.Black == op)] dfb = df[(df.Black == p) & (df.White == op)] # If a game is normal or no tie-break points involved. if not is_arm: # Update the score when p is white. for i in range(len(dfw)): v = dfw.iloc[i]['Result'] if v == '1-0': score[0] += 1.0 * winpoint score[1] += 0.0 elif v == '0-1': score[0] += 0.0 score[1] += 1.0 * winpoint elif v == '1/2-1/2': score[0] += drawpoint score[1] += drawpoint # Update the score when p is black. for i in range(len(dfb)): v = dfb.iloc[i]['Result'] if v == '1-0': score[0] += 0.0 score[1] += 1.0 * winpoint elif v == '0-1': score[0] += 1.0 * winpoint score[1] += 0.0 elif v == '1/2-1/2': score[0] += drawpoint score[1] += drawpoint # Else if a game has armageddon tie-break. else: # A. In norway chess, in normal game, the winner will get 3.0 points, # the loser will get 0.0 point. # 1. Get the score from normal game with 1-0 and 0-1 result where # the first player is white. We don't include the draw results # because we will use the armageddon tie-break system. dfw_normal = df[ (df.White == p) & (df.Black == op) & (df.Arm == 0) & ((df.Result == '1-0') | (df.Result == '0-1'))] for i in range(len(dfw_normal)): r = dfw_normal.iloc[i]['Result'] if r == '1-0': score[0] += 1.0 * winpoint score[1] += 0.0 elif r == '0-1': score[0] += 0.0 score[1] += 1.0 * winpoint # 2. Get the score from normal game with 1-0 and 0-1 result where # the first player is black. We don't include the draw results # because we will use the armageddon tie-break system. dfb_normal = df[ (df.Black == p) & (df.White == op) & (df.Arm == 0) & ((df.Result == '1-0') | (df.Result == '0-1'))] for i in range(len(dfb_normal)): r = dfb_normal.iloc[i]['Result'] if r == '0-1': score[0] += 1.0 * winpoint score[1] += 0.0 elif r == '1-0': score[0] += 0.0 score[1] += 1.0 * winpoint # B. In norway chess, in armageddon game, the winner will get # 1.5 points, the loser will get 1.0 point. The armageddon game # is done if the normal game resulted in a draw. The point in a # normal game that resulted in a draw is discarded. # 1. Get the score from armageddon game where the first player is white. dfw_arm = df[(df.White == p) & (df.Black == op) & (df.Arm == 1)] for i in range(len(dfw_arm)): r = dfw_arm.iloc[i]['Result'] if r == '1-0': score[0] += 1.0 * winpointarm score[1] += 1.0 * losspointarm elif r == '0-1': score[0] += 1.0 * losspointarm score[1] += 1.0 * winpointarm elif r == '1/2-1/2': score[0] += 1.0 * losspointarm score[1] += 1.0 * winpointarm # black wins # 2. Get the score from armageddon game where the first player is black. dfb_arm = df[(df.Black == p) & (df.White == op) & (df.Arm == 1)] for i in range(len(dfb_arm)): r = dfb_arm.iloc[i]['Result'] if r == '0-1': score[0] += 1.0 * winpointarm score[1] += 1.0 * losspointarm elif r == '1-0': score[0] += 1.0 * losspointarm score[1] += 1.0 * winpointarm elif r == '1/2-1/2': score[0] += 1.0 * winpointarm # black wins score[1] += 1.0 * losspointarm return score
[docs]def df_to_html(df: pd.DataFrame, fn: str) -> None: """Converts pandas dataframe to basic html table. Read the df and write html in the fn. Args: df: Pandas dataframe. fn: the output file, can be csv, txt or html. Returns: Nothing """ dict_data = [df.to_dict(), df.to_dict('index')] htmldf = '<!DOCTYPE html>\n' htmldf += '<html lang="en">\n' htmldf += ' <head>\n' htmldf += ' <meta charset="utf-8">\n' htmldf += ' <meta name="viewport" content="width=device-width, initial-scale=1">\n' htmldf += ' <title>PGN Helper</title>\n' # Define style. htmldf += ' <style>\n' htmldf += ' body {margin-top: 25px;}\n' htmldf += ' table, th, td {\n' htmldf += ' border: 1px solid black;\n' htmldf += ' border-collapse: collapse;\n' htmldf += ' text-align: center;\n' htmldf += ' }\n\n' htmldf += ' th, td {\n' htmldf += ' padding: 5px;\n' htmldf += ' }\n\n' htmldf += ' tr:nth-child(even) {\n' htmldf += ' background-color: #D5DBDB;\n' htmldf += ' }\n' htmldf += ' tr:hover {background-color: #EBDEF0;}\n\n' htmldf += ' table.center {\n' htmldf += ' margin-left: auto;\n' htmldf += ' margin-right: auto;\n' htmldf += ' }\n' htmldf += ' </style>\n' htmldf += ' </head>\n\n' htmldf += ' <body>\n' # Define table. htmldf += ' <div style="overflow-x: auto;">\n' # responsive htmldf += ' <table class="center">\n' # Define header row. htmldf += '<tr>\n' for key in dict_data[0].keys(): htmldf += '<th>' + str(key) + '</th>\n' htmldf += '</tr>\n' # Define data. for key in dict_data[1].keys(): htmldf += '<tr>\n' for subkey in dict_data[1][key]: htmldf += '<td>' + str(dict_data[1][key][subkey]) + '</td>\n' htmldf += '</tr>\n' htmldf += ' </table>\n' htmldf += ' </div>\n' htmldf += ' </body>\n' htmldf += '</html>\n' # Write html. with open(fn, 'w', encoding='utf-8') as f: f.write(htmldf)
[docs]def save(df: pd.DataFrame, fn: str) -> None: """Save the dataframe. The output can be a csv, txt and html. Args: df: A pandas dataframe. fn: The output filename. """ ext = Path(fn).suffix if ext == '.html': df_to_html(df, fn) elif ext == '.csv': df.to_csv(fn, index=False) else: df.to_string(fn, index=False)