Created
November 7, 2025 06:51
-
-
Save luispedro/2175390e0d17ddbf203a53d8fd6a7888 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from collections import namedtuple | |
| import re | |
| # From https://live.chessbase.com/en/CrossTable?id=fide-world-cup-2025&displayTitle=FIDE%20World%20Cup%202025%2C%20Goa | |
| DATA = ''' | |
| Kovalev,V2557½1------1.5 | |
| Velten,P2530½0------0.5 | |
| Mekhitarian,K25450½------0.5 | |
| Petrov,M25401½------1.5 | |
| Can,E2552½00½----1 | |
| Maksimovic,B2532½11½----3 | |
| Subelj,J2545½00½----1 | |
| Kuybokarov,T2535½11½----3 | |
| Bogner,S2555½½0½----1.5 | |
| Stremavicius,T2531½½1½----2.5 | |
| Nogerbek,K2543½101011½5 | |
| Raja Rithvik R2541½010100½3 | |
| Piorun,K2557½1½½----2.5 | |
| Lobanov,S2526½0½½----1.5 | |
| Flores,D255810½0----1.5 | |
| Makhnev,D252501½1----2.5 | |
| Kantor,G2559½1------1.5 | |
| Rodrigue-Lemieux,S2524½0------0.5 | |
| Ganguly,S257311------2 | |
| Ahmadzada,A252300------0 | |
| Supi,L2575½½1½----2.5 | |
| Galaviz Medina,S2515½½0½----1.5 | |
| Ghosh,D2573½11½----3 | |
| Peng,X2521½00½----1 | |
| Lodici,L2560½1------1.5 | |
| Samadov,R2523½0------0.5 | |
| Jobava,B25730½11----2.5 | |
| Cardoso Cardoso,J25181½00----1.5 | |
| Bartel,M2575001001--2 | |
| Aronyak Ghosh2514110110--4 | |
| Lupulescu,C25770½------0.5 | |
| Blohberger,F25131½------1.5 | |
| Petrov,N25761-------1 | |
| Ghazarian,K25130-------0 | |
| Fier,A2577½1------1.5 | |
| Parligras,M2510½0------0.5 | |
| Brkic,A2578½10½½00½3 | |
| Oro,F2509½01½½11½5 | |
| Karthik Venkataraman25791½------1.5 | |
| Garcia Pantoja,R25020½------0.5 | |
| Kourkoulos-Arditis,S258311------2 | |
| Divya Deshmukh249800------0 | |
| Tin,J2583½11½----3 | |
| Lashkin,J2497½00½----1 | |
| Motylev,A258611------2 | |
| Avila Pavas,S249000------0 | |
| Warmerdam,M2582½011011½5 | |
| Lalit Babu M R2502½100100½3 | |
| Neiksans,A2585½½0½----1.5 | |
| Suleymenov,A2491½½1½----2.5 | |
| Nesterov,A25841½------1.5 | |
| Atabayev,S24940½------0.5 | |
| Huschenbeth,N25871½------1.5 | |
| Bellahcene,B24850½------0.5 | |
| Abasov,N258711------2 | |
| Suyarov,M248700------0 | |
| Adly,A2589½10½½1½-4 | |
| Grigoryan,K2481½01½½0½-3 | |
| Henriquez Villagra,C26051½10----2.5 | |
| Agibileg,U24480½01----1.5 | |
| Bai,J2590½1------1.5 | |
| Fawzy,A2476½0------0.5 | |
| Yilmaz,M2591½1------1.5 | |
| Harshavardhan G B2476½0------0.5 | |
| Woodward,A259011------2 | |
| Gusain,H247600------0 | |
| Cori,J2594½11½----3 | |
| Ansat,A2470½00½----1 | |
| Idani,P260111------2 | |
| Cori Quispe,K245100------0 | |
| Najer,E26101½------1.5 | |
| Rakotomaharo,F24350½------0.5 | |
| Dardha,D260511------2 | |
| Banh Gia Huy244000------0 | |
| Lagarde,M2617½1------1.5 | |
| Amartuvshin,G2415½0------0.5 | |
| Daneshvar,B2602½1------1.5 | |
| Salinas Herrera,P2451½0------0.5 | |
| Cheng,B25961½------1.5 | |
| Siddharth,J24670½------0.5 | |
| Narayanan S L2617½11½----3 | |
| Rojas Salas,S2413½00½----1 | |
| Zemlyanskii,I25961½------1.5 | |
| Pantsulaia,L24570½------0.5 | |
| Indjic,A2618½1------1.5 | |
| Schnaider,I2413½0------0.5 | |
| Suleymanli,A261411------2 | |
| Laohawirapap,P241700------0 | |
| Meier,G2596½1------1.5 | |
| Neelash Saha2466½0------0.5 | |
| Iniyan,P2599½1------1.5 | |
| Berdayes Ason,D2453½0------0.5 | |
| Erdogmus,Y265111------2 | |
| Abugenda,N197200------0 | |
| Mendonca,L26200½------0.5 | |
| Wang,S24021½------1.5 | |
| Ivanchuk,V2616½1------1.5 | |
| Mohammad Fahad,R2416½0------0.5 | |
| Grebnev,A26111½------1.5 | |
| Quizon,D24200½------0.5 | |
| Xiong,J2648½1------1.5 | |
| Li,Y1994½0------0.5 | |
| Yuffa,D2621½½½½½11½5 | |
| Thavandiran,S2402½½½½½00½3 | |
| Rodshtein,M264711------2 | |
| Qin,O207800------0 | |
| Sargissian,G2624½1------1.5 | |
| Liyanage,R2401½0------0.5 | |
| Adams,M264611------2 | |
| Alrehaili,A210900------0 | |
| Cheparinov,I2626½1------1.5 | |
| Cordoba Roa,A2392½0------0.5 | |
| Artemiev,V264611------2 | |
| Ndahangwapo,H209300------0 | |
| Martirosyan,H26261½------1.5 | |
| Cahaya,S23930½------0.5 | |
| Svane,R2614½1------1.5 | |
| Vazquez,F2419½0------0.5 | |
| Grandelius,N2645½1------1.5 | |
| Allam,M2112½0------0.5 | |
| Bacrot,E26271-------1 | |
| Mwali,C23920-------0 | |
| Martinez Alcantara,J264411------2 | |
| Huh,I213900------0 | |
| Ivic,V262811------2 | |
| Orozbaev,E237500------0 | |
| Gledura,B264311------2 | |
| Amdouni,Z218600------0 | |
| Amin,B26291-------1 | |
| Mandizha,F23750-------0 | |
| Kollars,D264211------2 | |
| Salih,A221200------0 | |
| Pranesh M2630½1------1.5 | |
| Akhmedinov,S2372½0------0.5 | |
| Salem,A262011------2 | |
| Tran,T240700------0 | |
| Sadhwani,R26411½------1.5 | |
| Barrish,D22840½------0.5 | |
| Hovhannisyan,R2633½½1½----2.5 | |
| Kavin Mohan2346½½0½----1.5 | |
| Pranav,V264111------2 | |
| Boulrens,A221400------0 | |
| Tari,A26311½------1.5 | |
| Manon,R23690½------0.5 | |
| Donchenko,A264111------2 | |
| Kigigha,B226300------0 | |
| Anton Guijarro,D2631½1------1.5 | |
| Silva,D2347½0------0.5 | |
| Vokhidov,S264011------2 | |
| Ilkhomi,J228900------0 | |
| Chigaev,M2634½1------1.5 | |
| Elbilia,J2332½0------0.5 | |
| Svane,F263811------2 | |
| Husbands,O229100------0 | |
| Gurel,E263411------2 | |
| Efimov,I233100------0 | |
| Keymer,V277311---------2 | |
| Kovalev,V255700---------0 | |
| Erigaisi Arjun276911---------2 | |
| Petrov,M254000---------0 | |
| Giri,A2769½1---------1.5 | |
| Maksimovic,B2532½0---------0.5 | |
| Praggnanandhaa R2768½½½½0111---5 | |
| Kuybokarov,T2535½½½½1000---3 | |
| So,W2764½0---------0.5 | |
| Stremavicius,T2531½1---------1.5 | |
| Gukesh D2763½1---------1.5 | |
| Nogerbek,K2543½0---------0.5 | |
| Wei,Y275311---------2 | |
| Piorun,K255700---------0 | |
| Abdusattorov,N2750½½½1-------2.5 | |
| Makhnev,D2525½½½0-------1.5 | |
| Mamedyarov,S27421011-------3 | |
| Kantor,G25590100-------1 | |
| Vachier-Lagrave,M27401½---------1.5 | |
| Ganguly,S25730½---------0.5 | |
| Rapport,R274011---------2 | |
| Supi,L257500---------0 | |
| Nepomniachtchi,I2732½0---------0.5 | |
| Ghosh,D2573½1---------1.5 | |
| Niemann,H2729½½0½-------1.5 | |
| Lodici,L2560½½1½-------2.5 | |
| Le,Q2729½1---------1.5 | |
| Jobava,B2573½0---------0.5 | |
| Aronian,L27281½---------1.5 | |
| Aronyak Ghosh25140½---------0.5 | |
| Yu,Y2726½½01½½1½---4.5 | |
| Blohberger,F2513½½10½½0½---3.5 | |
| Sindarov,J27211½---------1.5 | |
| Petrov,N25760½---------0.5 | |
| Fedoseev,V27171½---------1.5 | |
| Fier,A25770½---------0.5 | |
| Vidit,S2715½½½1-------2.5 | |
| Oro,F2509½½½0-------1.5 | |
| Aravindh,C2713½0---------0.5 | |
| Karthik Venkataraman2579½1---------1.5 | |
| Nihal Sarin2704½½0½-------1.5 | |
| Kourkoulos-Arditis,S2583½½1½-------2.5 | |
| Sevian,S2701½½11-------3 | |
| Tin,J2583½½00-------1 | |
| Maghsoodloo,P2701½1---------1.5 | |
| Motylev,A2586½0---------0.5 | |
| Liang,A270111---------2 | |
| Warmerdam,M258200---------0 | |
| Van Foreest,J2693½1---------1.5 | |
| Suleymenov,A2491½0---------0.5 | |
| Harikrishna,P2690½1---------1.5 | |
| Nesterov,A2584½0---------0.5 | |
| Yakubboev,N2689½1---------1.5 | |
| Huschenbeth,N2587½0---------0.5 | |
| Esipenko,A268111---------2 | |
| Abasov,N258700---------0 | |
| Bluebaum,M26801½---------1.5 | |
| Adly,A25890½---------0.5 | |
| Sarana,A2675½1---------1.5 | |
| Henriquez Villagra,C2605½0---------0.5 | |
| Dubov,D2674½½½½11-----4 | |
| Bai,J2590½½½½00-----2 | |
| Bu,X2667½½½0-------1.5 | |
| Yilmaz,M2591½½½1-------2.5 | |
| Alekseenko,K2666½1---------1.5 | |
| Woodward,A2590½0---------0.5 | |
| Sargsyan,S2664½½011½-----3.5 | |
| Cori,J2594½½100½-----2.5 | |
| Karthikeyan,M2662½½10½½½0---3.5 | |
| Idani,P2601½½01½½½1---4.5 | |
| Christiansen,J26610½---------0.5 | |
| Najer,E26101½---------1.5 | |
| Oparin,G2660½½0½-------1.5 | |
| Dardha,D2605½½1½-------2.5 | |
| Wojtaszek,R2660½½½1-------2.5 | |
| Lagarde,M2617½½½0-------1.5 | |
| Saric,I26601½---------1.5 | |
| Daneshvar,B26020½---------0.5 | |
| Leko,P2660½1---------1.5 | |
| Cheng,B2596½0---------0.5 | |
| Vitiugov,N2657½½½½½½00---3 | |
| Narayanan S L2617½½½½½½11---5 | |
| Robson,R26570½---------0.5 | |
| Zemlyanskii,I25961½---------1.5 | |
| Theodorou,N2656½½½1-------2.5 | |
| Indjic,A2618½½½0-------1.5 | |
| Deac,B2655½½1½-------2.5 | |
| Suleymanli,A2614½½0½-------1.5 | |
| Murzin,V26550½---------0.5 | |
| Meier,G25961½---------1.5 | |
| Nguyen,T2652½1---------1.5 | |
| Iniyan,P2599½0---------0.5 | |
| Erdogmus,Y265111---------2 | |
| Wang,S240200---------0 | |
| Shankland,S264911---------2 | |
| Ivanchuk,V261600---------0 | |
| Navara,D2648½0---------0.5 | |
| Grebnev,A2611½1---------1.5 | |
| Xiong,J264811---------2 | |
| Yuffa,D262100---------0 | |
| Rodshtein,M2647½½½½00-----2 | |
| Sargissian,G2624½½½½11-----4 | |
| Adams,M2646½½½½10½½11-6 | |
| Cheparinov,I2626½½½½01½½00-4 | |
| Artemiev,V2646½½½1-------2.5 | |
| Martirosyan,H2626½½½0-------1.5 | |
| Mamedov,R2646½½½½01011005 | |
| Svane,R2614½½½½10100116 | |
| Grandelius,N264501½1-------2.5 | |
| Bacrot,E262710½0-------1.5 | |
| Martinez Alcantara,J2644½½½½½½1½---4.5 | |
| Ivic,V2628½½½½½½0½---3.5 | |
| Gledura,B2643½1---------1.5 | |
| Amin,B2629½0---------0.5 | |
| Kollars,D2642½½00-------1 | |
| Pranesh M2630½½11-------3 | |
| Mishra,A2642½0---------0.5 | |
| Salem,A2620½1---------1.5 | |
| Sadhwani,R2641½½00-------1 | |
| Hovhannisyan,R2633½½11-------3 | |
| Pranav,V2641101½-------2.5 | |
| Tari,A2631010½-------1.5 | |
| Donchenko,A2641½1---------1.5 | |
| Anton Guijarro,D2631½0---------0.5 | |
| Vokhidov,S2640½½11-------3 | |
| Chigaev,M2634½½00-------1 | |
| Svane,F2638½1---------1.5 | |
| Gurel,E2634½0---------0.5 | |
| ''' | |
| Player = namedtuple('Player', ['name', 'rating']) | |
| Match = namedtuple('Match', ['player1', 'player2', 'result']) | |
| RESULT = r'^(\D+)(\d\d\d\d)([0-9½])([0-9½])' | |
| def _value(r): | |
| if r == '1': | |
| return 1.0 | |
| elif r == '0': | |
| return 0.0 | |
| elif r == '½': | |
| return 0.5 | |
| else: | |
| raise ValueError(f'Invalid result: {r}') | |
| def read_results(): | |
| for line in DATA.strip().splitlines(): | |
| line = line.strip() | |
| if match := re.match(RESULT, line): | |
| name, rating, r1, r2 = match.groups() | |
| yield Player(name, int(rating)), _value(r1), _value(r2) | |
| def expected_score(delta): | |
| return 1 / (1 + 10**(-delta / 400)) | |
| def prob_one_game(delta): | |
| assert delta >= 0 | |
| expected1 = expected_score(delta) | |
| # assume that wins are twice as likely as draws | |
| p_win = expected1 * 2/3 | |
| p_draw = expected1 * 1/3 | |
| p_lose = 1 - expected1 | |
| return (p_win, p_draw, p_lose) | |
| def match_probabilities(delta): | |
| assert delta >= 0 | |
| p_win1, p_draw1, p_lose1 = prob_one_game(delta) | |
| p_win = p_win1**2 + 2 * p_win1 * p_draw1 | |
| p_draw = p_draw1**2 + 2 * p_win1 * p_lose1 | |
| p_lose = p_lose1**2 + 2 * p_draw1 * p_lose1 | |
| return (p_win, p_draw, p_lose) | |
| matches = [] | |
| results = read_results() | |
| while True: | |
| try: | |
| p1, r1, r2 = next(results) | |
| except StopIteration: | |
| break | |
| p2, r3, r4 = next(results) | |
| assert (r1 + r3 == 1.0), f'Incompatible results: {r1} vs {r3}' | |
| assert (r2 + r4 == 1.0), f'Incompatible results: {r2} vs {r4}' | |
| matches.append(Match(p1, p2, (r1, r2))) | |
| delta_results = [] | |
| for m in matches: | |
| delta = m.player1.rating - m.player2.rating | |
| delta_results.append((delta, m.result[0]+m.result[1])) | |
| expected_upsets = 0 | |
| total_upsets = 0 | |
| LIMIT = 200 | |
| for m in matches: | |
| delta = m.player1.rating - m.player2.rating | |
| if delta >= LIMIT: | |
| p_win, p_draw, p_lose = match_probabilities(delta) | |
| is_upset = (m.result[0] + m.result[1]) < 1.0 | |
| if is_upset: | |
| print(f'Upset: {m.player1.name} ({m.player1.rating}) vs {m.player2.name} ({m.player2.rating}) => {m.result[0]}-{m.result[1]} (p={p_lose:.3f})') | |
| expected_upsets += p_lose | |
| total_upsets += is_upset | |
| print(f''' | |
| Total matches with delta >= {LIMIT}: {len([m for m in matches if (m.player1.rating - m.player2.rating) >= LIMIT])} | |
| Expected upsets: {expected_upsets:.1f} | |
| Actual upsets: {total_upsets} | |
| Difference: {total_upsets - expected_upsets:.1f} | |
| ''') | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment