Using Python to estimate a player's chances in a round robin

Using Python to estimate a player's chances in a round robin

Avatar of RobKing
| 6

Being a chess junky who also does analytics for a living, I find myself asking funny questions about the game. One of these situations had arisen recently as I was following the results of a local chess club's Club Championship. After 6 rounds at the Wachusett Chess Club in Fitchburg, MA, one of the lowest seeds was tied for first going into the last round. Naturally, I wondered "what are the odds of him actually winning the tournament?" Luckily, we have ways of figuring this out!

To do this, we want to use a simulation. As part of this simulation, we will create all of the different pairings in a tournament, use the players' ratings to sample a result for each game, and determine the standings. We will then run this simulation 100,000 times and then look at how often our underdog finishes in at least shared first place. Sound easy enough?

Let's start with the libraries we will use. Note that I am running this code using the Anaconda Distribution (Version 4.1.1) of Python (2.7) in a Jupyter Notebook. This code should transfer to Python 3 seamlessly. 

null

We will be using numpy's exp and log when calculating our win and draw rates, itertools combinations to generate all of our round robin pairings, rankdata from scipy.stats to determine standings, and random_integers to generate random results. Finally, pandas is used for some data manipulation at the end.

Before defining anything to do with the simulation, we want to define some functions that accomplish some technical tasks for us. The core part of the simulation is being able to use players' ratings to simulate a result. Using the definition of the USCF Elo Rating system, the expected score for Player A against Player B is: null

However, this is only the expected score and NOT the probability of winning. To get to that, we need a method to estimate the probability of drawing. Using research conducted by Kirill Kyrukov on Chess Engine draw rates, we can estimate the chances for a draw based on rating difference.

null

NOTE: I am an analytics professional and self-proclaimed hacker. I am NOT a software developer and my code is probably cringe-worthy to that population. I apologize in advance happy.png

From this estimated probability, we can estimate the probability of winning by taking the expected score and subtracting half of the draw rate. Once we have this, we can create a function that can help us in our simulation. Instead of returning these probabilities, I want my function to return a Python list of 100 elements with elements consisting of 1's, 0.5's. and 0's all weighted by how likely they are to happen. We will randomly sample from this list later when we do our simulation.

null

Now that we have our technical function, let's start creating players and tournaments. We start with a Player class to define some properties and methods for our players.

null

This class has only a few things but allows us to track scores and simulate games with other opponents. Let's start to create our tournament.

null

This class let us build our tournament, add players, and then simulate a single game and then an arbitrary number of games. The properties that will be of interest to us will be the ranks that are generated by all of the simulations. I will leave it to the reader to look through my code and understand how the simulation is working. Let's use these classes to generate some results!

null

The Wachusett Chess Club championship consists of 8 players with ratings varying from the high 1900's to the 1700's. We create a player instance for each and then add each of them to our tournament. We then create the round robin for that tournament and simulate 100,000 times. Here is a sample output you may receive from the pandas dataframe that we create from the ranks:

null

In our first example, we see there are many players who finish on shared 1st but in the 4th row, 'RC' finishes on clear first. From this data, we want to count up how often each player finishes in first place (possibly shared) and then divide by the total number of simulations to get the chances that each player would finish on at least shared first.

null

Doing this, you see that the highest rated player (RC) had a 43% chance of finishing on at least shared first while our lowest rated player had only a 1.6% chance of finishing first. Of note is that our underdog (GB) who is on 4.5/6 going into the last round and currently in shared first had only a 2% chance of finishing on the top! Let's hope that he can pull it off in the last round!

This has been a very different kind of chess blog and I'm very curious to know what you think? Would you like to see more programming applied to interesting chess problems? Let me know in the comments.

RobKing.gif

RobKing
United States

 

My name is Rob King and I am a National Master that lives just outside of Boston,MA. I'm not here to sell you anything, I just want to share my knowledge and passion for chess and analytics. Feel free to message me on here or email me at robking1983@gmail.com on anything related to both.

 

View complete profile