Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
90a5e36
Create catalog dir and move one EFG and one NFG into it from contrib/…
edwardchalstrey1 Feb 3, 2026
83dd410
ignore catalog files copied into pygambit
edwardchalstrey1 Feb 3, 2026
7fc2199
add failing tests
edwardchalstrey1 Feb 3, 2026
3c53bea
improve tests
edwardchalstrey1 Feb 3, 2026
898a916
add pandas to pyproject.toml
edwardchalstrey1 Feb 3, 2026
8f916db
add test_catalog_load_invalid_slug
edwardchalstrey1 Feb 3, 2026
606dd8a
create load function
edwardchalstrey1 Feb 3, 2026
00beed3
add catalog to __init__
edwardchalstrey1 Feb 3, 2026
64eb310
add games() function
edwardchalstrey1 Feb 3, 2026
d24befd
refactor to define READERS once
edwardchalstrey1 Feb 3, 2026
72aade1
Big refactor to get catalog files from catalog dir external to pygambit
edwardchalstrey1 Feb 3, 2026
e7953e9
update Makefile.am for the 2 examples we moved into the catalog so far
edwardchalstrey1 Feb 3, 2026
7490ae6
update Game.comment to be Game.description in Python code
edwardchalstrey1 Feb 4, 2026
ebf6829
Revert "update Game.comment to be Game.description in Python code"
edwardchalstrey1 Feb 4, 2026
fbf6b89
Add initial update catalog script and RST page
edwardchalstrey1 Feb 4, 2026
1ca3461
rename table headers on output df from game() func
edwardchalstrey1 Feb 4, 2026
bd3c1f3
add generating the catalog csv for docs into GH actions
edwardchalstrey1 Feb 4, 2026
569148c
Revert "add generating the catalog csv for docs into GH actions"
edwardchalstrey1 Feb 4, 2026
8cf0396
refactor update script so its run from repo root
edwardchalstrey1 Feb 4, 2026
1b20438
update readthedocs to build the catalog csv before docs build
edwardchalstrey1 Feb 4, 2026
e977e64
add function which updates Makefile.am
edwardchalstrey1 Feb 4, 2026
af08d29
use a proper path for CATALOG_CSV
edwardchalstrey1 Feb 4, 2026
cd2ffc9
tidy update script
edwardchalstrey1 Feb 4, 2026
5675444
use explicit python executable from the virtualenv to create CSV for …
edwardchalstrey1 Feb 4, 2026
f574223
add developer doc for updating the catalog
edwardchalstrey1 Feb 4, 2026
5147278
Don't update Makefile.am by default
edwardchalstrey1 Feb 4, 2026
4b033c9
consistency in notebook comment
edwardchalstrey1 Feb 4, 2026
b14402a
demo loading from catalog in tutorial 1
edwardchalstrey1 Feb 4, 2026
264f7fb
load from catalog for game examples in advanced tutorials
edwardchalstrey1 Feb 4, 2026
0e268a2
Try using pip instead of setuptools to ensure pyproject.toml deps ins…
edwardchalstrey1 Feb 4, 2026
8649946
remove deleted contrib games from Makefile.am
edwardchalstrey1 Feb 4, 2026
adea4f2
add a warning about moving games from contrib
edwardchalstrey1 Feb 4, 2026
a72f7a2
check if pandas duplications error exists if we dont save outputs on …
edwardchalstrey1 Feb 4, 2026
57863d4
fix problem with print function
edwardchalstrey1 Feb 4, 2026
b687e20
resave notebook outputs
edwardchalstrey1 Feb 4, 2026
6562433
Update writer.cc
tturocy Feb 10, 2026
39fde9d
Merge branch 'master' into ehancement/731/take2
edwardchalstrey1 Feb 10, 2026
f84bcc8
move catalog update script into build support
edwardchalstrey1 Feb 10, 2026
d17f976
rename script
edwardchalstrey1 Feb 10, 2026
f07fdae
rename var
edwardchalstrey1 Feb 10, 2026
fd66e41
update path to catalog update script in readthedocs yml and docs page
edwardchalstrey1 Feb 10, 2026
bb1e920
move myserson fig into subfolder
edwardchalstrey1 Feb 10, 2026
5c7a60f
clarify script usage
edwardchalstrey1 Feb 10, 2026
dc7a373
add test_catalog_load_subdir_slug
edwardchalstrey1 Feb 10, 2026
7850585
update makefile
edwardchalstrey1 Feb 10, 2026
f6ea5df
update agent nb
edwardchalstrey1 Feb 10, 2026
f655645
add test for slug in subdir of catalog
edwardchalstrey1 Feb 10, 2026
56cd19a
update games func to list slugs correctly
edwardchalstrey1 Feb 10, 2026
6a4df8f
update test to avoid duplicates
edwardchalstrey1 Feb 10, 2026
886131c
fix code for handling slugs that duplicates of those in subfolders
edwardchalstrey1 Feb 10, 2026
68909b9
tidy the games() refactor
edwardchalstrey1 Feb 10, 2026
bb8f483
resave notebook
edwardchalstrey1 Feb 10, 2026
50e618b
strip nb outputs
edwardchalstrey1 Feb 10, 2026
67dedb2
remove modification to games() that was fixing a local issue
edwardchalstrey1 Feb 10, 2026
1794a83
fix the update script to get correct paths
edwardchalstrey1 Feb 10, 2026
079aacd
remove unused var
edwardchalstrey1 Feb 10, 2026
e57cfce
Add Windows handling
edwardchalstrey1 Feb 10, 2026
bdc5d3a
fix incorrect var name and make consistent
edwardchalstrey1 Feb 11, 2026
69d8cb9
use as_posix for slugs
edwardchalstrey1 Feb 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,5 @@ Gambit.app/*
*.ef
build_support/msw/gambit.wxs
build_support/osx/Info.plist
src/pygambit/catalog
doc/catalog.csv
6 changes: 5 additions & 1 deletion .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@ build:
- libgmp-dev
- pandoc
- texlive-full
jobs:
# Create CSV for catalog table in docs
post_install:
- $READTHEDOCS_VIRTUALENV_PATH/bin/python build_support/catalog/update.py

python:
install:
- requirements: doc/requirements.txt
- method: setuptools
- method: pip
path: "."
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
recursive-include src/core *.cc *.h *.imp
recursive-include src/games *.cc *.h *.imp
recursive-include src/solvers *.c *.cc *.h *.imp
recursive-include catalog *
include src/gambit.h
include src/pygambit/*.pxd
include src/pygambit/*.pyx
Expand Down
10 changes: 5 additions & 5 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ EXTRA_DIST = \
src/gui/bitmaps/zoom1.xpm \
src/gui/bitmaps/gambitrc.rc \
contrib/games/2s2x2x2.efg \
contrib/games/2smp.efg \
contrib/games/2x2x2.efg \
contrib/games/4cards.efg \
contrib/games/artist1.efg \
Expand Down Expand Up @@ -169,7 +168,6 @@ EXTRA_DIST = \
contrib/games/my_3-3d.efg \
contrib/games/my_3-3e.efg \
contrib/games/my_3-4.efg \
contrib/games/myerson.efg \
contrib/games/nim7.efg \
contrib/games/nim.efg \
contrib/games/palf2.efg \
Expand All @@ -195,7 +193,6 @@ EXTRA_DIST = \
contrib/games/2x2a.nfg \
contrib/games/2x2const.nfg \
contrib/games/2x2.nfg \
contrib/games/2x2x2.nfg \
contrib/games/2x2x2x2.nfg \
contrib/games/2x2x2x2x2.nfg \
contrib/games/3x3x3.nfg \
Expand Down Expand Up @@ -224,7 +221,6 @@ EXTRA_DIST = \
contrib/games/mixdom2.nfg \
contrib/games/mixdom.nfg \
contrib/games/oneill.nfg \
contrib/games/pd.nfg \
contrib/games/perfect1.nfg \
contrib/games/perfect2.nfg \
contrib/games/perfect3.nfg \
Expand All @@ -240,7 +236,11 @@ EXTRA_DIST = \
contrib/games/winkels.nfg \
contrib/games/yamamoto.nfg \
contrib/games/zero.nfg \
src/README.rst
src/README.rst \
catalog/2smp.efg \
catalog/2x2x2.nfg \
catalog/myerson/fig_4_2.efg \
catalog/pd.nfg

core_SOURCES = \
src/core/core.h \
Expand Down
74 changes: 74 additions & 0 deletions build_support/catalog/update.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import argparse
from pathlib import Path

import pygambit as gbt

CATALOG_CSV = Path(__file__).parent.parent.parent / "doc" / "catalog.csv"
CATALOG_DIR = Path(__file__).parent.parent.parent / "catalog"
MAKEFILE_AM = Path(__file__).parent.parent.parent / "Makefile.am"


def update_makefile():
"""Update the Makefile.am with all games from the catalog."""

# Using rglob("*") to find files in all subdirectories
slugs = []
for resource_path in sorted(CATALOG_DIR.rglob("*.efg")):
if resource_path.is_file():
rel_path = resource_path.relative_to(CATALOG_DIR)
slugs.append(str(rel_path))
for resource_path in sorted(CATALOG_DIR.rglob("*.nfg")):
if resource_path.is_file():
rel_path = resource_path.relative_to(CATALOG_DIR)
slugs.append(str(rel_path))

game_files = []
for slug in slugs:
game_files.append(f"catalog/{slug}")
game_files.sort()

with open(MAKEFILE_AM, encoding="utf-8") as f:
content = f.readlines()

with open(MAKEFILE_AM, "w", encoding="utf-8") as f:
in_gamefiles_section = False
for line in content:
# Add to the EXTRA_DIST after the README.rst line
if line.startswith(" src/README.rst \\"):
in_gamefiles_section = True
f.write(" src/README.rst \\\n")
for gf in game_files:
if gf == game_files[-1]:
f.write(f"\t{gf}\n")
else:
f.write(f"\t{gf} \\\n")
f.write("\n")
elif in_gamefiles_section:
if line.strip() == "":
in_gamefiles_section = False
continue # Skip old gamefiles lines
else:
f.write(line)

with open(MAKEFILE_AM, encoding="utf-8") as f:
updated_content = f.readlines()

if content != updated_content:
print(f"Updated {str(MAKEFILE_AM)}")
else:
print(f"No changes to add to {str(MAKEFILE_AM)}")


if __name__ == "__main__":

parser = argparse.ArgumentParser()
parser.add_argument("--build", action="store_true")
args = parser.parse_args()

# Create CSV used by RST docs page
gbt.catalog.games().to_csv(CATALOG_CSV, index=False)
print(f"Generated {CATALOG_CSV} for use in local docs build. DO NOT COMMIT.")

# Update the Makefile.am with the current list of catalog files
if args.build:
update_makefile()
File renamed without changes.
File renamed without changes.
60 changes: 60 additions & 0 deletions catalog/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from importlib.resources import as_file, files
from pathlib import Path

import pandas as pd

import pygambit as gbt

# Use the full string path to the virtual package we created
_CATALOG_RESOURCE = files(__name__)

READERS = {
".nfg": gbt.read_nfg,
".efg": gbt.read_efg,
}


def load(slug: str) -> gbt.Game:
"""
Load a game from the package catalog.
"""
slug = str(Path(slug)).replace("\\", "/")

for suffix, reader in READERS.items():
resource_path = _CATALOG_RESOURCE / f"{slug}{suffix}"

if resource_path.is_file():
# as_file ensures we have a real filesystem path for the reader
with as_file(resource_path) as path:
return reader(str(path))

raise FileNotFoundError(f"No catalog entry called {slug}.nfg or {slug}.efg")


def games() -> pd.DataFrame:
"""
List games available in the package catalog, including subdirectories.
"""
records: list[dict[str, str]] = []

# Using rglob("*") to find files in all subdirectories
for resource_path in sorted(_CATALOG_RESOURCE.rglob("*")):
reader = READERS.get(resource_path.suffix)

if reader is not None and resource_path.is_file():

# Calculate the path relative to the root resource
# and remove the suffix to get the "slug"
rel_path = resource_path.relative_to(_CATALOG_RESOURCE)
slug = rel_path.with_suffix("").as_posix()

with as_file(resource_path) as path:
game = reader(str(path))
records.append(
{
"Game": slug,
"Title": game.title,
}
)

return pd.DataFrame.from_records(records, columns=["Game", "Title"])
File renamed without changes.
File renamed without changes.
8 changes: 8 additions & 0 deletions doc/catalog.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Catalog of games
================

.. csv-table::
:file: catalog.csv
:header-rows: 1
:widths: 20, 80
:class: tight-table
45 changes: 45 additions & 0 deletions doc/developer.catalog.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
Updating the Games Catalog
==========================

This page covers the process for contributing to and updating Gambit's :ref:`Games Catalog <pygambit-catalog>`.
To do so, you will need to have the `gambit` GitHub repo cloned and be able to submit pull request via GitHub;
you may wish to first review the :ref:`contributor guidelines <contributing>`.

You can add games to the catalog saved in a valid representation :ref:`format <file-formats>`.
Currently supported representations are:

- `.efg` for extensive form games
- `.nfg` for normal form games

Add new games
-------------

1. **Create the game file:**

Use either :ref:`pygambit <pygambit>`, the Gambit :ref:`CLI <command-line>` or :ref:`GUI <section-gui>` to create and save game in a valid representation :ref:`format <file-formats>`.

2. **Add the game file:**

Create a new branch in the ``gambit`` repo. Add your new game file(s) inside the ``catalog`` dir and commit them.

3. **Update the catalog:**

Use the ``update.py`` script to update Gambit's documentation & build files.

.. code-block:: bash

python build_support/catalog/update.py --build

.. note::

Run this script in a Python environment where ``pygambit`` itself is also :ref:`installed <build-python>`.

.. warning::

Running the script with the ``--build`` flag updates `Makefile.am`. If you moved games that were previously in `contrib/games` you'll need to also manually remove those files from `EXTRA_DIST`.

4. **Submit a pull request to GitHub with all changes.**

.. warning::

Make sure you commit all changed files e.g. run ``git add --all`` before committing and pushing.
2 changes: 2 additions & 0 deletions doc/developer.contributing.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _contributing:

Contributing to Gambit
======================

Expand Down
1 change: 1 addition & 0 deletions doc/developer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ This section contains information for developers who want to contribute to the G

developer.build
developer.contributing
developer.catalog
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ We recommended most new users install the PyGambit Python package and read the a
pygambit
tools
gui
catalog
samples
developer
formats
Expand Down
Loading