API

App

Manages job requests from user through the command line.

class pgnhelper.app.PgnHelper(job: str, inpgnfn: Optional[str] = None, outpgnfn: Optional[str] = None, inecopgnfn: Optional[str] = None, sort_tag: str = 'eco', sort_direction: str = 'lowtohigh', output: Optional[str] = None, winpoint: float = 1.0, drawpoint: float = 0.5, encoding: str = 'utf-8', armageddonfile: Optional[str] = None, winpointarm: float = 1.0, losspointarm: float = 0.0, showmaxscore: bool = False, round: int = 20)[source]

Manages user options to execute the job.

job

The kind of job to be done, sort, addeco and roundrobin.

inpgnfn

The input pgn file or path and filename.

outpgnfn

The output pgn file or path and filename.

inecopgnfn

The eco.pgn that will be used in addeco job.

sort_tag

Used in sorting games.

sort_direction

The output sorting ordering, lowtohigh or hightolow.

start()[source]

Run the type of job to be done.

It will sort the games, add eco, opening and variation names to the games or generate a round-robin result table.

Add ECO

Add eco, opening and variation names to the input pgn file.

The eco codes, opening and variations names are coming from the file eco.pgn that you have to supply to pgnhelper for this to work.

eco.pgn file sources:

Example:

>>> import pgnhelper.eco
>>> pgnhelper.eco.add_eco("./pgn/candidates_zurich_1953.pgn", "eco_cz.pgn", "./eco/eco.pgn")

Example output from eco_cz.pgn:

[Event "ct"]
[Site "Zurich"]
[Date "1953.??.??"]
[Round "01"]
[White "Szabo L"]
[Black "Geller E"]
[Result "0-1"]
[ECO "A15"]
[ECOT "E02"]
[Opening "English"]
[OpeningT "Catalan"]
[Variation "Anglo-Indian"]
[VariationT "open, 5.Qa4"]

1. c4 Nf6 2. g3 e6 3. Bg2 d5 4. d4 dxc4 5. Qa4+ Nbd7 ...

Note there are ECOT, OpeningT, and VariationT, these are new tags where T refers to Transposition. The ECO A15 is the ECO based on the first 2 moves and ECOT E02 is the ECO after 12 moves.

pgnhelper.eco.add_eco(inpgnfn: str, outpgnfn: str, inecopgnfn: str, ply: int = 4, maxply: int = 24)[source]

Add eco, opening and variation names to the pgn file.

Parameters
  • inpgnfn – The input pgn file.

  • outpgnfn – The output file.

  • inecopgnfn – The eco.pgn file.

  • ply – The game ply to start classifying the opening.

  • maxply – The max game ply to stop classifying the opening.

pgnhelper.eco.create_eco_db(inecopgnfn: str)[source]

Creats a dictionary of eco data.

Parameters

inecopgnfn – The eco.pgn file to be converted to a dictionary.

pgnhelper.eco.get_opening_stats(fn: str, is_arm: bool = False)[source]

Generates a dataframe of opening stats.

Opening, counts Sicilian, 4 …….., …

Parameters

fn – The pgn filename.

Returns

A dataframe of Opening and count

Sort games

Sort games by game tags.

class pgnhelper.sort.Game[source]

Manages sorting of games.

add_line(line: str)[source]

Saves lines read from each game.

Parameters

line – A line read from the game.

pgnhelper.sort.read_games(inpgnfn: str, encoding: str = 'utf-8') List[Game][source]

Read games from input pgn file.

Parameters
  • inpgnfn – The input pgn file.

  • encoding – Encoding used in reading a file. If you encounter a UnicodeDecodeError we can use ISO-8859-1 instead of utf-8.

Returns

A list of Game objects.

pgnhelper.sort.save_games(games: List[Game], outpgnfn: str)[source]

Save the games to output file.

Parameters
  • games – A list of games.

  • outpgnfn – The output file.

pgnhelper.sort.sort_games(inpgnfn: str, outpgnfn: str, sort_tag: str, sort_direction: str, encoding: str = 'utf-8') None[source]

Sort based on criteria and save the games.

Read the input pgn file, sort it and save the sorted games in output file. The input file is not changed.

Parameters
  • inpgnfn – The input pgn file.

  • outpgnfn – The output pgn file.

  • sort_tag – The sorting criteria, can be event, site, date, round, white, black and eco.

  • sort_direction – Direction can be hightolow or lowtohigh.

  • encoding – Encoding used in reading the input file.

Roundrobin

Generates a round-robin result table.

It reads the input pgn file and generates a dataframe of round-robin table. It also add columns for tie-break scores for tied players.

Typical tie-break system that can be applied to a round-robin tournament according to FIDE.

13.16.2. Individual Round-Robin Tournaments:
  • Direct encounter

  • The greater number of wins, including forfeits

  • Sonneborn-Berger

  • Koya System (to be implemented in pgnhelper)

https://handbook.fide.com/files/handbook/C02Standards.pdf

class pgnhelper.roundrobin.RoundRobin(infn: str, infnarm: Optional[str] = None, winpoint: float = 1.0, drawpoint: float = 0.5, winpointarm: float = 1.0, losspointarm: float = 0.0, showmaxscore: bool = False)[source]

Manages round-robin result table generation.

infn

The input pgn file.

infnarm

The input pgn file with armageddon games.

winpoint

The point for the winner.

drawpoint

The point when player draws.

winpointarm

The point for the winner in armageddon game.

losspointarm

The point for the loser in armageddon game.

games_per_encounter() int[source]

Counts the number of games per encounter excluding armageddon.

Returns

The number of games per encounter.

player_ranking() DataFrame[source]

Generates a dataframe of player ranking.

Returns

A pandas dataframe of players ranking.

standing() DataFrame[source]

Returns a dataframe of player standing.

The standing is sorted by score, with tie-breaks DE, Wins and SB.

table() DataFrame[source]

Generates a round-robin result table.

The table is sorted by DE or Direct Encounter, Number of Wins and SB (sonneborn-Berger)

Returns

A pandas dataframe of round-robin table.

Swiss

Generates a swiss result table.

It reads the input pgn file and generates a dataframe of swiss table. It also add columns for tie-break scores for tied players.

Typical tie-break system that can be applied to a swiss tournament according to FIDE.

13.16.4. Individual Swiss Tournaments where not all the ratings are consistent:

  • Buchholz Cut 1

  • Buchholz

  • Sonneborn-Berger

  • Cumulative system - Sum of Progressive Scores

  • Direct encounter

  • The greater number of wins including forfeits

  • The greater number of wins with Black pieces

13.16.5. Individual Swiss Tournaments where all the ratings are consistent:

  • Buchholz Cut 1

  • Buchholz

  • Direct encounter

  • AROC

  • The greater number of wins including forfeits

  • The greater number of wins with Black pieces

  • The greater number of games with Black (unplayed games shall be counted as played with White)

  • Sonneborn-Berger

https://handbook.fide.com/files/handbook/C02Standards.pdf

Other reference: FIDE Chess.com Grand Swiss 2021

4. 8. 3. Tie-breaks If two (2) or more players score the same points, the tie is to be decided by the following criteria, in order of priority:

  1. Buchholz Cut 1;

  2. Buchholz;

  3. Sonneborn-Berger;

  4. Direct encounter between the players in tie;

  5. Drawing of lots.

All tie-breaks are calculated as described in C.02.13 of the FIDE Handbook.

Tie-break supported by this library:

TB1 = Buchholz Cut 1 TB2 = Buchholz TB3 = Sonneborn-Berger TB4 = Direct Encounter TB5 = Number of wins TB6 = Number of wins as black

class pgnhelper.swiss.Swiss(infn: str, round: int = 20)[source]

Manages swiss result table generation.

infn

The input pgn file.

infnarm

The input pgn file with armageddon games.

winpoint

The point for the winner.

drawpoint

The point when player draws.

winpointarm

The point for the winner in armageddon game.

losspointarm

The point for the loser in armageddon game.

round

The number of rounds.

convert_score(score: float)[source]

Convert 1.0 to 1, 0.0 to 0 and 0.5 to =

get_opp_info(opp_data: List, df_final: DataFrame, dfr: DataFrame, p: str) Tuple[List, bool][source]

Creates result data to build swiss table.

player_ranking() DataFrame[source]

Generates a dataframe of player ranking.

Returns

A pandas dataframe of players ranking.

table() DataFrame[source]

Generates a swiss result table.

The table is sorted by [score, buchholz cut 1, buchholz, sonneborn-berger, direct encounter].

Returns

A pandas dataframe of swiss table.

Record

Manages conversion of pgn file into a pandas dataframe.

Read the games in the pgn file. Each game will be converted to a row with header:

Round, White, Black, WElo, BElo, Result, Wpt, Bpt, Arm, Eco, Opening, WRChg, BRChg

Example:

PS F:\Github\pgnhelper> python
>>> import pgnhelper
>>> df, players, rating = pgnhelper.record.get_pgn_data("./pgn/wchcand22.pgn")
>>> df
Round                White                Black  WElo  ...  Eco                        Opening     WRChg     BRChg
  1.1  Duda, Jan-Krzysztof     Rapport, Richard  2750  ...  B44               Sicilian defence  0.201367 -0.201367
  1.2          Ding, Liren  Nepomniachtchi, Ian  2806  ...  A20                English opening -5.573116  5.573116
  1.3     Caruana, Fabiano     Nakamura, Hikaru  2783  ...  C65                      Ruy Lopez  4.669486 -4.669486
pgnhelper.record.get_pgn_data(fn, is_arm: bool = False, k: int = 10) Tuple[DataFrame, List, bool][source]

Converts games to dataframe.

Parameters
  • fn – The pgn filename.

  • is_arm – If pgn file has armageddon games.

  • k – The rating change k factor.

Returns

df, players, is_rating

Tiebreak

Generates tie-break points on tied players.

Tie-breaks supported:
  • Direct Encounter

  • Number of wins

  • Sonneborn-Berger

  • Koya system

pgnhelper.tiebreak.direct_encounter(result_df: DataFrame, ranking_df: DataFrame, winpoint: float = 1.0, drawpoint: float = 0.5, winpointarm: float = 1.5, losspointarm: float = 1.0, label: str = 'DE') DataFrame[source]

Creates a dataframe with DE column or direct encounter.

Requirement:

It is only applied when tied players have played each other. In round-robin format this can be applied automatically. But for swiss format, the tied players have to be checked.

pgnhelper.tiebreak.koya_system(result_df: DataFrame, ranking_df: DataFrame, winpoint: float = 1.0, drawpoint: float = 0.5) DataFrame[source]

Creates a dataframe with Koya column for Koya system score.

Koya system - the number of points achieved against all opponents who have achieved 50 % or more.

11.5.4.3, https://handbook.fide.com/files/handbook/C02Standards.pdf

Parameters
  • result_df – A dataframe of [Round, White, Black, Result …].

  • ranking_df – A dataframe of standing, [Name, Games, Score].

Returns

A ranking dataframe with Koya column.

pgnhelper.tiebreak.num_wins(result_df: DataFrame, ranking_df: DataFrame, label: str = 'Wins', bwins: bool = False) DataFrame[source]

Creates a dataframe with Win column.

If a game has an armageddon tie-break, we will only count the number of wins based from the normal game only.

Parameters
  • result_df – The result dataframe.

  • ranking_df – Ranking of players based on score.

  • label – The label or header of the resulting dataframe.

  • bwins – If true then only count wins by black. If not count all wins.

Returns

A dataframe of ranking with Wins column for tie-break.

pgnhelper.tiebreak.sonneborn_berger(result_df: DataFrame, ranking_df: DataFrame, gpe: int = 1, winpoint: float = 1.0, drawpoint: float = 0.5, label: str = 'SB') DataFrame[source]

Creates a dataframe with SB column for Sonneborn-Berger score.

Armageddon games currently are excluded in the calculation.

Parameters
  • result_df – A dataframe of [Round, White, Black, Result].

  • ranking_df – A dataframe of standing, [Name, Games, Score].

  • gpe – games per encounter

Returns

A dataframe of round-robin result table.

pgnhelper.tiebreak.tb_buchholz(record_df: DataFrame, rank_df: DataFrame, cut: int = 0, label: str = 'TB1') DataFrame[source]

Calculates buchholz score or sum of opponents score.

This tie-break system is only applied for a tournament with swiss format.

Parameters
  • record_df – A dataframe of tournament games records.

  • rank_df – A dataframe with player ranking, initially at [‘Name, Games, Score]. Later [‘Name, Games, Score, Buchholz, … tie-break system]

  • cut – Cut the player opponent score, if cut is 0 the default then no one will be cut, this is the normal buchholz. If this is 1 then the lowest score will be cut. If this is 2 then the last two lowest scores will be cut. If value is -1 this is median or cut the highest and lowest. If value is -2 then cut the 2 highest and 2 lowest.

Returns

A dataframe of name and buchholz score.

Elo

pgnhelper.elo.add_rating_change(df: DataFrame, is_rating: bool, k: int = 10) DataFrame[source]

Adds rating change columns to existing df.

Parameters
  • df – A dataframe of players match records.

  • is_rating – True if players have rating.

  • k – The k factor.

Returns

A dataframe of game records with elo rating change columns. [Round, White, Black, WElo, BElo, Result, Wpt, Bpt, Arm, WRChg, BRChg]

pgnhelper.elo.expected_score(rating_a: int, rating_b: int) float[source]

Calculates the expected score of player_a against player_b.

Parameters
  • rating_a – Rating of player_a

  • rating_b – Rating of player_b

Returns

expected score of player_a

Example:

>>> import pgnhelper.elo
>>> white_elo = 2600
>>> black_elo = 2500
>>> score = pgnhelper.elo.expected_score(white_elo, black_elo)
>>> score
0.6400649998028851
pgnhelper.elo.get_rating(df: DataFrame, p: str) Union[int, str][source]

Gets the rating of player p.

Parameters
  • df – A dataframe of players match records.

  • p – A player name.

Returns

rating of player p

pgnhelper.elo.get_rating_change(df: DataFrame, p: str, k: int = 10) float[source]

Gets the rating change of player p.

The given df has a rating change column for each side. This rating change column was calculated using a k factor with value 10. The k parameter if not 10 will be used to recalculate the rating change for the given player.

Armageddon games are not included in the returned rating change value.

Parameters
  • df – A dataframe of players match records.

  • p – A player named p.

  • k – The rating change k factor.

Returns

rating change

Eample 1, get the rating change of a player in the PGN file:

>>> import pgnhelper.record
>>> import pgnhelper.elo
>>> df, players, is_rating = pgnhelper.record.get_pgn_data("./pgn/superbet_classic_2022_bucharest.pgn")
>>> players
['Firouzja, Alireza', 'Aronian, Levon', 'So, Wesley', 'Nepomniachtchi, Ian', 'Caruana, Fabiano', 'Vachier-Lagrave, Maxime', 'Deac, Bogdan-Daniel', 'Mamedyarov, Shakhriyar', 'Dominguez Perez, Leinier', 'Rapport, Richard']
>>> rc_levon = pgnhelper.elo.get_rating_change(df, "Aronian, Levon", k=10)
>>> rc_levon
9.496967974633389

Eample 2, get the rating change of black player:

>>> import pgnhelper.elo
>>> white_rating = 2700
>>> black_rating = 2600
>>> black_point = 1
>>> white_point = 0
>>> expected_score = pgnhelper.elo.expected_score(black_rating, white_rating)
>>> k = 10
>>> rating_change = k * (black_point - expected_score)
>>> rating_change
6.400649998028851

Utility

Helps build the round-robin result table.

pgnhelper.utility.df_to_html(df: DataFrame, fn: str) None[source]

Converts pandas dataframe to basic html table.

Read the df and write html in the fn.

Parameters
  • df – Pandas dataframe.

  • fn – the output file, can be csv, txt or html.

Returns

Nothing

pgnhelper.utility.get_encounter_score(df: DataFrame, p: str, op: str, winpoint: float = 1.0, drawpoint: float = 0.5, winpointarm: float = 1.0, losspointarm: float = 0.0) List[float][source]

Calculates the scores between the player p and op.

Parameters
  • 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>].

pgnhelper.utility.save(df: DataFrame, fn: str) None[source]

Save the dataframe.

The output can be a csv, txt and html. :param df: A pandas dataframe. :param fn: The output filename.