Page 1 of 1

Position performance in a pgn database

Posted: Fri Jul 12, 2019 11:27 am
by giovanni
Is there a command line tool that takes as input a epd or a FEN string and reports its performance in a pgn database? For performance, the white score percentage would suffice, but if it would calculates also the Elo performance would be even better.
I know that several GUIs like Scid, ChessBase, etc., already do this, but I am looking for a command line tool.
Thanks in advance.

Re: Position performance in a pgn database

Posted: Sun Jul 14, 2019 11:45 am
by Ferdy
giovanni wrote: Fri Jul 12, 2019 11:27 am Is there a command line tool that takes as input a epd or a FEN string and reports its performance in a pgn database? For performance, the white score percentage would suffice, but if it would calculates also the Elo performance would be even better.
I know that several GUIs like Scid, ChessBase, etc., already do this, but I am looking for a command line tool.
Thanks in advance.
This one https://github.com/mcostalba/scoutfish is capable of doing what you need.
A sample python code is available see at end of page. scoutfish.py module is inside the src folder, you need it. Also pip install pexpect.

Try this script, change the pgn filename.

Code: Select all

#!/usr/bin/env python3
"""
sc.py

"""


import time
from scoutfish import Scoutfish


def search(eng, pgn, threads=1, fen=None, res=None):
    p = Scoutfish(eng)
    p.setoption('threads', threads)  # Will use 4 threads for searching
    p.open(pgn)
    
    q = { "sub-fen": fen, "result": res }
    result = p.scout(q)
    num = result['match count']
    
    p.close()
    
    return num


def main():
    pgn = 'clean_KingBase2019-A00-A39.pgn'
    eng = 'scoutfish.exe'
    threads = 1
    
    fen = input('enter fen? ')
    
    t1 = time.perf_counter()
    res = '1-0'
    wwins = search(eng, pgn, threads, fen, res)
    
    res = '0-1'
    wloss = search(eng, pgn, threads, fen, res)
    
    res = '1/2-1/2'
    wdraw = search(eng, pgn, threads, fen, res)
    
    total = wwins + wloss + wdraw
    score = wwins + wdraw/2
    rate = score/total
    print('rate: {:0.2f}% wpov'.format(rate*100))
    print('elapsed sec: {:0.2f}'.format(time.perf_counter() - t1))


if __name__ == "__main__":
    main()
Sample run.
enter fen? rnbqkb1r/pppp1ppp/5n2/4p3/2P5/6P1/PP1PPP1P/RNBQKBNR w KQkq - 1 3
rate: 53.95% wpov
elapsed sec: 2.13

source pgn is around 250k games.

Download scoutfish.exe at https://github.com/pychess/scoutfish/releases
Place scoutfish.exe, scoutfish.py and sc.py in same folder.
Install pexpect with,
pip install pexpect

Re: Position performance in a pgn database

Posted: Sun Jul 14, 2019 3:04 pm
by giovanni
Ferdy wrote: Sun Jul 14, 2019 11:45 am
giovanni wrote: Fri Jul 12, 2019 11:27 am Is there a command line tool that takes as input a epd or a FEN string and reports its performance in a pgn database? For performance, the white score percentage would suffice, but if it would calculates also the Elo performance would be even better.
I know that several GUIs like Scid, ChessBase, etc., already do this, but I am looking for a command line tool.
Thanks in advance.
This one https://github.com/mcostalba/scoutfish is capable of doing what you need.
A sample python code is available see at end of page. scoutfish.py module is inside the src folder, you need it. Also pip install pexpect.

Try this script, change the pgn filename.

Code: Select all

#!/usr/bin/env python3
"""
sc.py

"""


import time
from scoutfish import Scoutfish


def search(eng, pgn, threads=1, fen=None, res=None):
    p = Scoutfish(eng)
    p.setoption('threads', threads)  # Will use 4 threads for searching
    p.open(pgn)
    
    q = { "sub-fen": fen, "result": res }
    result = p.scout(q)
    num = result['match count']
    
    p.close()
    
    return num


def main():
    pgn = 'clean_KingBase2019-A00-A39.pgn'
    eng = 'scoutfish.exe'
    threads = 1
    
    fen = input('enter fen? ')
    
    t1 = time.perf_counter()
    res = '1-0'
    wwins = search(eng, pgn, threads, fen, res)
    
    res = '0-1'
    wloss = search(eng, pgn, threads, fen, res)
    
    res = '1/2-1/2'
    wdraw = search(eng, pgn, threads, fen, res)
    
    total = wwins + wloss + wdraw
    score = wwins + wdraw/2
    rate = score/total
    print('rate: {:0.2f}% wpov'.format(rate*100))
    print('elapsed sec: {:0.2f}'.format(time.perf_counter() - t1))


if __name__ == "__main__":
    main()

Sample run.
enter fen? rnbqkb1r/pppp1ppp/5n2/4p3/2P5/6P1/PP1PPP1P/RNBQKBNR w KQkq - 1 3
rate: 53.95% wpov
elapsed sec: 2.13

source pgn is around 250k games.

Download scoutfish.exe at https://github.com/pychess/scoutfish/releases
Place scoutfish.exe, scoutfish.py and sc.py in same folder.
Install pexpect with,
pip install pexpect
Thanks Ferdy. Appreciated. Thanks also for drawing our attention to this very interesting tool.

Re: Position performance in a pgn database

Posted: Sun Jul 14, 2019 8:52 pm
by Ferdy
giovanni wrote: Fri Jul 12, 2019 11:27 am Is there a command line tool that takes as input a epd or a FEN string and reports its performance in a pgn database? For performance, the white score percentage would suffice, but if it would calculates also the Elo performance would be even better.
The module scoutfish.py can extract game headers, with that headers we can calculate the position's rating perf.
Using rating perf simple formula

Code: Select all

white elo perf = (sum_elo_black + 400 * (white_wins - white_loses)) / num_games
from https://en.wikipedia.org/wiki/Elo_ratin ... nce_rating

Make sure your games have ratings.

Sample run.

Code: Select all

enter pgn? clean_KingBase2019-A00-A39.pgn

enter fen? rnbqkb1r/pppp1ppp/5n2/4p3/2P5/6P1/PP1PPP1P/RNBQKBNR w KQkq - 1 3

pgn: clean_KingBase2019-A00-A39.pgn
FEN: rnbqkb1r/pppp1ppp/5n2/4p3/2P5/6P1/PP1PPP1P/RNBQKBNR w KQkq - 1 3
white score rate     : 53.95%
white average_rating : 2368
white Elo perf       : 2399

elapsed sec: 3.58

Revised script.

Code: Select all

#!/usr/bin/env python3
"""
sc.py

"""


import time
from scoutfish import Scoutfish


def search(eng, pgn, threads=1, fen=None, res=None):
    p = Scoutfish(eng)
    p.setoption('threads', threads)
    p.open(pgn)
    
    res_stat = []
    white_rating = []
    black_rating = []
    white_wins = 0
    white_loses = 0
    
    for r in res:
        q = { "sub-fen": fen, "result": r }
        result = p.scout(q)
        num = result['match count']
        res_stat.append(num)
        
        # Get game headers
        games = p.get_games(result['matches'])                
        headers = p.get_game_headers(games)
        for h in headers:            
            wr = int(h['WhiteElo'])
            br = int(h['BlackElo'])
            r = h['Result']
            
            if r == '1-0':
                white_wins += 1
            elif r == '0-1':
               white_loses += 1 
            
            white_rating.append(wr)
            black_rating.append(br)
    
    p.close()
    
    white_average_rating = sum(white_rating)/len(white_rating)
    num_games = len(black_rating)
    
    white_elo_perf = sum(black_rating) + 400 * (white_wins - white_loses)
    white_elo_perf = white_elo_perf/num_games
    
    return res_stat[0], res_stat[1], res_stat[2], white_average_rating, white_elo_perf


def main():
    eng = 'scoutfish.exe'
    threads = 1
    res = ['1-0', '0-1', '1/2-1/2']
    
    # pgn= 'clean_KingBase2019-A00-A39.pgn'
    # fen = 'rnbqkb1r/pppp1ppp/5n2/4p3/2P5/6P1/PP1PPP1P/RNBQKBNR w KQkq - 1 3'
    
    pgn = input('enter pgn? ')
    fen = input('enter fen? ')    
    
    t1 = time.perf_counter()
    
    wwins, wloss, wdraw, white_average_rating, white_elo_perf = \
            search(eng, pgn, threads, fen, res)
    
    total = wwins + wloss + wdraw
    score = wwins + wdraw/2
    score_rate = 100*score/total
    
    print()
    print('pgn: {}'.format(pgn))
    print('FEN: {}'.format(fen))
    print('white score rate     : {:0.2f}%'.format(score_rate))
    print('white average_rating : {:0.0f}'.format(white_average_rating))
    print('white Elo perf       : {:0.0f}'.format(white_elo_perf))
    
    print('\nelapsed sec: {:0.2f}'.format(time.perf_counter() - t1))


if __name__ == "__main__":
    main()

Re: Position performance in a pgn database

Posted: Mon Jul 15, 2019 9:46 am
by giovanni
Nice. Thanks again, Ferdy.