Hi Murat, Just to clarify a few things: * The Python 3.10 installation is just the interpreter — essentially a shell — and not the GNUBG application itself. For any of the Python scripts or bindings to work, you’ll need to have GNU Backgammon installed separately. - Unless I'm missing something? * To my knowledge, there's no PyPI-distributed package for the GNUBG Python interface. It has to be built from source. The relevant documentation I think you are looking for is here: ?? https://gnubg.readthedocs.io/en/latest/
On the AI side: while I’m not an expert in machine learning, most modern approaches use reinforcement learning. There’s a now archived open-source project called AMCA, which applies this to backgammon using Stable Baselines: ?? https://github.com/ardabbour/amca It’s a shame you’re not keen on using Python, as it's currently the most well-supported and efficient route to move beyond the limitations of the old TD-Gammon lineage. Best regards, David ________________________________ From: Murat K <[email protected]> Sent: Friday, May 30, 2025 1:15 AM To: DAVID REAY <[email protected]>; bug-gnubg <[email protected]> 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 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 [email protected]<mailto:[email protected]> ________________________________ From: Murat K <[email protected]><mailto:[email protected]> Sent: Tuesday, May 27, 2025 8:59 PM To: DAVID REAY <[email protected]><mailto:[email protected]>; bug-gnubg <[email protected]><mailto:[email protected]> 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 [email protected]<mailto:[email protected]> ________________________________ From: Murat K <[email protected]><mailto:[email protected]> Sent: Monday, May 26, 2025 8:05 PM To: DAVID REAY <[email protected]><mailto:[email protected]>; bug-gnubg <[email protected]><mailto:[email protected]> 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
