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