diff --git a/.gitignore b/.gitignore
index d2f3fe579..9d37e0d3b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,3 +48,5 @@ doc/tutorials/*.png
Gambit.app/*
*.ipynb_checkpoints
*.ef
+build_support/msw/gambit.wxs
+build_support/osx/Info.plist
diff --git a/doc/pygambit.api.rst b/doc/pygambit.api.rst
index ae029bae7..8a83e8b8d 100644
--- a/doc/pygambit.api.rst
+++ b/doc/pygambit.api.rst
@@ -325,3 +325,158 @@ Computation of quantal response equilibria
logit_estimate
LogitQREMixedStrategyFitResult
LogitQREMixedBehaviorFitResult
+
+
+Game catalog
+~~~~~~~~~~~~
+
+.. currentmodule:: pygambit.catalog
+
+.. autosummary::
+ :toctree: api/
+
+ games
+ Game2s2x2x2
+ Game2smp
+ Game2x2
+ Game2x2a
+ Game2x2const
+ Game2x2x2_nau
+ Game2x2x2
+ Game2x2x2NFG
+ Game2x2x2x2
+ Game2x2x2x2x2
+ Game3x3x3
+ Game4cards
+ Game5x4x3
+ Game8x2x2
+ Game8x8
+ Artist1
+ Artist2
+ Badgame1
+ Badgame2
+ Bagwell
+ Bayes1a
+ Bayes2a
+ Bcp2
+ Bcp3
+ Bcp4
+ Bhg1
+ Bhg2
+ Bhg3
+ Bhg4
+ Bhg5
+ Caro2
+ Cent2
+ Cent2NFG
+ Cent3
+ Cent4
+ Cent6
+ Centcs10
+ Centcs6
+ Condjury
+ Coord2
+ Coord2NFG
+ Coord2ts
+ Coord3
+ Coord3NFG
+ Coord333
+ Coord4
+ Coord4NFG
+ Cross
+ Cs
+ Csg1
+ Csg2
+ Csg3
+ Csg4
+ Deg1
+ Deg2
+ E01
+ E01NFG
+ E02
+ E02NFG
+ E03
+ E04
+ E04NFG
+ E05
+ E06
+ E07
+ E07NFG
+ E08
+ E09
+ E10
+ E10a
+ E13
+ E16
+ E17
+ E18
+ G1
+ G1NFG
+ G2
+ G2NFG
+ G3
+ G3NFG
+ Holdout
+ Hs1
+ Jury_mr
+ Jury_un
+ Km1
+ Km2
+ Km3
+ Km6
+ Loopback
+ Mixdom
+ Mixdom2
+ Montyhal
+ My_2_1
+ My_2_4
+ My_2_8
+ My_3_3a
+ My_3_3b
+ My_3_3c
+ My_3_3d
+ My_3_3e
+ My_3_4
+ Myerson
+ Myerson_fig_4_2
+ Nim
+ Nim7
+ Oneill
+ Palf
+ Palf2
+ Palf3
+ Pbride
+ PrisonersDilemma
+ Perfect1
+ Perfect2
+ Perfect3
+ Poker
+ PokerNFG
+ Poker2
+ Pvw
+ Pvw2
+ Sh3
+ Sh3NFG
+ Spence
+ Stengel
+ Sww1
+ Sww1NFG
+ Sww2
+ Sww3
+ Tim
+ Todd1
+ Todd2
+ Todd3
+ Ttt
+ Vd
+ VdNFG
+ W_ex1
+ W_ex2
+ Wilson1
+ Wink3
+ Winkels
+ Work1
+ Work2
+ Work3
+ Yamamoto
+ Zero
diff --git a/doc/tutorials/01_quickstart.ipynb b/doc/tutorials/01_quickstart.ipynb
index 06ec6f91e..354218160 100644
--- a/doc/tutorials/01_quickstart.ipynb
+++ b/doc/tutorials/01_quickstart.ipynb
@@ -38,7 +38,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 1,
"id": "c58d382d",
"metadata": {},
"outputs": [],
@@ -50,7 +50,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 2,
"id": "2060c1ed",
"metadata": {},
"outputs": [
@@ -60,7 +60,7 @@
"pygambit.gambit.Game"
]
},
- "execution_count": 1,
+ "execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
@@ -83,7 +83,7 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 3,
"id": "9d8203e8",
"metadata": {},
"outputs": [],
@@ -111,7 +111,7 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 4,
"id": "61030607",
"metadata": {},
"outputs": [],
@@ -135,7 +135,7 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 5,
"id": "caecc334",
"metadata": {},
"outputs": [
@@ -149,7 +149,7 @@
"Game(title='Prisoner's Dilemma')"
]
},
- "execution_count": 4,
+ "execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
@@ -189,7 +189,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 6,
"id": "843ba7f3",
"metadata": {},
"outputs": [
@@ -203,7 +203,7 @@
"Game(title='Another Prisoner's Dilemma')"
]
},
- "execution_count": 5,
+ "execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
@@ -233,7 +233,7 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 7,
"id": "5ee752c4",
"metadata": {},
"outputs": [
@@ -270,7 +270,7 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": 8,
"id": "a81c06c7",
"metadata": {},
"outputs": [
@@ -280,7 +280,7 @@
"pygambit.nash.NashComputationResult"
]
},
- "execution_count": 7,
+ "execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
@@ -300,7 +300,7 @@
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": 9,
"id": "bd395180",
"metadata": {},
"outputs": [
@@ -310,7 +310,7 @@
"1"
]
},
- "execution_count": 8,
+ "execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
@@ -329,7 +329,7 @@
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": 10,
"id": "76570ebc",
"metadata": {},
"outputs": [
@@ -342,7 +342,7 @@
"[[Rational(0, 1), Rational(1, 1)], [Rational(0, 1), Rational(1, 1)]]"
]
},
- "execution_count": 9,
+ "execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
@@ -354,7 +354,7 @@
},
{
"cell_type": "code",
- "execution_count": 10,
+ "execution_count": 11,
"id": "6e8cfcde",
"metadata": {},
"outputs": [
@@ -364,7 +364,7 @@
"pygambit.gambit.MixedStrategyProfileRational"
]
},
- "execution_count": 10,
+ "execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
@@ -385,7 +385,7 @@
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": 12,
"id": "980bf6b1",
"metadata": {},
"outputs": [
@@ -417,11 +417,163 @@
},
{
"cell_type": "markdown",
- "id": "24f36b0d",
+ "id": "15ab8d84",
"metadata": {},
"source": [
"The equilibrium shows that both players are playing their dominant strategy, which is to defect. This is because defecting is the best response to the other player's strategy, regardless of what that strategy is.\n",
"\n",
+ "Loading games from the catalog\n",
+ "------------------------------\n",
+ "\n",
+ "Gambit includes a catalog of standard games that can be loaded directly by name.\n",
+ "You can list all the available games and filtering on the game type and number of players in the catalog like so:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "701aa52a",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['Game2x2',\n",
+ " 'Game2x2a',\n",
+ " 'Game2x2const',\n",
+ " 'Game8x8',\n",
+ " 'Cent2NFG',\n",
+ " 'Coord2NFG',\n",
+ " 'Coord3NFG',\n",
+ " 'Coord4NFG',\n",
+ " 'Csg1',\n",
+ " 'Csg2',\n",
+ " 'Csg3',\n",
+ " 'Csg4',\n",
+ " 'Deg1',\n",
+ " 'Deg2',\n",
+ " 'E02NFG',\n",
+ " 'E04NFG',\n",
+ " 'E07NFG',\n",
+ " 'Loopback',\n",
+ " 'Mixdom',\n",
+ " 'Mixdom2',\n",
+ " 'Oneill',\n",
+ " 'PrisonersDilemma',\n",
+ " 'Perfect1',\n",
+ " 'Perfect2',\n",
+ " 'PokerNFG',\n",
+ " 'Sh3NFG',\n",
+ " 'Stengel',\n",
+ " 'Sww1NFG',\n",
+ " 'Todd1',\n",
+ " 'Todd2',\n",
+ " 'Todd3',\n",
+ " 'VdNFG',\n",
+ " 'Wink3',\n",
+ " 'Winkels',\n",
+ " 'Yamamoto',\n",
+ " 'Zero']"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "gbt.catalog.games(game_type=\"nfg\", num_players=2)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fd3f5829-c268-451a-8bc7-28e766e7d655",
+ "metadata": {},
+ "source": [
+ "The catalog can also be searched with custom metadata filters:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "id": "2e680610-e2c9-45bc-84bd-67006aca5174",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['PrisonersDilemma']"
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "gbt.catalog.games(tutorial=1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "id": "ff307b74-16bc-4889-b57c-fef3124ce5ca",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "''"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "gbt.catalog.PrisonersDilemma.description"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a919ddf7",
+ "metadata": {},
+ "source": [
+ "You can then load a specific game by its name. For example, to load the \"Prisoner's Dilemma\" game from the catalog, you would do the following:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "id": "6db7a29a",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
Two person Prisoner's Dilemma game
\n",
+ "\n"
+ ],
+ "text/plain": [
+ "Game(title='Two person Prisoner's Dilemma game')"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "g = gbt.catalog.PrisonersDilemma()\n",
+ "g"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "24f36b0d",
+ "metadata": {},
+ "source": [
"Saving and reading strategic form games to and from file\n",
"--------------------\n",
"\n",
@@ -433,7 +585,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 17,
"id": "f58eaa77",
"metadata": {},
"outputs": [],
@@ -451,23 +603,12 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 18,
"id": "4119a2ac",
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "pygambit.gambit.Game"
- ]
- },
- "execution_count": 13,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
- "# gbt.read_nfg(\"test_games/prisoners_dilemma.nfg\")"
+ "# gbt.read_nfg(\"prisoners_dilemma.nfg\")"
]
}
],
diff --git a/doc/tutorials/02_extensive_form.ipynb b/doc/tutorials/02_extensive_form.ipynb
index 528970c61..4fed4cfbb 100644
--- a/doc/tutorials/02_extensive_form.ipynb
+++ b/doc/tutorials/02_extensive_form.ipynb
@@ -79,20 +79,20 @@
{
"data": {
"image/svg+xml": [
- "