Hi David,

I guess ChatGPT has difficulty understand me... ;)  Recent GnuBG installations
include Python 3.10.9 and I have no other intended use for Python.

We'll see if others use it to develop better UI's for GnuBG but I'm relatively
happy with its current UI (even if the improvements I suggested never got
implemented).

What I would like most is a better AI that will break away from the progeny
of (the bastardized second version of) TD-Gammon.

As for Heled's Python interface, I was talking about its functionality. Below
is a list of the functions it offers. Feel free to specify which same functions
your extension offers, which ones it doesn't offer and which new ones it
offers in addition.

This is my last post on this subject. I won't waste any more of your and
ChatGPT's time...

MK

===================================================

FUNCTIONS
    gnubg.board(...)
        Get the current board
        arguments: none
        returns: tuple of two lists of 25 ints:
            pieces on points 1..24 and the bar

    gnubg.calcgammonprice(...)
        return cube-info with updated gammon prices
        arguments: [cube-info dictionary]
            cube-info: see 'cfevaluate'
        returns: cube-info dictionary

    gnubg.cfevaluate(...)
        Cubeful evaluation
        arguments: [board] [cube-info] [eval-context]
           board = tuple ( see "board" )
           cube-info = dictionary: 'jacoby'=>0/1, 'crawford'=>0/1
               'move'=>0/1, 'beavers'=>0/1, 'cube'=>cube val (int)
               'matchto'=>length (0 for money), 'bgv'=>0..4
               'score'=>(int, int), 'gammonprice'=(float[4])
           eval-context = dictionary: 'cubeful'=>0/1, 'plies'=>int,
               'deterministic'=> 0/1, 'noise'->float
        returns: evaluation = tuple (floats optimal, nodouble, take, drop, int recommendation, String recommendationtext)

    gnubg.classifypos(...)
        classify a position for a given backammon variant and board
        arguments: [board], [int variant]
        returns: int posclass

    gnubg.command(...)
        Execute a command
        arguments: string containing command
        returns: nothing

    gnubg.cubeinfo(...)
        Make a cubeinfo
        arguments: [cube value, cube owner = 0/1, player on move = 0/1,
            match length (0 = money), score (tuple int, int),
            is crawford = 0/1, bg variant = 0/5]
        returns pos-info dictionary ( see 'cfevaluate' )

    gnubg.dicerolls(...)
        return a list of dice rolls from current RNG
        arguments: number of rolls
         returns: list of tuples (2 elements each, one for each die)

    gnubg.eq2mwc(...)
        convert equity to MWC
        argument: [float equity], [cube-info]
             defaults equity = 0.0, cube-info see 'cfevaluate'
        return float mwc

    gnubg.eq2mwc_stderr(...)
        convert equity standard error to MWC
        argument: [float equity], [cube-info]
             defaults equity = 0.0, cube-info see 'cfevaluate'
        return float mwc

    gnubg.errorrating(...)
        convert an error per move amount to a rating 0 = awful..7=supernatural
        arguments: float error per move
        returns: int

    gnubg.evalcontext(...)
        make an evalcontext
        argument: [tuple ( 5 int, float )]
        returns:  eval-context ( see 'cfevaluate' )

    gnubg.evaluate(...)
        Cubeless evaluation
        arguments: [board] [cube-info] [eval context]
             see 'cfevaluate'
        returns tuple(floats P(win), P(win gammon), P(win backgammnon)
             P(lose gammon), P(lose backgammon), cubeless equity)

    gnubg.findbestmove(...)
        Find the best move
        arguments: [board] [cube-info] [eval-context]
            see 'cfevaluate'
        returns: tuple( ints point from, point to,
            unused moves are set to zero

    gnubg.getevalhintfilter(...)
        return hint/eval move filters
        arguments: none
        returns: list of movefilters

    gnubg.gnubgid(...)
        return GNUBGID from current position, or from board, cube-info, pos-info
        arguments: [board, cube-info dictionary, pos-info dictionary]
            board, cube-info: see 'cfevaluate'
            pos-info: see 'posinfo'
        returns: GNUBGID as string

    gnubg.hint(...)
        arguments: [max moves]
        returns: hint dictionary

    gnubg.luckrating(...)
        convert a luck per move amount into a rating 0..5 for very unlucky to 
very lucky
        arguments: float luck per move
        returns: int 0..5

    gnubg.match(...)
        Get the current match
        arguments: [ include-analysis = 0/1, include-boards = 0/1,
           include-statistics = 0/1, verbose = 0/1 ]
        returns: dictionary of match info:
           'games' => list of dictionaries, one per game
             'info' => dictionary
               'points-won'=>int, 'score-X'=> int, 'winner'=>'X'/'O'
               'resigned'=> 0/1, 'score-O'=> int
             'stats' => dictionary
               'X' => player 0 dictionary of stats
                 'cube'=>dictionary
                   'close-cube'=>int, 'err-missed-double-above-cp-cost'=>float
                   'err-missed-double-above-cp-skill'=>float
                   'err-missed-double-below-cp-cost'=>float
                   'err-missed-double-below-cp-skill'=>float
                   'err-wrong-double-above-tg-cost'=>float
                   'err-wrong-double-above-tg-skill'=>float
                   'err-wrong-double-below-dp-cost'=>float
                   'err-wrong-double-below-dp-skill'=>float
                   'err-wrong-drop-cost'=>float, 'err-wrong-drop-skill'=>float
                   'err-wrong-take-cost'=>float, 'err-wrong-take-skill'=>float
                   'error-cost'=>float, 'error-skill'=>float
                   'missed-double-above-cp'=>int, 'missed-double-below-cp'=>int
                   'n-doubles'=>int, 'n-drops'=>int, 'n-takes': =>int,
                   'total-cube'=>int, 'wrong-double-above-tg'=>int
                   'wrong-double-below-dp'=>int, 'wrong-drop'=>int,
                   'wrong-take'=>int
                 'moves'=>dictionary
                   'marked'=>dictionarly
                      'good'=> int, 'unmarked'->int, 'doubtful'=>int,
                      'bad'=>int, 'very bad'=>int
                   'total-moves'=>int, 'unforced-moves'=>int,
                   'error-cost'=>float, 'error-skill'=>float
                 'dice'=>dictionary
                   'actual-result;=>float, 'cube'=>float, 'luck'=>float,
                   'luck-cost'=>float, 'luck-adjusted-result'=>float
                   'marked-rolls'=>dictionary
                     'verygood'=>int, 'good'=>int, 'unmarked'=>int,
                     'bad'=>int, 'verybad'=>int
                  'time'=>dictionary
                    'time-penalty'=>int, 'time-penalty-cost'=>float,
                    'time-penalty-skill'=>float
                'O'=>  player 1 dicrtionary of stats - see 'X; above
             'game'=>list of dictionaries, one per move
                'dice'=>(int, int), move=>((int, int),[(int, int),...])
                'player'=>'X'/'O', 'board'=>board-id-string,
                'action'=>'move', 'double', 'take', 'drop', 'resign'
                'analysis'=>dictionary
                  'imove'=>int index of move in list of analysed moves
                  'moves'=>list of dictionaries, one per analysed move
                     'score'=>equity for move, 'type'=>'eval''rollout'
                     'move'=>((int, int),[(int, int),...])
                     'probs'=> tuple (5 floats - P(win),
                     P(win gammon)..P(lose bkgammon)
                     [ 'evalcontext' = dictionary describing eval context
                            if not default
            'match-info' = dictionary
              'X' => player-0 dictionary
                'rating' = rating if known
                'name'   = player name
              'O' => player-1 dictionary, as 'X', above
              'date'=>(tuple dd, mm, yyyy)
              'default-eval-context' = dictionary
                'plies'=> int, 'deterministic'=>0/1, 'noise'=>float,
                'cubeful'=>0/1, 'prune'=>0/1
              'match_length' = int
              'result' =>0/1
              'rules' = 'Crawford'/whatever
              'variation' => 'Standard' or whatever

    gnubg.matchchecksum(...)
        Calculate checksum for current match
        arguments: none
        returns: MD5 digest as 32 char hex string

    gnubg.matchid(...)
        return MatchID from current position, or from cube-info, pos-info
        arguments: [cube-info dictionary], [pos-info dictionary]
            cube-info: see 'cfevaluate'
            pos-info: see 'posinfo'
        returns: Match ID as string

    gnubg.met(...)
        return the current match equity table
        arguments: [max score]
         returns: list of list n of list n (rows of pre-crawford table
             list 2 of list n of post-crawford for player 0/player 1

    gnubg.movetupletostring(...)
        Convert a move tuple to a move string
        arguments: tuple of 8 ints
        returns: String representation of move

    gnubg.mwc2eq(...)
        convert MWC to equity
        argument: [float match-winning-chance], [cube-info]
             defaults mwc = 0.0, cube-info see 'cfevaluate'
        returns: float equity

    gnubg.mwc2eq_stderr(...)
        convert standard error MWC to equity
        argument: [float match-winning-chance], [cube-info]
             defaults mwc = 0.0, cube-info see 'cfevaluate'
        returns: float equity

    gnubg.navigate(...)
        go to a position in a match or session'n    arguments: no args = go to 
start of match/session
        [ game=offset] go forward/backward n games
        [record=offset] go gorward/backward n moves'n    returns: None if no change, tuple( games moved, records moved)

    gnubg.nextturn(...)
        play one turn
        arguments: none
        returns: None

    gnubg.parsemove(...)
        Parse move
        arguments: string containing move to parse
        returns: tuple of (tuple (int, int)) representing each move

    gnubg.posinfo(...)
        Make a posinfo dictionary
        arguments: [player on roll = 0/1, player resigned = 0/1,
            player doubled = 0/1, gamestate = 0..7, dice = tuple(0..6, 0..6)]
        returns pos-info dictionary
           pos-info = dictionary: 'dice'=>tuple (int,int), 'turn'=>0/1
               'resigned'=>0/1, 'doubled'=>0/1, 'gamestate'=>int (0..7)

    gnubg.positionbearoff(...)
        return the bearoff id for the given position

    gnubg.positionfrombearoff(...)
        return the board from the given bearoff id
        arguments: [bearoff id] [no. chequers] [no. points]
        returns: board ( see 'cfevaluate' )

    gnubg.positionfromid(...)
        return board from position ID
        arguments: [position ID as string]
        returns: board ( see 'cfevaluate' )

    gnubg.positionfromkey(...)
        return position from key
        arguments: [ list of 10 ints]
        returns: board ( see 'cfevaluate' )

    gnubg.positionid(...)
        return position ID from board
        arguments: [board] ( see 'cfevaluate' )
        returns: position ID as string

    gnubg.positionkey(...)
        return key for position
        arguments: [ board ] ( see 'cfevaluate' )
        returns: tuple (10 ints)

    gnubg.rolloutcontext(...)
        make a rolloutcontext
        argument: [tuple ( 16 int, 2 float )]
        returns:  rollout-context

    gnubg.setevalhintfilter(...)
        return none
        arguments: a list of movefilters
        returns: none

    gnubg.show(...)
        Execute the 'show arguments' command
        arguments: string containing arguments
        returns: result, with final newline(s) stripped, as string

    gnubg.updateui(...)
        Allows the UI to update itself
        arguments: none
        returns: None

===================================================


On 5/27/2025 11:18 PM, DAVID REAY wrote:
Hi Murat,
Here’s a side-by-side comparison between the original Heled-based Python hooks and the new |gnubg| CPython extension:
Feature
        
Heled’s Python Hooks
        
|gnubg| CPython Extension
*Installation*
        
• Clone Savannah repo & build from source• Use the special |gnubg --python| 
interpreter (Python 2.7)
        
• |pip install gnubg|• Prebuilt wheels for Python 3.7–3.13, no build step
*Integration*
        
• Launch |gnubg| as a subprocess• Send commands, parse text output
        
• |import gnubg| into existing python programs
*Dependencies & Setup*
        
• External binary, manual download/config of weights & bear-off tables
        
• Bundles weights & tables inside the wheel• Auto-initialized on first import
*Call Overhead*
        
• High per-call latency (spawn/process I/O)
        
• Low overhead, in-memory C API calls
*Python Version*
        
Python 2.7 only
        
Python 3.7–3.13
*Platform Support*
        
Manual builds on Linux/macOS; limited Windows 32 bit
        
Wheels for Windows x86_64, Linux (x86_64 & ARM), macOS (Intel & ARM) 64 bit
*Ideal Use Cases*
        
Ad-hoc scripts in python2.7 (outdated and unsupported programming language)
        
Jupyter notebooks, CI pipelines, batch data-science workflows, web UIs
*Ecosystem Reach*
        
Limited to existing GnuBG user base
        
*Ubiquitous* in the Python community—opens up backgammon tooling and game development to the largest programming audience

*What I’m aiming to accomplish*

1.
    *Turnkey Python 3 support* without manual builds or subprocess hacks.
2.
    *Broad accessibility*: by distributing on PyPI to the world’s most popular 
developer
    community, |gnubg| becomes instantly available for anyone to build 
backgammon UIs, bots,
    educational tools, data-science research, and more.
3.
    *Cross-platform consistency*: guaranteed prebuilt binaries on all major 
OS/architectures.

To be transparent, I used ChatGPT to help me frame this explanation. I realize Python development may not be part of your day-to-day work—and these enhancements might not directly impact your own workflows—but they’ll pave a much smoother onboarding path for others, with accessible, familiar documentation and examples. That way, developers across the wide Python3 community can more easily get started, leverage, and extend GNU Backgammon, and backgammon like games in general.
Best regards,
David Reay
dr323...@falmouth.ac.uk <mailto:dr323...@falmouth.ac.uk>

----------------------------------------------------------------------------------------------------
*From:* Murat K <muratk1...@yahoo.com>
*Sent:* Tuesday, May 27, 2025 8:59 PM
*To:* DAVID REAY <dr323...@falmouth.ac.uk>; bug-gnubg <bug-gnubg@gnu.org>
*Subject:* Re: Alpha Release of Python3 Extension Module
CAUTION: This email originated from outside of the organisation. Do not click links or open attachments unless you recognise the sender and know the content is safe.

Hi David,

I may have not worded my question clearly. I was expecting a
side-by-side comparison of your extension with Heled's.

All the things you mentioned as pluses are actually minuses
for me. I have created dozens of Python scripts to run many
experiments with GnuBG. After intalling GnuBG, I didn't have
to do anything other than coding my scripts in a text editor
and running them.

Maybe I don't understand what you are trying accomplish..?

MK

On 5/26/2025 1:23 PM, DAVID REAY wrote:
Hi Murat,
Thank you for taking the time to evaluate the alpha release. The goal of this package is to provide a *native Python 3.x extension module* for the core GNU Backgammon neural-net evaluation engine, so you can write scripts or programs in Python 3.7–3.13. In particular, it offers:

 *
    *Full Python 3 support*
    You no longer need to fall back to Python 2.7 or the specialized GNU 
Backgammon
    interpreter—simply run your existing analysis code under Python 3.7 through 
3.13.
 *
    *Easy installation via PyPI*
    |pip install gnubg |
    and then in your code:
    |import gnubg |
    No more manual clones of Savannah, no wrestling with build scripts, GNU 
autotools, or
    makefiles, and no more hunting down network-weight files.
 *
    *Cross-platform wheels*
    Prebuilt binaries are available for Windows x86_64, Linux (x86_64 & ARM), and 
macOS (Intel &
    ARM).
 *
    *Out-of-the-box packaging*
    All necessary weight files, bear-off tables, are bundled. You get a turnkey 
CPython extension
    module—no extra steps required.

Best regards,

David Reay
dr323...@falmouth.ac.uk <mailto:dr323...@falmouth.ac.uk>

----------------------------------------------------------------------------------------------------
*From:* Murat K <muratk1...@yahoo.com> <mailto:muratk1...@yahoo.com>
*Sent:* Monday, May 26, 2025 8:05 PM
*To:* DAVID REAY <dr323...@falmouth.ac.uk> <mailto:dr323...@falmouth.ac.uk>; bug-gnubg <bug-gnubg@gnu.org> <mailto:bug-gnubg@gnu.org>
*Subject:* Re: Alpha Release of Python3 Extension Module
CAUTION: This email originated from outside of the organisation. Do not click links or open attachments unless you recognise the sender and know the content is safe.


On 5/24/2025 11:38 PM, DAVID REAY wrote:

 > I'm writing to share the alpha release of the
 > Python extension module that wraps the GNU
 > Backgammon neural network evaluation engine.

After looking at your site, it's not clear to me
what functionality does your extension offers
that we don't already have..?

MK


Reply via email to