├── textworld ├── envs │ ├── glulx │ │ └── __init__.py │ ├── zmachine │ │ └── __init__.py │ ├── pddl │ │ ├── __init__.py │ │ ├── logic │ │ │ ├── logic.ebnf │ │ │ └── model.py │ │ └── textgen │ │ │ ├── textgen.ebnf │ │ │ └── model.py │ ├── wrappers │ │ ├── __init__.py │ │ ├── generic.py │ │ ├── recorder.py │ │ ├── limit.py │ │ ├── tests │ │ │ ├── test_limit.py │ │ │ ├── test_filter.py │ │ │ └── test_viewer.py │ │ └── filter.py │ ├── __init__.py │ └── batch │ │ └── __init__.py ├── challenges │ ├── tw_cooking │ │ ├── __init__.py │ │ ├── textworld_data │ │ │ ├── logic │ │ │ │ ├── pot.twl │ │ │ │ ├── player.twl │ │ │ │ ├── supporter.twl │ │ │ │ ├── key.twl │ │ │ │ ├── object.twl │ │ │ │ ├── stove.twl │ │ │ │ ├── thing.twl │ │ │ │ ├── container.twl │ │ │ │ ├── inventory.twl │ │ │ │ └── oven.twl │ │ │ ├── logic_drop │ │ │ │ ├── pot.twl │ │ │ │ ├── supporter.twl │ │ │ │ ├── player.twl │ │ │ │ ├── key.twl │ │ │ │ ├── object.twl │ │ │ │ ├── stove.twl │ │ │ │ ├── thing.twl │ │ │ │ ├── container.twl │ │ │ │ └── oven.twl │ │ │ └── text_grammars │ │ │ │ └── house_ext_cook.twg │ │ └── README.md │ ├── tw_simple │ │ ├── __init__.py │ │ └── textworld_data │ │ │ └── logic │ │ │ ├── player.twl │ │ │ ├── supporter.twl │ │ │ ├── thing.twl │ │ │ ├── key.twl │ │ │ ├── object.twl │ │ │ ├── food.twl │ │ │ ├── container.twl │ │ │ └── inventory.twl │ ├── tw_coin_collector │ │ ├── __init__.py │ │ └── textworld_data │ │ │ └── logic │ │ │ ├── player.twl │ │ │ ├── object.twl │ │ │ ├── thing.twl │ │ │ └── inventory.twl │ ├── tw_treasure_hunter │ │ ├── __init__.py │ │ └── textworld_data │ │ │ └── logic │ │ │ ├── player.twl │ │ │ ├── supporter.twl │ │ │ ├── thing.twl │ │ │ ├── key.twl │ │ │ ├── object.twl │ │ │ ├── food.twl │ │ │ ├── container.twl │ │ │ └── inventory.twl │ ├── __init__.py │ ├── tests │ │ ├── test_treasure_hunter.py │ │ └── test_coin_collector.py │ ├── registration.py │ └── utils.py ├── version.py ├── thirdparty │ └── glulx │ │ ├── Git-Glulx │ │ ├── .gitignore │ │ ├── user_agent.py │ │ ├── help │ │ │ ├── about.png │ │ │ ├── fixed.png │ │ │ ├── help.png │ │ │ ├── prop.png │ │ │ ├── credits.htm │ │ │ ├── options.png │ │ │ ├── scroll.png │ │ │ ├── Git.css │ │ │ ├── Git.hhp │ │ │ ├── glulx.htm │ │ │ ├── autorun.htm │ │ │ ├── glk.htm │ │ │ ├── menus_toolbar.htm │ │ │ ├── blorb.htm │ │ │ ├── archive.htm │ │ │ ├── gfx_sound.htm │ │ │ ├── license_ogg.htm │ │ │ ├── getting_started.htm │ │ │ └── overview.htm │ │ ├── win │ │ │ ├── res │ │ │ │ ├── Blorb.ico │ │ │ │ ├── Glulx.ico │ │ │ │ ├── Ulx.ico │ │ │ │ └── Git.manifest │ │ │ └── git.rc │ │ ├── version.h │ │ ├── test.sh │ │ ├── Makefile.win │ │ ├── gestalt.c │ │ └── git_mac.c │ │ └── cheapglk │ │ ├── .gitignore │ │ ├── cgblorb.c │ │ ├── cgstyle.c │ │ ├── glkstart.c │ │ ├── agent.h │ │ ├── LICENSE │ │ ├── gi_debug.c │ │ ├── Makefile │ │ ├── glkstart.h │ │ └── cgschan.c ├── gym │ ├── __init__.py │ ├── envs │ │ ├── __init__.py │ │ └── utils.py │ └── core.py ├── render │ ├── tmpl │ │ ├── static │ │ │ └── images │ │ │ │ ├── TextWorldIcons_Door.png │ │ │ │ ├── TextWorldIcons_Food.png │ │ │ │ ├── TextWorldIcons_Key.png │ │ │ │ ├── TextWorldIcons_Cooked.png │ │ │ │ ├── TextWorldIcons_Fixed.png │ │ │ │ ├── TextWorldIcons_Locked.png │ │ │ │ ├── TextWorldIcons_Object.png │ │ │ │ ├── TextWorldIcons_Player.png │ │ │ │ ├── TextWorldIcons_Chevron.png │ │ │ │ ├── TextWorldIcons_Container.png │ │ │ │ ├── TextWorldIcons_DoorOpen.png │ │ │ │ ├── TextWorldIcons_LightOff.png │ │ │ │ ├── TextWorldIcons_LightOn.png │ │ │ │ ├── TextWorldIcons_Portable.png │ │ │ │ ├── TextWorldIcons_Supporter.png │ │ │ │ ├── TextWorldIcons_Uncooked.png │ │ │ │ ├── TextWorldIcons_Unlocked.png │ │ │ │ └── TextWorldIcons_ContainerOpen.png │ │ └── slideshow.handlebars │ ├── __init__.py │ └── tests │ │ └── test_graph.py ├── generator │ ├── data │ │ ├── logic │ │ │ ├── player.twl │ │ │ ├── supporter.twl │ │ │ ├── thing.twl │ │ │ ├── key.twl │ │ │ ├── object.twl │ │ │ ├── food.twl │ │ │ ├── container.twl │ │ │ └── inventory.twl │ │ └── text_grammars │ │ │ ├── basic_instruction.twg │ │ │ └── basic_room.twg │ ├── inform7 │ │ └── __init__.py │ └── tests │ │ ├── test_init.py │ │ └── test_logger.py ├── agents │ ├── __init__.py │ ├── simple.py │ ├── walkthrough.py │ └── random.py ├── __init__.py ├── textgen │ ├── textgen.ebnf │ └── model.py ├── tests │ └── test_core.py └── text_utils.py ├── misc ├── vscode │ ├── .gitignore │ ├── .vscodeignore │ ├── .gitattributes │ ├── CHANGELOG.md │ ├── README.md │ ├── .vscode │ │ └── launch.json │ ├── language-configuration.json │ └── package.json ├── logo.png └── logo_ascii.txt ├── requirements-pddl.txt ├── notebooks ├── figs │ └── neural_agent.png ├── games │ ├── tw-another_game.z8 │ ├── tw-rewardsDense_goalBrief.z8 │ ├── tw-rewardsSparse_goalNone.z8 │ ├── tw-rewardsSparse_goalBrief.z8 │ ├── tw-rewardsBalanced_goalBrief.z8 │ ├── tw-rewardsDense_goalDetailed.z8 │ ├── tw-rewardsSparse_goalDetailed.z8 │ └── tw-rewardsBalanced_goalDetailed.z8 └── make_games.sh ├── docs ├── requirements.txt ├── source │ ├── notes │ │ ├── images │ │ │ ├── TextWorld.png │ │ │ ├── zork1_frotz.png │ │ │ └── zork1_textworld.png │ │ ├── troubleshoot.rst │ │ ├── framework.rst │ │ └── zork1.md │ ├── textworld.gym.core.rst │ ├── textworld.envs.tw.rst │ ├── textworld.generator.game.rst │ ├── textworld.utils.rst │ ├── tw-make.rst │ ├── tw-play.rst │ ├── tw-view.rst │ ├── textworld.generator.maker.rst │ ├── tw-extract.rst │ ├── textworld.challenges.rst │ ├── textworld.gym.spaces.rst │ ├── textworld.rst │ ├── textworld.envs.glulx.rst │ ├── textworld.generator.world.rst │ ├── textworld.envs.zmachine.rst │ ├── textworld.generator.grammar.rst │ ├── textworld.generator.inform7.rst │ ├── textworld.envs.rst │ ├── textworld.challenges.cooking.rst │ ├── textworld.challenges.simple.rst │ ├── textworld.challenges.coin_collector.rst │ ├── textworld.challenges.treasure_hunter.rst │ ├── textworld.gym.rst │ ├── textworld.logic.rst │ ├── textworld.render.rst │ ├── textworld.gym.envs.rst │ ├── textworld.envs.wrappers.rst │ ├── textworld.agents.rst │ ├── Makefile │ ├── textworld.generator.rst │ ├── index.rst │ └── textworld.generator.data.rst ├── Makefile └── make.bat ├── docker ├── run-documentation.sh ├── run-tests.sh ├── Dockerfile └── README.md ├── requirements-vis.txt ├── requirements.txt ├── .azure └── pipelines │ ├── security.yml │ ├── release.yml │ ├── tests.yml │ ├── prerelease.yml │ ├── macos-template.yml │ └── linux-template.yml ├── tools ├── package-impl.sh ├── prep-release.sh └── package.sh ├── .gitignore ├── requirements-full.txt ├── .github └── workflows │ ├── pep8.yml │ └── test_pypi.yml ├── .readthedocs.yaml ├── tox.ini ├── glk_build.py ├── .codecov.yml ├── CONTRIBUTING.md ├── TODO.md ├── scripts ├── tw-data ├── tw-view ├── check_generated_games.py └── tw-stats ├── tests ├── test_check_generated_games.py ├── test_sample_quests.py ├── test_tw-play.py └── test_make_game.py ├── benchmark └── agent_template.py ├── MANIFEST.in ├── LICENSE.txt ├── pyproject.toml └── setup.py /textworld/envs/glulx/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /textworld/envs/zmachine/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /textworld/challenges/tw_simple/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /misc/vscode/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.vsix -------------------------------------------------------------------------------- /textworld/version.py: -------------------------------------------------------------------------------- 1 | __version__ = '1.6.2' 2 | -------------------------------------------------------------------------------- /textworld/challenges/tw_coin_collector/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /textworld/challenges/tw_treasure_hunter/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.pyc 3 | -------------------------------------------------------------------------------- /misc/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/misc/logo.png -------------------------------------------------------------------------------- /textworld/envs/pddl/__init__.py: -------------------------------------------------------------------------------- 1 | from textworld.envs.pddl.pddl import PddlEnv 2 | -------------------------------------------------------------------------------- /requirements-pddl.txt: -------------------------------------------------------------------------------- 1 | # For using PddlEnv (needed for ALFWorld) 2 | fast-downward-textworld 3 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/user_agent.py: -------------------------------------------------------------------------------- 1 | def evaluate(words): 2 | return ('n', False) 3 | -------------------------------------------------------------------------------- /misc/vscode/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | .gitignore 4 | vsc-extension-quickstart.md 5 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/cheapglk/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | Make.* 4 | .idea/* 5 | cmake-build-debug/* -------------------------------------------------------------------------------- /misc/vscode/.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behavior to automatically normalize line endings. 2 | * text=auto 3 | 4 | -------------------------------------------------------------------------------- /notebooks/figs/neural_agent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/notebooks/figs/neural_agent.png -------------------------------------------------------------------------------- /notebooks/games/tw-another_game.z8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/notebooks/games/tw-another_game.z8 -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx>=2,<=5.1.1 2 | recommonmark 3 | sphinx_autodoc_typehints 4 | sphinx-argparse 5 | sphinx-rtd-theme 6 | -------------------------------------------------------------------------------- /docs/source/notes/images/TextWorld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/docs/source/notes/images/TextWorld.png -------------------------------------------------------------------------------- /docs/source/notes/images/zork1_frotz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/docs/source/notes/images/zork1_frotz.png -------------------------------------------------------------------------------- /docs/source/notes/images/zork1_textworld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/docs/source/notes/images/zork1_textworld.png -------------------------------------------------------------------------------- /notebooks/games/tw-rewardsDense_goalBrief.z8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/notebooks/games/tw-rewardsDense_goalBrief.z8 -------------------------------------------------------------------------------- /notebooks/games/tw-rewardsSparse_goalNone.z8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/notebooks/games/tw-rewardsSparse_goalNone.z8 -------------------------------------------------------------------------------- /notebooks/games/tw-rewardsSparse_goalBrief.z8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/notebooks/games/tw-rewardsSparse_goalBrief.z8 -------------------------------------------------------------------------------- /notebooks/games/tw-rewardsBalanced_goalBrief.z8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/notebooks/games/tw-rewardsBalanced_goalBrief.z8 -------------------------------------------------------------------------------- /notebooks/games/tw-rewardsDense_goalDetailed.z8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/notebooks/games/tw-rewardsDense_goalDetailed.z8 -------------------------------------------------------------------------------- /notebooks/games/tw-rewardsSparse_goalDetailed.z8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/notebooks/games/tw-rewardsSparse_goalDetailed.z8 -------------------------------------------------------------------------------- /textworld/gym/__init__.py: -------------------------------------------------------------------------------- 1 | from textworld.gym.utils import register_game, register_games, make, registry 2 | from textworld.gym.core import Agent 3 | -------------------------------------------------------------------------------- /notebooks/games/tw-rewardsBalanced_goalDetailed.z8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/notebooks/games/tw-rewardsBalanced_goalDetailed.z8 -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/help/about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/thirdparty/glulx/Git-Glulx/help/about.png -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/help/fixed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/thirdparty/glulx/Git-Glulx/help/fixed.png -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/help/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/thirdparty/glulx/Git-Glulx/help/help.png -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/help/prop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/thirdparty/glulx/Git-Glulx/help/prop.png -------------------------------------------------------------------------------- /misc/vscode/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to the "textworld-vscode" extension will be documented in this file. 3 | 4 | ## [0.1.0] 5 | - Beta -------------------------------------------------------------------------------- /textworld/gym/envs/__init__.py: -------------------------------------------------------------------------------- 1 | from textworld.gym.envs.textworld import TextworldGymEnv 2 | from textworld.gym.envs.textworld_batch import TextworldBatchGymEnv 3 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/help/credits.htm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/thirdparty/glulx/Git-Glulx/help/credits.htm -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/help/options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/thirdparty/glulx/Git-Glulx/help/options.png -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/help/scroll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/thirdparty/glulx/Git-Glulx/help/scroll.png -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/win/res/Blorb.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/thirdparty/glulx/Git-Glulx/win/res/Blorb.ico -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/win/res/Glulx.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/thirdparty/glulx/Git-Glulx/win/res/Glulx.ico -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/win/res/Ulx.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/thirdparty/glulx/Git-Glulx/win/res/Ulx.ico -------------------------------------------------------------------------------- /docs/source/textworld.gym.core.rst: -------------------------------------------------------------------------------- 1 | Agent 2 | ===== 3 | 4 | .. autoclass:: textworld.gym.core.Agent 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: -------------------------------------------------------------------------------- /docs/source/textworld.envs.tw.rst: -------------------------------------------------------------------------------- 1 | TextWorld 2 | ========= 3 | 4 | .. automodule:: textworld.envs.tw 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Door.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Door.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Food.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Food.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Key.png -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/version.h: -------------------------------------------------------------------------------- 1 | // Automatically generated file -- do not edit! 2 | #define GIT_MAJOR 1 3 | #define GIT_MINOR 3 4 | #define GIT_PATCH 5 5 | -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Cooked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Cooked.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Fixed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Fixed.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Locked.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Object.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Object.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Player.png -------------------------------------------------------------------------------- /docs/source/textworld.generator.game.rst: -------------------------------------------------------------------------------- 1 | Game 2 | ==== 3 | 4 | .. automodule:: textworld.generator.game 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | -------------------------------------------------------------------------------- /docs/source/textworld.utils.rst: -------------------------------------------------------------------------------- 1 | textworld.utils 2 | ================ 3 | 4 | .. automodule:: textworld.utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/tw-make.rst: -------------------------------------------------------------------------------- 1 | tw-make 2 | ======= 3 | 4 | .. argparse:: 5 | :filename: ../../scripts/tw-make 6 | :func: build_parser 7 | :prog: tw-make 8 | :markdownhelp: 9 | -------------------------------------------------------------------------------- /docs/source/tw-play.rst: -------------------------------------------------------------------------------- 1 | tw-play 2 | ======= 3 | 4 | .. argparse:: 5 | :filename: ../../scripts/tw-play 6 | :func: build_parser 7 | :prog: tw-play 8 | :markdownhelp: 9 | -------------------------------------------------------------------------------- /docs/source/tw-view.rst: -------------------------------------------------------------------------------- 1 | tw-view 2 | ======= 3 | 4 | .. argparse:: 5 | :filename: ../../scripts/tw-view 6 | :func: build_parser 7 | :prog: tw-view 8 | :markdownhelp: 9 | -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Chevron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Chevron.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Container.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Container.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_DoorOpen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_DoorOpen.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_LightOff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_LightOff.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_LightOn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_LightOn.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Portable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Portable.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Supporter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Supporter.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Uncooked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Uncooked.png -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_Unlocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_Unlocked.png -------------------------------------------------------------------------------- /docker/run-documentation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | pip3 install -e . 6 | 7 | pushd docs 8 | pip3 install -r requirements.txt || true 9 | make html 10 | popd 11 | -------------------------------------------------------------------------------- /docs/source/textworld.generator.maker.rst: -------------------------------------------------------------------------------- 1 | GameMaker 2 | ========= 3 | 4 | .. automodule:: textworld.generator.maker 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /textworld/render/tmpl/static/images/TextWorldIcons_ContainerOpen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/TextWorld/HEAD/textworld/render/tmpl/static/images/TextWorldIcons_ContainerOpen.png -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd ../cheapglk && make -j16 && cd ../Git-Glulx && make -j16 && PYTHONPATH=. ./git-glulx ../Sherbrooke/textworld/games/test.ulx 3 | -------------------------------------------------------------------------------- /docs/source/tw-extract.rst: -------------------------------------------------------------------------------- 1 | tw-extract 2 | ========== 3 | 4 | .. argparse:: 5 | :filename: ../../scripts/tw-extract 6 | :func: build_parser 7 | :prog: tw-extract 8 | :markdownhelp: 9 | -------------------------------------------------------------------------------- /docs/source/notes/troubleshoot.rst: -------------------------------------------------------------------------------- 1 | Known Issues 2 | ============ 3 | 4 | Inform 7 5 | -------- 6 | Inform 7 command line tools don't support Windows Linux Subsystem (a.k.a Bash on Ubuntu on Windows). 7 | 8 | -------------------------------------------------------------------------------- /requirements-vis.txt: -------------------------------------------------------------------------------- 1 | # For visualization 2 | pybars3>=0.9.3 3 | flask>=1.0.2 4 | selenium>=3.12.0,<4.3 5 | greenlet>=0.4.13 6 | gevent>=1.3.5 7 | pillow>=5.1.0 8 | plotly>=4.0.0,<6.0.0 9 | pydot>=1.2.4 10 | psutil 11 | matplotlib 12 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/help/Git.css: -------------------------------------------------------------------------------- 1 | body { font-family:verdana;font-size:8pt } 2 | td { font-family:verdana;font-size:8pt } 3 | h1 { font-size:12pt } 4 | h2 { font-size:10pt } 5 | ul { margin-left:16pt;margin-top:2pt } 6 | 7 | -------------------------------------------------------------------------------- /docker/run-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | export PATH=$PWD/glulx/Git-Glulx:$PATH 6 | 7 | pip3 install -v . 8 | pip3 install nose coverage 9 | nosetests -sv --with-xunit --with-coverage --cover-xml --cover-html --cover-package textworld -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Main dependencies 2 | numpy>=1.14.5 3 | tqdm>=4.17.1 4 | cffi>=1.0.0 5 | networkx>=2 6 | more_itertools 7 | tatsu==5.8.3 8 | hashids>=1.2.0 9 | jericho>=3.3.0 10 | mementos>=1.3.1 11 | termcolor 12 | 13 | # For advanced prompt 14 | prompt_toolkit 15 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/textworld_data/logic/pot.twl: -------------------------------------------------------------------------------- 1 | ## pot 2 | #type pot : box { 3 | # 4 | # inform7 { 5 | # type { 6 | # kind :: "pot-like"; 7 | # definition :: "pot-like is a kind of box-like."; 8 | # } 9 | # 10 | # } 11 | #} 12 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/textworld_data/logic_drop/pot.twl: -------------------------------------------------------------------------------- 1 | ## pot 2 | #type pot : box { 3 | # 4 | # inform7 { 5 | # type { 6 | # kind :: "pot-like"; 7 | # definition :: "pot-like is a kind of box-like."; 8 | # } 9 | # 10 | # } 11 | #} 12 | -------------------------------------------------------------------------------- /docs/source/textworld.challenges.rst: -------------------------------------------------------------------------------- 1 | textworld.challenges 2 | ==================== 3 | 4 | .. toctree:: 5 | :maxdepth: 1 6 | 7 | textworld.challenges.simple 8 | textworld.challenges.coin_collector 9 | textworld.challenges.cooking 10 | textworld.challenges.treasure_hunter 11 | -------------------------------------------------------------------------------- /docs/source/textworld.gym.spaces.rst: -------------------------------------------------------------------------------- 1 | Spaces 2 | ====== 3 | 4 | .. automodule:: textworld.gym.spaces 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: textworld.gym.spaces.text_spaces 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | -------------------------------------------------------------------------------- /docs/source/textworld.rst: -------------------------------------------------------------------------------- 1 | textworld 2 | ========= 3 | 4 | .. automodule:: textworld 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | 10 | Core 11 | ---- 12 | 13 | .. automodule:: textworld.core 14 | :members: 15 | :undoc-members: 16 | :show-inheritance: 17 | -------------------------------------------------------------------------------- /docs/source/textworld.envs.glulx.rst: -------------------------------------------------------------------------------- 1 | Glulx 2 | ===== 3 | 4 | .. automodule:: textworld.envs.glulx 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: textworld.envs.glulx.git_glulx 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | -------------------------------------------------------------------------------- /docs/source/textworld.generator.world.rst: -------------------------------------------------------------------------------- 1 | World 2 | ===== 3 | 4 | .. automodule:: textworld.generator.world 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: textworld.generator.graph_networks 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | -------------------------------------------------------------------------------- /docs/source/textworld.envs.zmachine.rst: -------------------------------------------------------------------------------- 1 | Z-Machine 2 | ========= 3 | 4 | .. automodule:: textworld.envs.zmachine 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: textworld.envs.zmachine.jericho 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | -------------------------------------------------------------------------------- /docs/source/textworld.generator.grammar.rst: -------------------------------------------------------------------------------- 1 | Grammar 2 | ======= 3 | 4 | .. automodule:: textworld.generator.text_generation 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: textworld.generator.text_grammar 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | -------------------------------------------------------------------------------- /docs/source/textworld.generator.inform7.rst: -------------------------------------------------------------------------------- 1 | Inform 7 2 | ======== 3 | 4 | .. automodule:: textworld.generator.inform7 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: textworld.generator.inform7.world2inform7 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | -------------------------------------------------------------------------------- /docs/source/textworld.envs.rst: -------------------------------------------------------------------------------- 1 | textworld.envs 2 | ============== 3 | 4 | .. automodule:: textworld.envs 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. toctree:: 10 | 11 | textworld.envs.tw 12 | textworld.envs.glulx 13 | textworld.envs.wrappers 14 | textworld.envs.zmachine 15 | 16 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/win/git.rc: -------------------------------------------------------------------------------- 1 | 100 ICON DISCARDABLE "win/res/Glulx.ico" 2 | 101 ICON DISCARDABLE "win/res/Blorb.ico" 3 | 102 ICON DISCARDABLE "win/res/Ulx.ico" 4 | 5 | 1 24 "win/res/Git.manifest" 6 | 7 | -------------------------------------------------------------------------------- /textworld/generator/data/logic/player.twl: -------------------------------------------------------------------------------- 1 | # Player 2 | type P { 3 | rules { 4 | look :: at(P, r) -> at(P, r); # Nothing changes. 5 | } 6 | 7 | reverse_rules { 8 | look :: look; 9 | } 10 | 11 | inform7 { 12 | commands { 13 | look :: "look" :: "looking"; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.azure/pipelines/security.yml: -------------------------------------------------------------------------------- 1 | # Run the Component Governance Detection task 2 | 3 | trigger: 4 | - main 5 | 6 | pool: 7 | vmImage: 'ubuntu-latest' 8 | 9 | steps: 10 | - task: ComponentGovernanceComponentDetection@0 11 | inputs: 12 | scanType: 'Register' 13 | verbosity: 'Verbose' 14 | alertWarningLevel: 'High' 15 | failOnAlert: true -------------------------------------------------------------------------------- /docs/source/textworld.challenges.cooking.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: textworld.challenges.cooking 2 | :members: 3 | :undoc-members: 4 | :show-inheritance: 5 | 6 | Usage 7 | ----- 8 | .. argparse:: 9 | :ref: textworld.challenges.tw_cooking.cooking.build_argparser 10 | :prog: tw-make tw-cooking 11 | :markdownhelp: 12 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile to call the Makefile found in the source folder. 2 | # 3 | 4 | # Put it first so that "make" without argument is like "make help". 5 | help: 6 | $(MAKE) -C source/ help 7 | 8 | .PHONY: help Makefile 9 | 10 | # Catch-all target: route all targets to the Makefile in the source folder. 11 | %: Makefile 12 | $(MAKE) -C source/ $@ -------------------------------------------------------------------------------- /docs/source/textworld.challenges.simple.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | .. automodule:: textworld.challenges.simple 4 | :members: 5 | :undoc-members: 6 | :show-inheritance: 7 | 8 | Usage 9 | ----- 10 | .. argparse:: 11 | :ref: textworld.challenges.tw_simple.simple.build_argparser 12 | :prog: tw-make tw-simple 13 | :markdownhelp: 14 | -------------------------------------------------------------------------------- /textworld/agents/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | 5 | from textworld.agents.random import RandomCommandAgent 6 | from textworld.agents.simple import NaiveAgent 7 | from textworld.agents.human import HumanAgent 8 | from textworld.agents.walkthrough import WalkthroughAgent, WalkthroughDone 9 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/textworld_data/logic/player.twl: -------------------------------------------------------------------------------- 1 | # Player 2 | type P { 3 | rules { 4 | look :: at(P, r) -> at(P, r); # Nothing changes. 5 | } 6 | 7 | reverse_rules { 8 | look :: look; 9 | } 10 | 11 | inform7 { 12 | commands { 13 | look :: "look" :: "looking"; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /textworld/challenges/tw_simple/textworld_data/logic/player.twl: -------------------------------------------------------------------------------- 1 | # Player 2 | type P { 3 | rules { 4 | look :: at(P, r) -> at(P, r); # Nothing changes. 5 | } 6 | 7 | reverse_rules { 8 | look :: look; 9 | } 10 | 11 | inform7 { 12 | commands { 13 | look :: "look" :: "looking"; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /textworld/challenges/tw_coin_collector/textworld_data/logic/player.twl: -------------------------------------------------------------------------------- 1 | # Player 2 | type P { 3 | rules { 4 | look :: at(P, r) -> at(P, r); # Nothing changes. 5 | } 6 | 7 | reverse_rules { 8 | look :: look; 9 | } 10 | 11 | inform7 { 12 | commands { 13 | look :: "look" :: "looking"; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /textworld/challenges/tw_treasure_hunter/textworld_data/logic/player.twl: -------------------------------------------------------------------------------- 1 | # Player 2 | type P { 3 | rules { 4 | look :: at(P, r) -> at(P, r); # Nothing changes. 5 | } 6 | 7 | reverse_rules { 8 | look :: look; 9 | } 10 | 11 | inform7 { 12 | commands { 13 | look :: "look" :: "looking"; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /textworld/render/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | 5 | from textworld.render.render import WebdriverNotFoundError 6 | from textworld.render.render import get_webdriver 7 | from textworld.render.render import load_state, load_state_from_game_state, visualize 8 | from textworld.render.graph import show_graph 9 | -------------------------------------------------------------------------------- /docs/source/textworld.challenges.coin_collector.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: textworld.challenges.coin_collector 2 | :members: 3 | :undoc-members: 4 | :show-inheritance: 5 | 6 | Usage 7 | ----- 8 | .. argparse:: 9 | :ref: textworld.challenges.tw_coin_collector.coin_collector.build_argparser 10 | :prog: tw-make tw-coin_collector 11 | :markdownhelp: 12 | -------------------------------------------------------------------------------- /docs/source/textworld.challenges.treasure_hunter.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: textworld.challenges.treasure_hunter 2 | :members: 3 | :undoc-members: 4 | :show-inheritance: 5 | 6 | Usage 7 | ----- 8 | .. argparse:: 9 | :ref: textworld.challenges.tw_treasure_hunter.treasure_hunter.build_argparser 10 | :prog: tw-make tw-treasure_hunter 11 | :markdownhelp: 12 | -------------------------------------------------------------------------------- /textworld/generator/data/logic/supporter.twl: -------------------------------------------------------------------------------- 1 | # supporter 2 | type s : t { 3 | predicates { 4 | on(o, s); 5 | } 6 | 7 | inform7 { 8 | type { 9 | kind :: "supporter"; 10 | definition :: "supporters are fixed in place."; 11 | } 12 | 13 | predicates { 14 | on(o, s) :: "The {o} is on the {s}"; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /textworld/challenges/tw_coin_collector/textworld_data/logic/object.twl: -------------------------------------------------------------------------------- 1 | # object 2 | type o : t { 3 | constraints { 4 | obj1 :: in(o, I) & at(o, r) -> fail(); 5 | obj2 :: at(o, r) & at(o, r') -> fail(); 6 | } 7 | 8 | inform7 { 9 | type { 10 | kind :: "object-like"; 11 | definition :: "object-like is portable."; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tools/package-impl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Based on https://github.com/pypa/python-manylinux-demo/blob/master/travis/build-wheels.sh 4 | 5 | set -e 6 | 7 | cd /usr/src/TextWorld 8 | 9 | for PYTHON in /opt/python/cp3{6,7,8,9}*/bin/python; do 10 | $PYTHON setup.py bdist_wheel -d wheelhouse 11 | done 12 | 13 | for WHEEL in wheelhouse/textworld-*.whl; do 14 | auditwheel repair $WHEEL -w dist 15 | done 16 | -------------------------------------------------------------------------------- /docs/source/textworld.gym.rst: -------------------------------------------------------------------------------- 1 | textworld.gym 2 | ============== 3 | 4 | .. automodule:: textworld.gym 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: textworld.gym.utils 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | 15 | .. toctree:: 16 | :hidden: 17 | 18 | textworld.gym.core 19 | textworld.gym.envs 20 | textworld.gym.spaces 21 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/textworld_data/logic/supporter.twl: -------------------------------------------------------------------------------- 1 | # supporter 2 | type s : t { 3 | predicates { 4 | on(o, s); 5 | } 6 | 7 | inform7 { 8 | type { 9 | kind :: "supporter"; 10 | definition :: "supporters are fixed in place."; 11 | } 12 | 13 | predicates { 14 | on(o, s) :: "The {o} is on the {s}"; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /textworld/challenges/tw_simple/textworld_data/logic/supporter.twl: -------------------------------------------------------------------------------- 1 | # supporter 2 | type s : t { 3 | predicates { 4 | on(o, s); 5 | } 6 | 7 | inform7 { 8 | type { 9 | kind :: "supporter"; 10 | definition :: "supporters are fixed in place."; 11 | } 12 | 13 | predicates { 14 | on(o, s) :: "The {o} is on the {s}"; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/source/textworld.logic.rst: -------------------------------------------------------------------------------- 1 | textworld.logic 2 | =============== 3 | 4 | .. automodule:: textworld.logic 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: textworld.logic.model 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. automodule:: textworld.logic.parser 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | 20 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/textworld_data/logic_drop/supporter.twl: -------------------------------------------------------------------------------- 1 | # supporter 2 | type s : t { 3 | predicates { 4 | on(o, s); 5 | } 6 | 7 | inform7 { 8 | type { 9 | kind :: "supporter"; 10 | definition :: "supporters are fixed in place."; 11 | } 12 | 13 | predicates { 14 | on(o, s) :: "The {o} is on the {s}"; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /textworld/challenges/tw_treasure_hunter/textworld_data/logic/supporter.twl: -------------------------------------------------------------------------------- 1 | # supporter 2 | type s : t { 3 | predicates { 4 | on(o, s); 5 | } 6 | 7 | inform7 { 8 | type { 9 | kind :: "supporter"; 10 | definition :: "supporters are fixed in place."; 11 | } 12 | 13 | predicates { 14 | on(o, s) :: "The {o} is on the {s}"; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/source/textworld.render.rst: -------------------------------------------------------------------------------- 1 | textworld.render 2 | ================ 3 | 4 | .. automodule:: textworld.render 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: textworld.render.render 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. automodule:: textworld.render.serve 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | 20 | -------------------------------------------------------------------------------- /textworld/envs/wrappers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | 5 | from textworld.envs.wrappers.recorder import Recorder 6 | from textworld.envs.wrappers.filter import Filter 7 | from textworld.envs.wrappers.limit import Limit 8 | from textworld.envs.wrappers.tw_inform7 import TWInform7 9 | from textworld.envs.wrappers.generic import GenericEnvironment 10 | -------------------------------------------------------------------------------- /textworld/challenges/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | from textworld.challenges.registration import register, CHALLENGES 5 | from textworld.challenges.tw_coin_collector import coin_collector 6 | from textworld.challenges.tw_treasure_hunter import treasure_hunter 7 | from textworld.challenges.tw_simple import simple 8 | from textworld.challenges.tw_cooking import cooking 9 | -------------------------------------------------------------------------------- /textworld/generator/data/logic/thing.twl: -------------------------------------------------------------------------------- 1 | # thing 2 | type t { 3 | rules { 4 | examine/t :: at(P, r) & $at(t, r) -> at(P, r); 5 | } 6 | 7 | reverse_rules { 8 | examine/t :: examine/t; 9 | } 10 | 11 | inform7 { 12 | type { 13 | kind :: "thing"; 14 | } 15 | 16 | commands { 17 | examine/t :: "examine {t}" :: "examining the {t}"; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | *.pyc 3 | *.so 4 | *.egg* 5 | *.z? 6 | *.ulx 7 | *.ni 8 | *.iml 9 | **/.idea/* 10 | **/cmake-build-debug/* 11 | .tox/ 12 | .vs/* 13 | **git-glulx-ml 14 | *.sublime-* 15 | build/* 16 | gen_games*/ 17 | experiments*/ 18 | /textworld/thirdparty/inform7-6M62 19 | gameinfo.dbg 20 | textworld_data/ 21 | Inform/ 22 | I7_6M62_Linux_all.tar.gz 23 | tmp/* 24 | *.ipynb_checkpoints 25 | /dist 26 | /wheelhouse 27 | docs/build 28 | docs/src 29 | -------------------------------------------------------------------------------- /textworld/generator/inform7/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | 5 | from textworld.generator.inform7.world2inform7 import Inform7Game 6 | from textworld.generator.inform7.world2inform7 import generate_inform7_source 7 | from textworld.generator.inform7.world2inform7 import compile_inform7_game 8 | from textworld.generator.inform7.world2inform7 import CouldNotCompileGameError 9 | -------------------------------------------------------------------------------- /textworld/challenges/tw_simple/textworld_data/logic/thing.twl: -------------------------------------------------------------------------------- 1 | # thing 2 | type t { 3 | rules { 4 | examine/t :: at(P, r) & $at(t, r) -> at(P, r); 5 | } 6 | 7 | reverse_rules { 8 | examine/t :: examine/t; 9 | } 10 | 11 | inform7 { 12 | type { 13 | kind :: "thing"; 14 | } 15 | 16 | commands { 17 | examine/t :: "examine {t}" :: "examining the {t}"; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /textworld/challenges/tw_coin_collector/textworld_data/logic/thing.twl: -------------------------------------------------------------------------------- 1 | # thing 2 | type t { 3 | rules { 4 | examine/t :: at(P, r) & $at(t, r) -> at(P, r); 5 | } 6 | 7 | reverse_rules { 8 | examine/t :: examine/t; 9 | } 10 | 11 | inform7 { 12 | type { 13 | kind :: "thing"; 14 | } 15 | 16 | commands { 17 | examine/t :: "examine {t}" :: "examining the {t}"; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/textworld_data/logic_drop/player.twl: -------------------------------------------------------------------------------- 1 | # Player 2 | type P { 3 | rules { 4 | look :: at(P, r) -> at(P, r); # Nothing changes. 5 | } 6 | 7 | reverse_rules { 8 | look :: look; 9 | } 10 | 11 | inform7 { 12 | commands { 13 | look :: "look" :: "looking"; 14 | } 15 | 16 | code :: """ 17 | The carrying capacity of the player is 0. 18 | """; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /textworld/challenges/tw_treasure_hunter/textworld_data/logic/thing.twl: -------------------------------------------------------------------------------- 1 | # thing 2 | type t { 3 | rules { 4 | examine/t :: at(P, r) & $at(t, r) -> at(P, r); 5 | } 6 | 7 | reverse_rules { 8 | examine/t :: examine/t; 9 | } 10 | 11 | inform7 { 12 | type { 13 | kind :: "thing"; 14 | } 15 | 16 | commands { 17 | examine/t :: "examine {t}" :: "examining the {t}"; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/help/Git.hhp: -------------------------------------------------------------------------------- 1 | [OPTIONS] 2 | Compatibility=1.1 or later 3 | Compiled file=Git.chm 4 | Contents file=Git.hhc 5 | Default Window=help 6 | Default topic=overview.htm 7 | Display compile progress=No 8 | Full-text search=Yes 9 | Language=0x809 English (United Kingdom) 10 | Title=Windows Git 11 | 12 | [WINDOWS] 13 | help=,"Git.hhc",,"overview.htm",,,,,,0x42520,,0x3006,[600,32,1200,632],,,,,,,0 14 | 15 | 16 | [FILES] 17 | overview.htm 18 | 19 | [INFOTYPES] 20 | 21 | -------------------------------------------------------------------------------- /docs/source/notes/framework.rst: -------------------------------------------------------------------------------- 1 | What is TextWorld? 2 | ================== 3 | 4 | TextWorld is a sandbox learning environment for training and testing reinforcement learning (RL) agents on text-based games. It enables generating games from a game distribution parameterized by the map size, the number of objects, quest length and complexity, richness of text descriptions, and more. Then, one can sample game from that distribution. TextWorld can also be used to play existing text-based games. 5 | 6 | .. image:: ./images/TextWorld.png 7 | -------------------------------------------------------------------------------- /docs/source/textworld.gym.envs.rst: -------------------------------------------------------------------------------- 1 | Envs 2 | ==== 3 | 4 | .. automodule:: textworld.gym.envs 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: textworld.gym.envs.textworld 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. automodule:: textworld.gym.envs.textworld_batch 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | .. automodule:: textworld.gym.envs.utils 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/README.md: -------------------------------------------------------------------------------- 1 | # Making First TextWorld Problem games 2 | 3 | ## Prerequisite 4 | 5 | - TextWorld 6 | 7 | The development branch of TextWorld can be installed using 8 | 9 | pip install https://github.com/Microsoft/TextWorld/archive/main.zip 10 | 11 | ## Usage 12 | 13 | Generating a First TextWorld Problem game is done using `tw-make` as follows 14 | 15 | tw-make tw-cooking --output tw_games/game.z8 16 | 17 | To list available settings that control the games difficulty 18 | 19 | tw-make tw-cooking --help 20 | -------------------------------------------------------------------------------- /docs/source/textworld.envs.wrappers.rst: -------------------------------------------------------------------------------- 1 | Wrappers 2 | ======== 3 | 4 | .. automodule:: textworld.envs.wrappers 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: textworld.envs.wrappers.recorder 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. automodule:: textworld.envs.wrappers.viewer 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | .. automodule:: textworld.envs.wrappers.filter 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /requirements-full.txt: -------------------------------------------------------------------------------- 1 | # Main dependencies 2 | numpy>=1.14.5 3 | tqdm>=4.17.1 4 | cffi>=1.0.0 5 | networkx>=2 6 | more_itertools 7 | tatsu==5.8.3 8 | hashids>=1.2.0 9 | jericho>=2.2.0 10 | mementos>=1.3.1 11 | termcolor 12 | 13 | # For advanced prompt 14 | prompt_toolkit 15 | 16 | # For visualization 17 | pybars3>=0.9.3 18 | flask>=1.0.2 19 | selenium>=3.12.0,<4.3 20 | greenlet>=0.4.13 21 | gevent>=1.3.5 22 | pillow>=5.1.0 23 | plotly>=4.0.0,<6.0.0 24 | pydot>=1.2.4 25 | psutil 26 | matplotlib 27 | 28 | # For using PddlEnv (needed for ALFWorld) 29 | fast-downward-textworld 30 | -------------------------------------------------------------------------------- /.github/workflows/pep8.yml: -------------------------------------------------------------------------------- 1 | name: PEP8 2 | on: [pull_request] 3 | jobs: 4 | run: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@master 8 | - name: Setup Python 3.7 9 | uses: actions/setup-python@master 10 | with: 11 | version: 3.7 12 | - name: flake8 13 | run: | 14 | pip install flake8 15 | # stop the build if there are Python syntax errors or undefined names 16 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 17 | # The GitHub editor is 127 chars wide 18 | flake8 . --count --max-complexity=10 --max-line-length=127 --statistics 19 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file 2 | 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | version: 2 6 | 7 | # Set the version of Python and other tools you might need 8 | build: 9 | os: ubuntu-22.04 10 | tools: 11 | python: "3.9" 12 | 13 | # Build documentation in the docs/ directory with Sphinx 14 | sphinx: 15 | configuration: docs/source/conf.py 16 | 17 | # Optionally declare the Python requirements required to build your docs 18 | python: 19 | install: 20 | - requirements: docs/requirements.txt 21 | - requirements: requirements.txt 22 | - method: pip 23 | path: . 24 | -------------------------------------------------------------------------------- /misc/vscode/README.md: -------------------------------------------------------------------------------- 1 | # Editing TextWorld in Visual Studio Code 2 | 3 | This extension enables syntax highlighting when editing `.twl` and `.twg` [TextWorld](https://aka.ms/textworld) files. 4 | 5 | ## Examples 6 | 7 | ### TextWorld Logic file (.twl) 8 | 9 | ![image](https://user-images.githubusercontent.com/660004/63561277-527f9480-c527-11e9-85f5-5a839b8f9ba7.png) 10 | 11 | ### TextWorld Grammar file (.twg) 12 | 13 | ![image](https://user-images.githubusercontent.com/660004/63561961-d0449f80-c529-11e9-920f-7ae74f91a232.png) 14 | 15 | ## Release Notes 16 | 17 | ### 0.1.0 18 | 19 | (Beta) Provide syntax highlighting for `.twl` and `.twg` files. 20 | -------------------------------------------------------------------------------- /textworld/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | import warnings 5 | 6 | from textworld.version import __version__ 7 | from textworld.utils import g_rng 8 | 9 | from textworld.core import EnvInfos, EnvInfoMissingError 10 | from textworld.core import Environment, GameState, Agent 11 | from textworld.generator import Game, GameMaker, GameOptions 12 | 13 | from textworld.generator import GenerationWarning 14 | 15 | from textworld.helpers import make, play, start 16 | 17 | # By default disable warning related to game generation. 18 | warnings.simplefilter("ignore", GenerationWarning) 19 | -------------------------------------------------------------------------------- /docs/source/textworld.agents.rst: -------------------------------------------------------------------------------- 1 | textworld.agents 2 | ================ 3 | 4 | .. automodule:: textworld.agents 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: textworld.agents.human 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. automodule:: textworld.agents.random 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | .. automodule:: textworld.agents.simple 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | 24 | .. automodule:: textworld.agents.walkthrough 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | 29 | 30 | -------------------------------------------------------------------------------- /misc/vscode/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that launches the extension inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ] 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /docs/source/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = TextWorld 8 | SOURCEDIR = . 9 | BUILDDIR = ../build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /textworld/generator/data/logic/key.twl: -------------------------------------------------------------------------------- 1 | # key 2 | type k : o { 3 | predicates { 4 | match(k, c); 5 | match(k, d); 6 | } 7 | 8 | constraints { 9 | k1 :: match(k, c) & match(k', c) -> fail(); 10 | k2 :: match(k, c) & match(k, c') -> fail(); 11 | k3 :: match(k, d) & match(k', d) -> fail(); 12 | k4 :: match(k, d) & match(k, d') -> fail(); 13 | } 14 | 15 | inform7 { 16 | type { 17 | kind :: "key"; 18 | } 19 | 20 | predicates { 21 | match(k, c) :: "The matching key of the {c} is the {k}"; 22 | match(k, d) :: "The matching key of the {d} is the {k}"; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3-slim 2 | 3 | # Get everything up-to-date 4 | RUN apt-get update 5 | RUN apt-get upgrade -qy 6 | 7 | # Install system dependencies 8 | RUN apt-get install -qy \ 9 | build-essential \ 10 | chromium \ 11 | chromium-driver \ 12 | curl \ 13 | git \ 14 | libffi-dev \ 15 | python3-dev \ 16 | python3-pip \ 17 | wget \ 18 | graphviz 19 | 20 | RUN pip install jupyter 21 | 22 | RUN git clone --single-branch --branch main https://github.com/microsoft/TextWorld.git /TextWorld 23 | RUN pip install /TextWorld[vis] 24 | 25 | # Environment variables 26 | ENV DISPLAY=:99 27 | 28 | CMD ["jupyter", "notebook", "/TextWorld/notebooks", "--ip", "0.0.0.0", "--allow-root"] 29 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/textworld_data/logic/key.twl: -------------------------------------------------------------------------------- 1 | # key 2 | type k : o { 3 | predicates { 4 | match(k, c); 5 | match(k, d); 6 | } 7 | 8 | constraints { 9 | k1 :: match(k, c) & match(k', c) -> fail(); 10 | k2 :: match(k, c) & match(k, c') -> fail(); 11 | k3 :: match(k, d) & match(k', d) -> fail(); 12 | k4 :: match(k, d) & match(k, d') -> fail(); 13 | } 14 | 15 | inform7 { 16 | type { 17 | kind :: "key"; 18 | } 19 | 20 | predicates { 21 | match(k, c) :: "The matching key of the {c} is the {k}"; 22 | match(k, d) :: "The matching key of the {d} is the {k}"; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /textworld/challenges/tw_simple/textworld_data/logic/key.twl: -------------------------------------------------------------------------------- 1 | # key 2 | type k : o { 3 | predicates { 4 | match(k, c); 5 | match(k, d); 6 | } 7 | 8 | constraints { 9 | k1 :: match(k, c) & match(k', c) -> fail(); 10 | k2 :: match(k, c) & match(k, c') -> fail(); 11 | k3 :: match(k, d) & match(k', d) -> fail(); 12 | k4 :: match(k, d) & match(k, d') -> fail(); 13 | } 14 | 15 | inform7 { 16 | type { 17 | kind :: "key"; 18 | } 19 | 20 | predicates { 21 | match(k, c) :: "The matching key of the {c} is the {k}"; 22 | match(k, d) :: "The matching key of the {d} is the {k}"; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/textworld_data/logic_drop/key.twl: -------------------------------------------------------------------------------- 1 | # key 2 | type k : o { 3 | predicates { 4 | match(k, c); 5 | match(k, d); 6 | } 7 | 8 | constraints { 9 | k1 :: match(k, c) & match(k', c) -> fail(); 10 | k2 :: match(k, c) & match(k, c') -> fail(); 11 | k3 :: match(k, d) & match(k', d) -> fail(); 12 | k4 :: match(k, d) & match(k, d') -> fail(); 13 | } 14 | 15 | inform7 { 16 | type { 17 | kind :: "key"; 18 | } 19 | 20 | predicates { 21 | match(k, c) :: "The matching key of the {c} is the {k}"; 22 | match(k, d) :: "The matching key of the {d} is the {k}"; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/cheapglk/cgblorb.c: -------------------------------------------------------------------------------- 1 | #include "glk.h" 2 | #include "gi_blorb.h" 3 | 4 | /* We'd like to be able to deal with game files in Blorb files, even 5 | if we never load a sound or image. We'd also like to be able to 6 | deal with Data chunks. So we're willing to set a map here. */ 7 | 8 | static giblorb_map_t *blorbmap = 0; /* NULL */ 9 | 10 | giblorb_err_t giblorb_set_resource_map(strid_t file) 11 | { 12 | giblorb_err_t err; 13 | 14 | err = giblorb_create_map(file, &blorbmap); 15 | if (err) { 16 | blorbmap = 0; /* NULL */ 17 | return err; 18 | } 19 | 20 | return giblorb_err_None; 21 | } 22 | 23 | giblorb_map_t *giblorb_get_resource_map() 24 | { 25 | return blorbmap; 26 | } 27 | -------------------------------------------------------------------------------- /tools/prep-release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (c) Microsoft Corporation. All rights reserved. 4 | # Licensed under the MIT license. 5 | 6 | set -ex 7 | echo "Preparing for release..."; 8 | 9 | # Generate parsers 10 | tatsu textworld/logic/logic.ebnf -o textworld/logic/parser.py -G textworld/logic/model.py 11 | tatsu textworld/textgen/textgen.ebnf -o textworld/textgen/parser.py -G textworld/textgen/model.py 12 | 13 | # Generate parsers for PddlEnv support 14 | tatsu textworld/envs/pddl/logic/logic.ebnf -o textworld/envs/pddl/logic/parser.py -G textworld/envs/pddl/logic/model.py 15 | tatsu textworld/envs/pddl/textgen/textgen.ebnf -o textworld/envs/pddl/textgen/parser.py -G textworld/envs/pddl/textgen/model.py 16 | -------------------------------------------------------------------------------- /textworld/challenges/tw_treasure_hunter/textworld_data/logic/key.twl: -------------------------------------------------------------------------------- 1 | # key 2 | type k : o { 3 | predicates { 4 | match(k, c); 5 | match(k, d); 6 | } 7 | 8 | constraints { 9 | k1 :: match(k, c) & match(k', c) -> fail(); 10 | k2 :: match(k, c) & match(k, c') -> fail(); 11 | k3 :: match(k, d) & match(k', d) -> fail(); 12 | k4 :: match(k, d) & match(k, d') -> fail(); 13 | } 14 | 15 | inform7 { 16 | type { 17 | kind :: "key"; 18 | } 19 | 20 | predicates { 21 | match(k, c) :: "The matching key of the {c} is the {k}"; 22 | match(k, d) :: "The matching key of the {d} is the {k}"; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /textworld/generator/data/logic/object.twl: -------------------------------------------------------------------------------- 1 | # object 2 | type o : t { 3 | constraints { 4 | obj1 :: in(o, I) & in(o, c) -> fail(); 5 | obj2 :: in(o, I) & on(o, s) -> fail(); 6 | obj3 :: in(o, I) & at(o, r) -> fail(); 7 | obj4 :: in(o, c) & on(o, s) -> fail(); 8 | obj5 :: in(o, c) & at(o, r) -> fail(); 9 | obj6 :: on(o, s) & at(o, r) -> fail(); 10 | obj7 :: at(o, r) & at(o, r') -> fail(); 11 | obj8 :: in(o, c) & in(o, c') -> fail(); 12 | obj9 :: on(o, s) & on(o, s') -> fail(); 13 | } 14 | 15 | inform7 { 16 | type { 17 | kind :: "object-like"; 18 | definition :: "object-like is portable."; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/textworld_data/logic/object.twl: -------------------------------------------------------------------------------- 1 | # object 2 | type o : t { 3 | constraints { 4 | obj1 :: in(o, I) & in(o, c) -> fail(); 5 | obj2 :: in(o, I) & on(o, s) -> fail(); 6 | obj3 :: in(o, I) & at(o, r) -> fail(); 7 | obj4 :: in(o, c) & on(o, s) -> fail(); 8 | obj5 :: in(o, c) & at(o, r) -> fail(); 9 | obj6 :: on(o, s) & at(o, r) -> fail(); 10 | obj7 :: at(o, r) & at(o, r') -> fail(); 11 | obj8 :: in(o, c) & in(o, c') -> fail(); 12 | obj9 :: on(o, s) & on(o, s') -> fail(); 13 | } 14 | 15 | inform7 { 16 | type { 17 | kind :: "object-like"; 18 | definition :: "object-like is portable."; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /textworld/challenges/tw_simple/textworld_data/logic/object.twl: -------------------------------------------------------------------------------- 1 | # object 2 | type o : t { 3 | constraints { 4 | obj1 :: in(o, I) & in(o, c) -> fail(); 5 | obj2 :: in(o, I) & on(o, s) -> fail(); 6 | obj3 :: in(o, I) & at(o, r) -> fail(); 7 | obj4 :: in(o, c) & on(o, s) -> fail(); 8 | obj5 :: in(o, c) & at(o, r) -> fail(); 9 | obj6 :: on(o, s) & at(o, r) -> fail(); 10 | obj7 :: at(o, r) & at(o, r') -> fail(); 11 | obj8 :: in(o, c) & in(o, c') -> fail(); 12 | obj9 :: on(o, s) & on(o, s') -> fail(); 13 | } 14 | 15 | inform7 { 16 | type { 17 | kind :: "object-like"; 18 | definition :: "object-like is portable."; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/textworld_data/logic_drop/object.twl: -------------------------------------------------------------------------------- 1 | # object 2 | type o : t { 3 | constraints { 4 | obj1 :: in(o, I) & in(o, c) -> fail(); 5 | obj2 :: in(o, I) & on(o, s) -> fail(); 6 | obj3 :: in(o, I) & at(o, r) -> fail(); 7 | obj4 :: in(o, c) & on(o, s) -> fail(); 8 | obj5 :: in(o, c) & at(o, r) -> fail(); 9 | obj6 :: on(o, s) & at(o, r) -> fail(); 10 | obj7 :: at(o, r) & at(o, r') -> fail(); 11 | obj8 :: in(o, c) & in(o, c') -> fail(); 12 | obj9 :: on(o, s) & on(o, s') -> fail(); 13 | } 14 | 15 | inform7 { 16 | type { 17 | kind :: "object-like"; 18 | definition :: "object-like is portable."; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /textworld/challenges/tw_treasure_hunter/textworld_data/logic/object.twl: -------------------------------------------------------------------------------- 1 | # object 2 | type o : t { 3 | constraints { 4 | obj1 :: in(o, I) & in(o, c) -> fail(); 5 | obj2 :: in(o, I) & on(o, s) -> fail(); 6 | obj3 :: in(o, I) & at(o, r) -> fail(); 7 | obj4 :: in(o, c) & on(o, s) -> fail(); 8 | obj5 :: in(o, c) & at(o, r) -> fail(); 9 | obj6 :: on(o, s) & at(o, r) -> fail(); 10 | obj7 :: at(o, r) & at(o, r') -> fail(); 11 | obj8 :: in(o, c) & in(o, c') -> fail(); 12 | obj9 :: on(o, s) & on(o, s') -> fail(); 13 | } 14 | 15 | inform7 { 16 | type { 17 | kind :: "object-like"; 18 | definition :: "object-like is portable."; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /textworld/envs/pddl/logic/logic.ebnf: -------------------------------------------------------------------------------- 1 | @@grammar :: PddlLogic 2 | 3 | @@eol_comments :: /#.*?$/ 4 | 5 | start = pddlDocument ; 6 | 7 | str = ?'"[^"]*"' ; 8 | 9 | strBlock = ?'"""(?:.|\n)*?"""' ; 10 | 11 | name = ?"[\w/-]+" ; 12 | 13 | template::ActionTemplateNode = "template" "::" template:str ";" ; 14 | 15 | feedback::ActionFeedbackNode = "feedback" "::" name:str ";" ; 16 | 17 | pddl::ActionPddlNode = "pddl" "::" code:strBlock ";" ; 18 | 19 | grammar::ActionGrammarNode = "grammar" "::" code:strBlock ";" ; 20 | 21 | actionType::ActionTypeNode = "action" name:name "{" {(template:template | feedback:feedback | pddl:pddl | grammar:grammar)}* "}" ; 22 | 23 | pddlDocument::PddlDocumentNode = parts:{(actionType | grammar)}* $ ; 24 | 25 | pddlStart = pddlDocument ; 26 | -------------------------------------------------------------------------------- /textworld/textgen/textgen.ebnf: -------------------------------------------------------------------------------- 1 | @@grammar :: TextGrammar 2 | 3 | @@whitespace :: ?"[\t ]+" 4 | 5 | @@eol_comments :: ?"^(#.*|\s*)\n" 6 | 7 | start = grammar ; 8 | 9 | symbol = ?"[\w()/!<>-]+" ; 10 | 11 | literal = ?"((?:[^;|<>\n\[\]()]|\[[^\[\]]*\]|\([^()]*\))+(?" rhs:entity ; 20 | 21 | alternative = match | entity | (); 22 | 23 | alternatives = ";".{alternative}+ ; 24 | 25 | productionRule::ProductionRule = symbol:symbol ":" alternatives:alternatives ("\n" | $) ; 26 | 27 | grammar::TextGrammar = rules:{productionRule}* $ ; 28 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # tox (https://tox.readthedocs.io/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py35,py36 8 | skip_missing_interpreters=True 9 | 10 | [testenv] 11 | commands = nosetests textworld 12 | deps = 13 | nose 14 | -rrequirements.txt 15 | 16 | [flake8] 17 | max-line-length = 127 18 | max-complexity = 12 19 | ignore= 20 | E741 21 | W503 22 | C901 23 | per-file-ignores = 24 | __init__.py:F401 25 | filename = 26 | *.py 27 | scripts/tw-* 28 | exclude = 29 | .git, 30 | __pycache__, 31 | docs, 32 | ./textworld/thirdparty, 33 | build, 34 | dist -------------------------------------------------------------------------------- /textworld/challenges/tests/test_treasure_hunter.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | import pytest 5 | 6 | import textworld 7 | from textworld.challenges import treasure_hunter 8 | 9 | 10 | @pytest.mark.filterwarnings("ignore::textworld.GenerationWarning") 11 | def test_making_treasure_hunter_games(): 12 | for level in range(1, 30 + 1): 13 | options = textworld.GameOptions() 14 | options.seeds = 1234 15 | 16 | settings = {"level": level} 17 | game = treasure_hunter.make(settings, options) 18 | assert len(game.quests[0].commands) == game.metadata["quest_length"], "Level {}".format(level) 19 | assert len(game.world.rooms) == game.metadata["world_size"], "Level {}".format(level) 20 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/cheapglk/cgstyle.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "glk.h" 3 | #include "cheapglk.h" 4 | 5 | /* None of these functions do much in CheapGlk. */ 6 | 7 | void glk_stylehint_set(glui32 wintype, glui32 styl, glui32 hint, 8 | glsi32 val) 9 | { 10 | /* We don't do styles */ 11 | } 12 | 13 | void glk_stylehint_clear(glui32 wintype, glui32 styl, glui32 hint) 14 | { 15 | /* We don't do styles */ 16 | } 17 | 18 | glui32 glk_style_distinguish(winid_t win, glui32 styl1, glui32 styl2) 19 | { 20 | /* Styles are never distinguishable. */ 21 | return FALSE; 22 | } 23 | 24 | glui32 glk_style_measure(winid_t win, glui32 styl, glui32 hint, 25 | glui32 *result) 26 | { 27 | /* We can't measure any style attributes. */ 28 | return FALSE; 29 | } 30 | 31 | 32 | -------------------------------------------------------------------------------- /misc/vscode/language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbol used for single line comment. Remove this entry if your language does not support line comments 4 | "lineComment": "#", 5 | }, 6 | // symbols used as brackets 7 | "brackets": [ 8 | ["{", "}"], 9 | ["[", "]"], 10 | ["(", ")"] 11 | ], 12 | // symbols that are auto closed when typing 13 | "autoClosingPairs": [ 14 | ["{", "}"], 15 | ["[", "]"], 16 | ["(", ")"], 17 | ["\"", "\""], 18 | ["'", "'"] 19 | ], 20 | // symbols that that can be used to surround a selection 21 | "surroundingPairs": [ 22 | ["{", "}"], 23 | ["[", "]"], 24 | ["(", ")"], 25 | ["\"", "\""], 26 | ["'", "'"] 27 | ] 28 | } -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/cheapglk/glkstart.c: -------------------------------------------------------------------------------- 1 | /* glkstart.c: Unix-specific startup code -- sample file. 2 | Designed by Andrew Plotkin 3 | http://www.eblong.com/zarf/glk/index.html 4 | 5 | This is Unix startup code for the simplest possible kind of Glk 6 | program -- no command-line arguments; no startup files; no nothing. 7 | 8 | Remember, this is a sample file. You should copy it into the Glk 9 | program you are compiling, and modify it to your needs. This should 10 | *not* be compiled into the Glk library itself. 11 | */ 12 | 13 | #include "glk.h" 14 | #include "glkstart.h" 15 | 16 | glkunix_argumentlist_t glkunix_arguments[] = { 17 | { NULL, glkunix_arg_End, NULL } 18 | }; 19 | 20 | int glkunix_startup_code(glkunix_startup_t *data) 21 | { 22 | return TRUE; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /glk_build.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | 5 | from cffi import FFI 6 | 7 | 8 | ffibuilder = FFI() 9 | 10 | with open('src/glk_comm.c') as f: 11 | ffibuilder.set_source("glk", f.read()) 12 | 13 | ffibuilder.cdef(r""" 14 | struct sock_names { 15 | char* sock_name; 16 | ...; 17 | }; 18 | """) 19 | 20 | ffibuilder.cdef(r""" 21 | int init_glulx(struct sock_names* names); 22 | const char* communicate(struct sock_names* names, const char* msg); 23 | const char* get_output_nosend(struct sock_names* names); 24 | void cleanup_glulx(struct sock_names* names); 25 | void free(void* ptr); 26 | """) 27 | 28 | if __name__ == "__main__": 29 | ffibuilder.compile(verbose=True) 30 | -------------------------------------------------------------------------------- /textworld/render/tests/test_graph.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | import textworld 5 | from textworld.utils import check_flag 6 | 7 | from textworld.render import show_graph 8 | 9 | 10 | def _make_game(): 11 | options = textworld.GameOptions() 12 | options.seeds = 1234 13 | options.nb_rooms = 3 14 | options.nb_objects = 10 15 | options.quest_length = 3 16 | options.grammar.theme = "house" 17 | options.grammar.include_adj = True 18 | 19 | game = textworld.generator.make_game(options) 20 | return game 21 | 22 | 23 | def test_show_graph(): 24 | game = _make_game() 25 | 26 | renderer = None 27 | if check_flag("TEXTWORLD_DEBUG"): 28 | renderer = "browser" 29 | 30 | show_graph(game.world.facts, renderer=renderer) 31 | -------------------------------------------------------------------------------- /textworld/envs/pddl/textgen/textgen.ebnf: -------------------------------------------------------------------------------- 1 | @@grammar :: CSG 2 | 3 | @@whitespace :: ?"[\t]+" 4 | 5 | @@eol_comments :: ?"^(//.*|\s*)\n?" 6 | 7 | start = symbols ; 8 | 9 | tag = ?"[\w()/!<>\-\s,.]+" ; 10 | 11 | given = ?"[^;|{}\n\[\]#]+" ; 12 | 13 | statement = ?"[^|\[\]{}\n<>]+" ; 14 | 15 | Literal = ?'[^;|"<>\[\]#{}]*' ; 16 | 17 | terminalSymbol::TerminalSymbol = ('"' literal:Literal '"' | ~literal:Literal); 18 | 19 | nonterminalSymbol::NonterminalSymbol = "#" symbol:tag "#" ; 20 | 21 | evalSymbol::EvalSymbol = statement:statement ; 22 | 23 | conditionalSymbol::ConditionalSymbol = "{" expression:(nonterminalSymbol | evalSymbol) [?"\s*\|\s*" given:given] "}" ; 24 | 25 | listSymbol::ListSymbol = "[" symbol:conditionalSymbol "]" ; 26 | 27 | Symbol = listSymbol | conditionalSymbol | nonterminalSymbol | terminalSymbol; 28 | 29 | symbols = {Symbol}+ ; 30 | -------------------------------------------------------------------------------- /textworld/generator/data/logic/food.twl: -------------------------------------------------------------------------------- 1 | # food 2 | type f : o { 3 | predicates { 4 | edible(f); 5 | eaten(f); 6 | } 7 | 8 | rules { 9 | eat :: in(f, I) -> eaten(f); 10 | } 11 | 12 | constraints { 13 | eaten1 :: eaten(f) & in(f, I) -> fail(); 14 | eaten2 :: eaten(f) & in(f, c) -> fail(); 15 | eaten3 :: eaten(f) & on(f, s) -> fail(); 16 | eaten4 :: eaten(f) & at(f, r) -> fail(); 17 | } 18 | 19 | inform7 { 20 | type { 21 | kind :: "food"; 22 | definition :: "food is edible."; 23 | } 24 | 25 | predicates { 26 | edible(f) :: "The {f} is edible"; 27 | eaten(f) :: "The {f} is nowhere"; 28 | } 29 | 30 | commands { 31 | eat :: "eat {f}" :: "eating the {f}"; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /textworld/envs/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | import re 4 | 5 | from textworld.envs.glulx.git_glulx import GitGlulxEnv 6 | from textworld.envs.zmachine.jericho import JerichoEnv 7 | from textworld.envs.tw import TextWorldEnv 8 | from textworld.envs.wrappers.tw_inform7 import TWInform7 9 | from textworld.envs.pddl import PddlEnv 10 | 11 | 12 | def _guess_backend(path): 13 | # Guess the backend from the extension. 14 | if path.endswith(".ulx"): 15 | return GitGlulxEnv 16 | elif re.search(r"\.z[1-8]", path): 17 | return JerichoEnv 18 | elif path.endswith(".json"): 19 | return TextWorldEnv 20 | elif path.endswith(".tw-pddl"): 21 | return PddlEnv 22 | 23 | msg = "Unsupported game format: {}".format(path) 24 | raise ValueError(msg) 25 | -------------------------------------------------------------------------------- /textworld/envs/wrappers/generic.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | from typing import Optional 5 | 6 | import textworld 7 | 8 | import textworld.envs 9 | from textworld.core import EnvInfos, Wrapper 10 | 11 | 12 | class GenericEnvironment(Wrapper): 13 | 14 | def __init__(self, request_infos: Optional[EnvInfos] = None) -> None: 15 | super().__init__() 16 | self.request_infos = request_infos 17 | self._last_backend = None 18 | 19 | def load(self, gamefile: str) -> None: 20 | backend = textworld.envs._guess_backend(gamefile) 21 | if self._last_backend != backend: 22 | self._wrap(textworld.start(gamefile, self.request_infos)) 23 | self._last_backend = backend 24 | else: 25 | self._wrapped_env.load(gamefile) 26 | -------------------------------------------------------------------------------- /.azure/pipelines/release.yml: -------------------------------------------------------------------------------- 1 | # Release code in the main branch to PyPi 2 | 3 | jobs: 4 | - job: 5 | displayName: Release_on_PyPi 6 | pool: 7 | vmImage: 'ubuntu-latest' 8 | 9 | steps: 10 | - task: UsePythonVersion@0 11 | displayName: 'Use Python' 12 | 13 | - script: | 14 | pip install twine 15 | 16 | # Build the python distribution from source 17 | - script: | 18 | pip install -r requirements.txt 19 | ./tools/package.sh 20 | 21 | - task: TwineAuthenticate@1 22 | displayName: 'Twine Authenticate' 23 | inputs: 24 | pythonUploadServiceConnection: pypi 25 | 26 | # Use command line script to 'twine upload', use -r to pass the repository name and --config-file to pass the environment variable set by the authenticate task. 27 | - script: | 28 | python -m twine upload -r pypi --config-file $(PYPIRC_PATH) dist/textworld-* 29 | -------------------------------------------------------------------------------- /textworld/challenges/tw_simple/textworld_data/logic/food.twl: -------------------------------------------------------------------------------- 1 | # food 2 | type f : o { 3 | predicates { 4 | edible(f); 5 | eaten(f); 6 | } 7 | 8 | rules { 9 | eat :: in(f, I) -> eaten(f); 10 | } 11 | 12 | constraints { 13 | eaten1 :: eaten(f) & in(f, I) -> fail(); 14 | eaten2 :: eaten(f) & in(f, c) -> fail(); 15 | eaten3 :: eaten(f) & on(f, s) -> fail(); 16 | eaten4 :: eaten(f) & at(f, r) -> fail(); 17 | } 18 | 19 | inform7 { 20 | type { 21 | kind :: "food"; 22 | definition :: "food is edible."; 23 | } 24 | 25 | predicates { 26 | edible(f) :: "The {f} is edible"; 27 | eaten(f) :: "The {f} is nowhere"; 28 | } 29 | 30 | commands { 31 | eat :: "eat {f}" :: "eating the {f}"; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /textworld/challenges/tw_treasure_hunter/textworld_data/logic/food.twl: -------------------------------------------------------------------------------- 1 | # food 2 | type f : o { 3 | predicates { 4 | edible(f); 5 | eaten(f); 6 | } 7 | 8 | rules { 9 | eat :: in(f, I) -> eaten(f); 10 | } 11 | 12 | constraints { 13 | eaten1 :: eaten(f) & in(f, I) -> fail(); 14 | eaten2 :: eaten(f) & in(f, c) -> fail(); 15 | eaten3 :: eaten(f) & on(f, s) -> fail(); 16 | eaten4 :: eaten(f) & at(f, r) -> fail(); 17 | } 18 | 19 | inform7 { 20 | type { 21 | kind :: "food"; 22 | definition :: "food is edible."; 23 | } 24 | 25 | predicates { 26 | edible(f) :: "The {f} is edible"; 27 | eaten(f) :: "The {f} is nowhere"; 28 | } 29 | 30 | commands { 31 | eat :: "eat {f}" :: "eating the {f}"; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | comment: 2 | layout: "reach, diff, files" 3 | behavior: default 4 | require_changes: false # if true: only post the comment if coverage changes 5 | require_base: no # [yes :: must have a base report to post] 6 | require_head: yes # [yes :: must have a head report to post] 7 | branches: null 8 | 9 | ignore: 10 | - "*/docs/*" 11 | - "*/notebooks/*" 12 | - "*/thirdparty/*" 13 | - "setup.py" 14 | - "*/setup.py" 15 | - "*/tests/*" 16 | 17 | coverage: 18 | status: 19 | project: 20 | default: 21 | # Drops on the order 0.01% are typical even when no change occurs 22 | # Having this threshold set a little higher (0.1%) than that makes it 23 | # a little more tolerant to fluctuations 24 | target: auto 25 | threshold: 0.1% 26 | patch: 27 | default: 28 | target: auto 29 | threshold: 0.1% -------------------------------------------------------------------------------- /textworld/generator/tests/test_init.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | 5 | import numpy.testing as npt 6 | 7 | from textworld.generator import make_world, make_small_map, make_world_with 8 | 9 | from textworld.logic import Variable, Proposition 10 | 11 | 12 | def test_make_world_no_rng(): 13 | world = make_world(1) 14 | assert world is not None 15 | 16 | 17 | def test_make_small_map_too_big(): 18 | # small maps have max size 19 | npt.assert_raises(ValueError, make_small_map, n_rooms=6) 20 | 21 | 22 | def test_make_small_map(): 23 | world = make_small_map(n_rooms=4) 24 | assert world is not None 25 | 26 | 27 | def test_make_world_with(): 28 | r1 = Variable("r_0", "r") 29 | P = Variable('P') 30 | world = make_world_with(rooms=[r1]) 31 | assert Proposition('at', [P, r1]) in world.facts 32 | -------------------------------------------------------------------------------- /notebooks/make_games.sh: -------------------------------------------------------------------------------- 1 | tw-make tw-simple --rewards dense --goal detailed --seed 18 --test --silent -f --output games/tw-rewardsDense_goalDetailed.z8 2 | tw-make tw-simple --rewards balanced --goal detailed --seed 18 --test --silent -f --output games/tw-rewardsBalanced_goalDetailed.z8 3 | tw-make tw-simple --rewards sparse --goal detailed --seed 18 --test --silent -f --output games/tw-rewardsSparse_goalDetailed.z8 4 | tw-make tw-simple --rewards dense --goal brief --seed 18 --test --silent -f --output games/tw-rewardsDense_goalBrief.z8 5 | tw-make tw-simple --rewards balanced --goal brief --seed 18 --test --silent -f --output games/tw-rewardsBalanced_goalBrief.z8 6 | tw-make tw-simple --rewards sparse --goal brief --seed 18 --test --silent -f --output games/tw-rewardsSparse_goalBrief.z8 7 | tw-make tw-simple --rewards sparse --goal none --seed 18 --test --silent -f --output games/tw-rewardsSparse_goalNone.z8 8 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/help/glulx.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Glulx

8 | The Glulx specification 9 | was written by Andrew Plotkin as an attempt to define a format for interactive fiction games that 10 | the Inform compiler could compile to, without the limitations of its original output format, Infocom's 11 | Z-Machine. 12 |

13 | Windows Git is based on Iain Merrick's Git 1.3.5, which is a complete implementation of version 3.1.2 14 | of the Glulx specification. 15 |

16 | More information on Glulx is available from the Glulx web page: 17 | http://www.eblong.com/zarf/glulx/ 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com. 4 | 5 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. 6 | 7 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 8 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # List of things to do 2 | 3 | ## Viewer 4 | - Display the game's objective when hovering a '?'/help icon. 5 | - Better support history, i.e. highlighting action and showing corresponding feedback. 6 | - Add a "density map" showing region visited often. 7 | - Add a "trace map" showing the trajectory the agent took. 8 | 9 | 10 | ## Benchmark 11 | - Provide an option to run Treasure Hunter in `benchmark.py`. 12 | 13 | ## Game 14 | - Support tracking multiple quests. 15 | - Support nonlinear quests. 16 | 17 | ## GameMaker 18 | - Remove `inventory` attribute and replace it with `player`. E.g. `M.player.add(apple)`. 19 | - Do we really need both `GameMaker.facts` and `GameMaker.state`? 20 | - Support defining multiple quests. 21 | 22 | ## World 23 | - Integrate it with `GameMaker` as much as possible. 24 | 25 | ## Unit test 26 | - Make sure we use `GameMaker` in the unit tests rather than using `textworld.generator.world`. 27 | -------------------------------------------------------------------------------- /scripts/tw-data: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) Microsoft Corporation. All rights reserved. 4 | # Licensed under the MIT license. 5 | 6 | 7 | """ 8 | Creates grammar files in the target directory. 9 | """ 10 | 11 | import argparse 12 | from os.path import join as pjoin 13 | 14 | from textworld.generator.data import create_data_files 15 | 16 | 17 | def parse_args(): 18 | parser = argparse.ArgumentParser() 19 | parser.add_argument("destination", nargs='?', default="./") 20 | parser.add_argument("-v", "--verbose", action="store_true") 21 | parser.add_argument("-f", "--force", action="store_true") 22 | return parser.parse_args() 23 | 24 | 25 | if __name__ == "__main__": 26 | args = parse_args() 27 | path = pjoin(args.destination, "textworld_data") 28 | print("Placing Textworld's customizable files in '{}'.".format(path)) 29 | create_data_files(path, verbose=args.verbose, force=args.force) 30 | -------------------------------------------------------------------------------- /docs/source/textworld.generator.rst: -------------------------------------------------------------------------------- 1 | textworld.generator 2 | =================== 3 | 4 | .. automodule:: textworld.generator 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: textworld.generator.chaining 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. automodule:: textworld.generator.dependency_tree 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | .. automodule:: textworld.generator.logger 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | 24 | .. automodule:: textworld.generator.vtypes 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | 29 | 30 | .. toctree:: 31 | :hidden: 32 | 33 | textworld.generator.game 34 | textworld.generator.world 35 | textworld.generator.maker 36 | textworld.generator.grammar 37 | textworld.generator.data 38 | textworld.generator.inform7 -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/cheapglk/agent.h: -------------------------------------------------------------------------------- 1 | #ifndef AGENT_H 2 | #define AGENT_H 3 | #pragma once 4 | 5 | /** 6 | * Initializes the agent. 7 | * @param sock_name The name of the unix socket file to connect to 8 | */ 9 | void agent_init(char* sock_name); 10 | 11 | /** 12 | * Adds an output-encoded string (UTF-8 or latin1) as input to the agent 13 | * @param buf The buf containing the output 14 | * @param len The length of the output 15 | */ 16 | void agent_put_string(char* buf, glui32 len); 17 | 18 | /** 19 | * Returns agent output for the input buffer for a continuous process. 20 | * @param output_buf Output buffer to write into 21 | * @param max_len Size of output buffer 22 | * @return The length of output actually written 23 | */ 24 | glui32 agent_get_output(char* output_buf, glui32 max_len); 25 | 26 | /** 27 | * Should be called on glk_exit() to avoid client programs hanging. 28 | */ 29 | void agent_exit(void); 30 | 31 | #endif //AGENT_H -------------------------------------------------------------------------------- /textworld/gym/envs/utils.py: -------------------------------------------------------------------------------- 1 | from typing import Iterable, Any 2 | 3 | from numpy.random import RandomState 4 | 5 | 6 | def shuffled_cycle(iterable: Iterable[Any], rng: RandomState, nb_loops: int = -1) -> Iterable[Any]: 7 | """ 8 | Yield each element of `iterable` one by one, then shuffle the elements 9 | and start yielding from the start. Stop after `nb_loops` loops. 10 | 11 | Arguments: 12 | iterable: Iterable containing the elements to yield. 13 | rng: Random generator used to shuffle the elements after each loop. 14 | nb_loops: Number of times to go through all the elements. If set to -1, 15 | loop an infinite number of times. 16 | """ 17 | elements = [] 18 | for e in iterable: 19 | elements.append(e) 20 | yield e 21 | 22 | cpt = nb_loops 23 | while cpt != 0: 24 | cpt -= 1 25 | rng.shuffle(elements) 26 | for e in elements: 27 | yield e 28 | -------------------------------------------------------------------------------- /textworld/envs/wrappers/recorder.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | 5 | from typing import Tuple 6 | 7 | from textworld.core import GameState, Wrapper 8 | 9 | 10 | class Recorder(Wrapper): 11 | def __init__(self) -> None: 12 | self.actions = [] 13 | self.last_game_state = None 14 | 15 | def _wrap(self, env): 16 | super()._wrap(env) 17 | # Recording requires some additional information. 18 | self.request_infos.last_action = True 19 | 20 | def step(self, command: str) -> Tuple[GameState, float, bool]: 21 | res = super().step(command) 22 | game_state = res[0] 23 | self.actions.append(game_state._last_action) 24 | self.last_game_state = game_state 25 | return res 26 | 27 | def reset(self) -> GameState: 28 | self.actions = [] 29 | self.last_game_state = None 30 | return super().reset() 31 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | set SPHINXPROJ=TextWorld 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/help/autorun.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Automatic Running

8 | When it comes time to distribute your game, you can package up the interpreter with your game 9 | into an archive or installer. But if you want the user to be able to start your game just by 10 | clicking on an icon, you can rename Git.exe to the same as the name as your game's 11 | Glulx file (apart from the .exe file extension). When the interpreter starts up it 12 | first looks for a Blorb file with the same name as the executable, and if one is found, loads 13 | and runs it straight away. So, if your game file is Foo.blb and the renamed interpreter 14 | executable is Foo.exe, all the user needs to do to run your game is double click on 15 | Foo.exe. 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /textworld/challenges/tw_coin_collector/textworld_data/logic/inventory.twl: -------------------------------------------------------------------------------- 1 | # Inventory 2 | type I { 3 | predicates { 4 | in(o, I); 5 | } 6 | 7 | rules { 8 | take :: $at(P, r) & at(o, r) -> in(o, I); 9 | drop :: $at(P, r) & in(o, I) -> at(o, r); 10 | inventory :: at(P, r) -> at(P, r); # Nothing changes. 11 | examine/I :: in(o, I) -> in(o, I); # Nothing changes. 12 | } 13 | 14 | reverse_rules { 15 | inventory :: inventory; 16 | take :: drop; 17 | examine/I :: examine/I; 18 | } 19 | 20 | inform7 { 21 | predicates { 22 | in(o, I) :: "The player carries the {o}"; 23 | } 24 | 25 | commands { 26 | take :: "take {o}" :: "taking the {o}"; 27 | drop :: "drop {o}" :: "dropping the {o}"; 28 | inventory :: "inventory" :: "taking inventory"; 29 | examine/I :: "examine {o}" :: "examining the {o}"; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.azure/pipelines/tests.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | - main 3 | 4 | stages: 5 | - stage: Test 6 | variables: 7 | - name: installFromSource 8 | value: true 9 | readonly: true 10 | jobs: 11 | - template: linux-template.yml 12 | parameters: 13 | vmImages: [ 'ubuntu-latest' ] 14 | pythonVersions: [ '3.9' ] 15 | - template: linux-template.yml 16 | parameters: 17 | vmImages: [ 'ubuntu-latest' ] 18 | pythonVersions: [ '3.10' ] 19 | - template: linux-template.yml 20 | parameters: 21 | vmImages: [ 'ubuntu-latest' ] 22 | pythonVersions: [ '3.11' ] 23 | - template: linux-template.yml 24 | parameters: 25 | vmImages: [ 'ubuntu-latest' ] 26 | pythonVersions: [ '3.12' ] 27 | - template: macos-template.yml 28 | parameters: 29 | vmImages: [ 'macOS-latest' ] 30 | pythonVersions: [ '3.9' ] 31 | - template: macos-template.yml 32 | parameters: 33 | vmImages: [ 'macOS-latest' ] 34 | pythonVersions: [ '3.12' ] 35 | -------------------------------------------------------------------------------- /textworld/envs/wrappers/limit.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | 5 | from typing import Tuple, Mapping, Any 6 | 7 | from textworld.core import Environment, Wrapper 8 | 9 | 10 | class Limit(Wrapper): 11 | """ 12 | Environment wrapper to limit the number of steps. 13 | 14 | """ 15 | 16 | def __init__(self, env: Environment, max_episode_steps: int): 17 | super().__init__(env) 18 | self.max_episode_steps = max_episode_steps 19 | self.nb_steps = 0 20 | 21 | def reset(self) -> Tuple[str, Mapping[str, Any]]: 22 | game_state = super().reset() 23 | self.nb_steps = 0 24 | return game_state 25 | 26 | def step(self, command: str) -> Tuple[str, Mapping[str, Any]]: 27 | game_state, score, done = super().step(command) 28 | self.nb_steps += 1 29 | done |= self.nb_steps >= self.max_episode_steps 30 | return game_state, score, done 31 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # Docker for TextWorld 2 | 3 | Dockerfile for running TextWorld - a text-based game generator and extensible sandbox learning environment for training and testing reinforcement learning agents. 4 | 5 | ## Instructions 6 | 7 | ```bash 8 | docker pull marccote19/textworld 9 | docker run -p 8888:8888 -it --rm marccote19/textworld 10 | ``` 11 | 12 | Then, in your browser, navigate to the Jupyter notebook's link displayed in your terminal. The link should look like this 13 | 14 | ```bash 15 | http://127.0.0.1:8888/?token=8d7aaa...e95 16 | ``` 17 | 18 | ## Troubleshoot 19 | 20 | ### bind: address already in use 21 | 22 | Try changing the port number published on the host. For instance, to map container's port `8888` (Jupyter's default port) to `9999` on the host, use 23 | 24 | ```bash 25 | docker run -p 9999:8888 -it --rm marccote19/textworld 26 | ``` 27 | 28 | Then, make sure you modify the Jupyter notebook's link accordingly, i.e. 29 | 30 | ```bash 31 | http://127.0.0.1:9999/?token=8d7aaa...e95 32 | ``` 33 | -------------------------------------------------------------------------------- /scripts/tw-view: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) Microsoft Corporation. All rights reserved. 4 | # Licensed under the MIT license. 5 | 6 | 7 | import os 8 | import argparse 9 | 10 | import textworld 11 | from textworld import EnvInfos 12 | from textworld.render import show_graph 13 | 14 | 15 | def build_parser(): 16 | description = "Display the graph representation of a game's initial state." 17 | parser = argparse.ArgumentParser(description=description) 18 | parser.add_argument("game", 19 | help="JSON file containing infos about the game.") 20 | parser.add_argument("-v", "--verbose", action="store_true", 21 | help="Verbose mode.") 22 | return parser 23 | 24 | 25 | if __name__ == "__main__": 26 | args = build_parser().parse_args() 27 | 28 | gamefile = os.path.splitext(args.game)[0] + ".json" 29 | env = textworld.start(gamefile, request_infos=EnvInfos(facts=True)) 30 | state = env.reset() 31 | 32 | show_graph(state.facts, renderer="browser") 33 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/win/res/Git.manifest: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | Windows Git Glulx Interpreter 14 | 15 | 16 | 17 | true 18 | 19 | 20 | 21 | 22 | 23 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/textworld_data/logic/stove.twl: -------------------------------------------------------------------------------- 1 | # stove 2 | type stove : s { 3 | rules { 4 | cook/stove/burned :: $at(P, r) & $at(stove, r) & $in(f, I) & cooked(f) & edible(f) -> burned(f) & inedible(f); 5 | cook/stove/cooked/raw :: $at(P, r) & $at(stove, r) & $in(f, I) & raw(f) -> fried(f) & cooked(f); 6 | cook/stove/cooked/needs_cooking :: $at(P, r) & $at(stove, r) & $in(f, I) & needs_cooking(f) & inedible(f) -> fried(f) & edible(f) & cooked(f); 7 | } 8 | 9 | inform7 { 10 | type { 11 | kind :: "stove-like"; 12 | definition :: "stove-like is a source of heat."; 13 | } 14 | 15 | commands { 16 | cook/stove/cooked/raw :: "cook {f} with {stove}" :: "cooking the {f} with the {stove}"; 17 | cook/stove/cooked/needs_cooking :: "cook {f} with {stove}" :: "cooking the {f} with the {stove}"; 18 | cook/stove/burned :: "cook {f} with {stove}" :: "cooking the {f} with the {stove}"; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/Makefile.win: -------------------------------------------------------------------------------- 1 | # Makefile for Windows Git, compiled with MinGW GCC 2.95 2 | 3 | CC = gcc-2 -Wall -O3 -mwindows 4 | OPTIONS = -DUSE_INLINE -DUSE_DIRECT_THREADING -DUSE_OWN_POWF 5 | LIBS = -L. -lglk 6 | 7 | OUTPUT = ../Executables/Release/Git 8 | 9 | CFLAGS = $(OPTIONS) -I../Include 10 | 11 | OBJS = git.o memory.o compiler.o opcodes.o operands.o peephole.o terp.o \ 12 | glkop.o search.o git_windows.o savefile.o saveundo.o gestalt.o \ 13 | accel.o heap.o glk.o res.o 14 | 15 | all: git chm 16 | 17 | git: $(OBJS) libglk.a 18 | $(CC) -s -o $(OUTPUT) $(OBJS) $(LIBS) 19 | 20 | glk.o: ../glk.c 21 | $(CC) $(CFLAGS) -c -o $@ $^ 22 | 23 | res.o: win/git.rc 24 | windres --preprocessor "gcc-2 -E -xc-header -DRC_INVOKED" $^ $@ 25 | 26 | libglk.a: 27 | dlltool --dllname=Glk.dll --def=../GlkDll/Glk.def --output-lib=libglk.a 28 | 29 | chm: 30 | -C:\\Program\ Files\ \(x86\)\\HTML\ Help\ Workshop\\hhc help\\Git.hhp 31 | copy help\\Git.chm ..\\Executables\\Release 32 | 33 | clean: 34 | del *.o *.a 35 | 36 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/textworld_data/logic_drop/stove.twl: -------------------------------------------------------------------------------- 1 | # stove 2 | type stove : s { 3 | rules { 4 | cook/stove/burned :: $at(P, r) & $at(stove, r) & $in(f, I) & cooked(f) & edible(f) -> burned(f) & inedible(f); 5 | cook/stove/cooked/raw :: $at(P, r) & $at(stove, r) & $in(f, I) & raw(f) -> fried(f) & cooked(f); 6 | cook/stove/cooked/needs_cooking :: $at(P, r) & $at(stove, r) & $in(f, I) & needs_cooking(f) & inedible(f) -> fried(f) & edible(f) & cooked(f); 7 | } 8 | 9 | inform7 { 10 | type { 11 | kind :: "stove-like"; 12 | definition :: "stove-like is a source of heat."; 13 | } 14 | 15 | commands { 16 | cook/stove/cooked/raw :: "cook {f} with {stove}" :: "cooking the {f} with the {stove}"; 17 | cook/stove/cooked/needs_cooking :: "cook {f} with {stove}" :: "cooking the {f} with the {stove}"; 18 | cook/stove/burned :: "cook {f} with {stove}" :: "cooking the {f} with the {stove}"; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/test_check_generated_games.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | import os 5 | from os.path import join as pjoin 6 | from subprocess import check_output 7 | 8 | from textworld.utils import make_temp_directory 9 | 10 | SCRIPTS_PATH = os.path.abspath(pjoin(__file__, "..", "..", "scripts")) 11 | 12 | 13 | def test_check_generated_game(): 14 | NB_GAMES = 3 15 | script = pjoin(SCRIPTS_PATH, "check_generated_games.py") 16 | with make_temp_directory(prefix="test_check_generated_game") as tmpdir: 17 | for i in range(NB_GAMES): 18 | command = ["tw-make", "custom", "--seed", str(i), "--output", tmpdir] 19 | check_output(command).decode() 20 | 21 | game_files = [pjoin(tmpdir, f) for f in os.listdir(tmpdir) if f.endswith(".z8")] 22 | assert len(game_files) == NB_GAMES 23 | command = ["python", script] + game_files 24 | stdout = check_output(command).decode() 25 | for file in game_files: 26 | assert "Testing " + file in stdout 27 | -------------------------------------------------------------------------------- /benchmark/agent_template.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | 5 | import numpy as np 6 | 7 | import textworld 8 | 9 | 10 | class CustomAgent(textworld.Agent): 11 | def __init__(self, seed=1234): 12 | self.seed = seed 13 | self.rng = np.random.RandomState(self.seed) 14 | self.actions = ["north", "south", "east", "west", "up", "down", 15 | "look", "inventory", "take all", "YES", "wait", 16 | "take", "drop", "eat", "attack"] 17 | 18 | def reset(self, env): 19 | env.display_command_during_render = True 20 | 21 | def act(self, game_state, reward, done): 22 | action = self.rng.choice(self.actions) 23 | if action in ["take", "drop", "eat", "attack"]: 24 | words = game_state.feedback.split() # Observed words. 25 | words = [w for w in words if len(w) > 3] # Ignore most stop words. 26 | if len(words) > 0: 27 | action += " " + self.rng.choice(words) 28 | 29 | return action 30 | -------------------------------------------------------------------------------- /textworld/agents/simple.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | 5 | import numpy as np 6 | 7 | from textworld import Agent 8 | 9 | 10 | class NaiveAgent(Agent): 11 | def __init__(self, seed=1234): 12 | self.seed = seed 13 | self.rng = np.random.RandomState(self.seed) 14 | self.actions = ["north", "south", "east", "west", "up", "down", 15 | "look", "inventory", "take all", "YES", "wait", 16 | "take", "drop", "eat", "attack"] 17 | 18 | def reset(self, env): 19 | env.display_command_during_render = True 20 | 21 | def act(self, game_state, reward, done): 22 | action = self.rng.choice(self.actions) 23 | if action in ["take", "drop", "eat", "attack"]: 24 | words = game_state.feedback.split() # Observed words. 25 | words = [w for w in words if len(w) > 3] # Ignore most stop words. 26 | if len(words) > 0: 27 | action += " " + self.rng.choice(words) 28 | 29 | return action 30 | -------------------------------------------------------------------------------- /textworld/challenges/tests/test_coin_collector.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | import pytest 5 | 6 | import textworld 7 | from textworld.challenges import coin_collector 8 | 9 | 10 | @pytest.mark.filterwarnings("ignore::textworld.GenerationWarning") 11 | def test_making_coin_collector(): 12 | expected = { 13 | 1: {"quest_length": 1, "nb_rooms": 1}, 14 | 100: {"quest_length": 100, "nb_rooms": 100}, 15 | 101: {"quest_length": 1, "nb_rooms": 2}, 16 | 200: {"quest_length": 100, "nb_rooms": 200}, 17 | 201: {"quest_length": 1, "nb_rooms": 3}, 18 | 300: {"quest_length": 100, "nb_rooms": 300}, 19 | } 20 | for level in [1, 100, 101, 200, 201, 300]: 21 | options = textworld.GameOptions() 22 | options.seeds = 1234 23 | 24 | settings = {"level": level} 25 | game = coin_collector.make(settings, options) 26 | assert len(game.quests[0].commands) == expected[level]["quest_length"] 27 | assert len(game.world.rooms) == expected[level]["nb_rooms"] 28 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/Git-Glulx/help/glk.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Glk

8 | The Glk specification 9 | was written by Andrew Plotkin as an attempt to define a standard input and output interface for general 10 | use in IF related projects. Windows Git uses my (David Kinder) implementation of Glk, called Windows 11 | Glk. Windows Glk is a complete implementation of all the features described in version 0.7.4 of the Glk 12 | specification. 13 |

14 | The complete Windows Glk package, including developer information, can be downloaded from the IF Archive's 15 | Glk implementations 16 | page. 17 |

18 | More information on Glk is available from the Glk web page: 19 | http://www.eblong.com/zarf/glk/ 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include requirements.txt 2 | include requirements-*.txt 3 | include README.md 4 | include LICENSE.txt 5 | include CHANGELOG.md 6 | include CONTRIBUTING.md 7 | include License.md 8 | include setup.sh 9 | 10 | include glk_build.py 11 | recursive-include src * 12 | 13 | include textworld/logic/*.ebnf 14 | include textworld/textgen/*.ebnf 15 | include textworld/generator/data/logic/*.twl 16 | include textworld/generator/data/text_grammars/*.twg 17 | recursive-include textworld/challenges/ *.twl 18 | recursive-include textworld/challenges/ *.twg 19 | 20 | include textworld/envs/pddl/logic/*.ebnf 21 | include textworld/envs/pddl/textgen/*.ebnf 22 | 23 | recursive-include textworld/render/tmpl * 24 | 25 | recursive-include textworld/thirdparty/glulx * 26 | 27 | recursive-include textworld/thirdparty/inform7 * 28 | include textworld/thirdparty/inform7-6M62/share/inform7/Compilers/inform6 29 | include textworld/thirdparty/inform7-6M62/share/inform7/Compilers/ni 30 | recursive-include textworld/thirdparty/inform7-6M62/share/inform7/Internal * 31 | 32 | global-exclude *.o *.a 33 | global-exclude */__pycache__/* 34 | 35 | prune build 36 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | TextWorld v1.2 2 | Copyright (c) Microsoft Corporation 3 | All rights reserved. 4 | 5 | MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | -------------------------------------------------------------------------------- /docs/source/notes/zork1.md: -------------------------------------------------------------------------------- 1 | # Zork1 2 | Some notes about Zork1. 3 | 4 | ## Stochasticity 5 | Zork1 has some stochasticity in it: 6 | 7 | - the thief will wander randomly in the dungeon stealing stuff. 8 | - when attacking someone, you can miss (to confirm) 9 | 10 | ## Death 11 | It seems that when you died, you get to continue playing but you lose 10 points (I think it is always 10). However, on your third death, the game ends. 12 | 13 | Everytime, when you get to continue playing, you seem to respawn in the Forest (but maybe the location can change, to confirm). 14 | 15 | ## Technical details 16 | When using the frotz interpreter, it is possible to provide the random seed as a parameter. 17 | `./frotz/dfrotz -s 1 zork1.z5` 18 | 19 | ## Additional documentation 20 | ### Game file 21 | The game file can be found here: [zork1.z5](https://archive.org/download/Zork1Release88Z-machineFile/zork1.z5). 22 | 23 | ### Map 24 | ![](http://oldsite.ironrealms.com/sites/default/files/zork-1-map.jpg) 25 | 26 | ### Walkthrough 27 | Here is a walkthrough (not optimal) when the Frotz's seed is set to one: [zork1_walkthrough.txt](./zork1_walkthrough.txt). 28 | -------------------------------------------------------------------------------- /tests/test_sample_quests.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | import os 5 | from os.path import join as pjoin 6 | from subprocess import check_output 7 | 8 | from textworld.utils import make_temp_directory 9 | 10 | SCRIPTS_PATH = os.path.abspath(pjoin(__file__, "..", "..", "scripts")) 11 | 12 | 13 | def test_sample_quests(): 14 | with make_temp_directory(prefix="test_sample_quests") as tmpdir: 15 | game_file = pjoin(tmpdir, "game.ulx") 16 | command = ["tw-make", "custom", "--seed", "20181004", "--output", game_file] 17 | check_output(command).decode() 18 | 19 | script = pjoin(SCRIPTS_PATH, "sample_quests.py") 20 | command = ["python", script, "--nb-quests", "10", "--quest-length", "10", 21 | "--quest-breadth", "5", "--output", tmpdir, game_file] 22 | stdout = check_output(command).decode() 23 | assert len(stdout) > 0 24 | assert os.path.isfile(pjoin(tmpdir, "sample_world.png")) 25 | assert os.path.isfile(pjoin(tmpdir, "sample_tree.svg")) 26 | assert os.path.isfile(pjoin(tmpdir, "sample_graph.svg")) 27 | -------------------------------------------------------------------------------- /textworld/generator/tests/test_logger.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | 5 | import numpy as np 6 | from os.path import join as pjoin 7 | 8 | import textworld 9 | from textworld.utils import make_temp_directory 10 | from textworld.generator.logger import GameLogger 11 | 12 | 13 | def test_logger(): 14 | rng = np.random.RandomState(1234) 15 | game_logger = GameLogger() 16 | 17 | for _ in range(10): 18 | options = textworld.GameOptions() 19 | options.nb_rooms = 5 20 | options.nb_objects = 10 21 | options.chaining.max_depth = 3 22 | options.chaining.max_breadth = 3 23 | options.seeds = rng.randint(65635) 24 | 25 | game = textworld.generator.make_game(options) 26 | game_logger.collect(game) 27 | 28 | with make_temp_directory(prefix="textworld_tests") as tests_folder: 29 | filename = pjoin(tests_folder, "game_logger.pkl") 30 | game_logger.save(filename) 31 | game_logger2 = GameLogger.load(filename) 32 | assert game_logger is not game_logger2 33 | assert game_logger.stats() == game_logger2.stats() 34 | -------------------------------------------------------------------------------- /textworld/thirdparty/glulx/cheapglk/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 1998-2016, Andrew Plotkin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/test_tw-play.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. 3 | 4 | from subprocess import check_call 5 | 6 | import textworld 7 | from textworld.utils import make_temp_directory 8 | 9 | 10 | def test_playing_a_game(): 11 | for ext in [".ulx", ".z8"]: 12 | with make_temp_directory(prefix="test_tw-play") as tmpdir: 13 | options = textworld.GameOptions() 14 | options.file_ext = ext 15 | options.path = tmpdir 16 | options.nb_rooms = 5 17 | options.nb_objects = 10 18 | options.quest_length = 5 19 | options.quest_breadth = 2 20 | options.seeds = 1234 21 | game_file, _ = textworld.make(options) 22 | 23 | command = ["tw-play", "--max-steps", "100", "--mode", "random", game_file] 24 | assert check_call(command) == 0 25 | 26 | command = ["tw-play", "--max-steps", "100", "--mode", "random-cmd", game_file] 27 | assert check_call(command) == 0 28 | 29 | command = ["tw-play", "--max-steps", "100", "--mode", "walkthrough", game_file] 30 | assert check_call(command) == 0 31 | -------------------------------------------------------------------------------- /.github/workflows/test_pypi.yml: -------------------------------------------------------------------------------- 1 | name: "Test from PyPi" 2 | 3 | on: 4 | workflow_dispatch: 5 | # Schedule a workflow to run at 00:00 (UTC) on the first of every month 6 | schedule: 7 | - cron: "0 0 1 * *" 8 | 9 | jobs: 10 | test: 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | os: [ubuntu-latest, macos-13, macos-14] 16 | python: ['3.9', '3.10', '3.11', '3.12', '3.13'] 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Use Python ${{ matrix.python }} 20 | uses: actions/setup-python@v5 21 | with: 22 | python-version: ${{ matrix.python }} 23 | 24 | - name: Install dependencies (Linux) 25 | run: sudo apt update && sudo apt install -y --no-install-recommends graphviz 26 | if: startsWith(matrix.os, 'ubuntu') 27 | 28 | - name: Install dependencies (MacOS) 29 | run: brew install graphviz 30 | if: startsWith(matrix.os, 'macos') 31 | 32 | - name: Install TextWorld 33 | run: | 34 | python -m pip install --upgrade pip 35 | pip install pytest 36 | pip install --pre textworld[full] 37 | - name: Run tests 38 | run: | 39 | pytest tests/ textworld/ 40 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. TextWorld documentation master file, created by 2 | sphinx-quickstart on Fri Jun 22 15:45:59 2018. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | TextWorld documentation 7 | ======================= 8 | TextWorld is a text-based learning environment for Reinforcement Learning agent. 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | 13 | notes/framework.md 14 | notes/troubleshoot.rst 15 | 16 | .. toctree:: 17 | :maxdepth: 1 18 | :caption: Scripts: 19 | 20 | tw-play 21 | tw-make 22 | tw-view 23 | tw-extract 24 | 25 | .. toctree:: 26 | :maxdepth: 1 27 | :caption: Challenges: 28 | 29 | textworld.challenges.simple 30 | textworld.challenges.coin_collector 31 | textworld.challenges.cooking 32 | textworld.challenges.treasure_hunter 33 | 34 | .. toctree:: 35 | :maxdepth: 1 36 | :caption: Package: 37 | 38 | textworld 39 | textworld.gym 40 | textworld.envs 41 | textworld.agents 42 | textworld.generator 43 | textworld.challenges 44 | textworld.logic 45 | textworld.render 46 | textworld.utils 47 | 48 | Indices and tables 49 | ================== 50 | 51 | * :ref:`genindex` 52 | * :ref:`modindex` 53 | * :ref:`search` 54 | -------------------------------------------------------------------------------- /textworld/challenges/tw_cooking/textworld_data/text_grammars/house_ext_cook.twg: -------------------------------------------------------------------------------- 1 | # New instructions 2 | cook:cook the #obj_types#. 3 | make:make the meal. 4 | 5 | # New descriptions 6 | 7 | #on cookers 8 | 9 | (stove):#(stove)_adj_1# | #(stove)_noun_1#;#(stove)_adj_2# | #(stove)_noun_2# 10 | 11 | (stove)_noun_1:stove;burner;stove top;range 12 | (stove)_adj_1:electric;gas;#cookgenadj# 13 | 14 | (stove)_noun_2:barbecue;barbeque;BBQ;barbecue pit;barbeque pit;grill 15 | (stove)_adj_2:propane fueled;#cookgenadj# 16 | 17 | 18 | 19 | #in cookers 20 | 21 | (oven):#(oven)_adj_1# | #(oven)_noun_1#;#(oven)_adj_1# | #(oven)_noun_1#;#(oven)_adj_2# | #(oven)_noun_2#;#(oven)_adj_3# | #(oven)_noun_3#;#(oven)_adj_4# | #(oven)_noun_4# 22 | 23 | (oven)_noun_1:oven;microwave 24 | (oven)_adj_1:#(o)_adj#;stainless steel;shiny;off brand;#cookgenadj# 25 | 26 | 27 | (oven)_noun_2:toaster;toaster oven 28 | (oven)_adj_2:two slice;four slice;crusty;ancient;#cookgenadj# 29 | 30 | (oven)_noun_3:slow cooker;rice cooker 31 | (oven)_adj_3:high speed;electric;no name brand;#cookgenadj# 32 | 33 | (oven)_noun_4:fryer;deep fryer 34 | (oven)_adj_4:#hot-adj# hot;#cookgenadj# 35 | 36 | 37 | #general adj for cookers# 38 | cookgenadj:store brand;no name brand;stainless steel;fancy;rustic;modern;smart;high tech;name brand 39 | -------------------------------------------------------------------------------- /textworld/envs/wrappers/tests/test_limit.py: -------------------------------------------------------------------------------- 1 | import textworld 2 | from textworld.envs.wrappers import Limit 3 | from textworld.generator import compile_game 4 | from textworld.utils import make_temp_directory 5 | 6 | 7 | def test_limit_wrapper(): 8 | # Make a game for testing purposes. 9 | max_episode_steps = 7 10 | 11 | num_nodes = 3 12 | num_items = 10 13 | options = textworld.GameOptions() 14 | options.seeds = 1234 15 | options.nb_rooms = num_nodes 16 | options.nb_objects = num_items 17 | options.quest_length = 3 18 | options.grammar.theme = "house" 19 | options.grammar.include_adj = True 20 | game = textworld.generator.make_game(options) 21 | 22 | game_name = "test_limit_wrapper" 23 | with make_temp_directory(prefix=game_name) as tmpdir: 24 | options.path = tmpdir 25 | game_file = compile_game(game, options) 26 | 27 | env = textworld.start(game_file) 28 | env = Limit(env, max_episode_steps) 29 | state = env.reset() 30 | 31 | done = False 32 | assert state["moves"] == 0 33 | for no_step in range(1, max_episode_steps + 1): 34 | assert not done 35 | state, score, done = env.step("wait") 36 | assert state["moves"] == no_step 37 | 38 | assert done 39 | -------------------------------------------------------------------------------- /docs/source/textworld.generator.data.rst: -------------------------------------------------------------------------------- 1 | .. _KB: 2 | 3 | Knowledge Base 4 | ============== 5 | 6 | .. automodule:: textworld.generator.data 7 | :members: 8 | :undoc-members: 9 | :show-inheritance: 10 | 11 | Data 12 | ---- 13 | 14 | container.twl 15 | ^^^^^^^^^^^^^ 16 | .. literalinclude:: ../../textworld/generator/data/logic/container.twl 17 | 18 | door.twl 19 | ^^^^^^^^ 20 | .. literalinclude:: ../../textworld/generator/data/logic/door.twl 21 | 22 | food.twl 23 | ^^^^^^^^ 24 | .. literalinclude:: ../../textworld/generator/data/logic/food.twl 25 | 26 | inventory.twl 27 | ^^^^^^^^^^^^^ 28 | .. literalinclude:: ../../textworld/generator/data/logic/inventory.twl 29 | 30 | key.twl 31 | ^^^^^^^ 32 | .. literalinclude:: ../../textworld/generator/data/logic/key.twl 33 | 34 | object.twl 35 | ^^^^^^^^^^ 36 | .. literalinclude:: ../../textworld/generator/data/logic/object.twl 37 | 38 | player.twl 39 | ^^^^^^^^^^ 40 | .. literalinclude:: ../../textworld/generator/data/logic/player.twl 41 | 42 | room.twl 43 | ^^^^^^^^ 44 | .. literalinclude:: ../../textworld/generator/data/logic/room.twl 45 | 46 | supporter.twl 47 | ^^^^^^^^^^^^^ 48 | .. literalinclude:: ../../textworld/generator/data/logic/supporter.twl 49 | 50 | thing.twl 51 | ^^^^^^^^^ 52 | .. literalinclude:: ../../textworld/generator/data/logic/thing.twl 53 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools >= 61.0", 4 | "cffi >= 1.0.0", 5 | ] 6 | build-backend = "setuptools.build_meta" 7 | 8 | [project] 9 | name = "textworld" 10 | description = "Microsoft Textworld - A Text-based Learning Environment." 11 | authors = [ 12 | { name = "Marc-Alexandre Côté" }, 13 | { name = "Microsoft Textworld", email = "textworld@microsoft.com" }, 14 | ] 15 | readme = "README.md" 16 | requires-python = ">=3.9" 17 | dynamic = ["version", "optional-dependencies", "dependencies"] 18 | 19 | classifiers = [ 20 | "Development Status :: 5 - Production/Stable", 21 | "Intended Audience :: Developers", 22 | "Intended Audience :: Information Technology", 23 | "License :: OSI Approved :: MIT License", 24 | "Natural Language :: English", 25 | "Operating System :: MacOS", 26 | "Operating System :: POSIX", 27 | "Programming Language :: Python :: 3.9", 28 | "Programming Language :: Python :: 3.10", 29 | "Programming Language :: Python :: 3.11", 30 | "Programming Language :: Python :: 3.12", 31 | "Topic :: Scientific/Engineering :: Artificial Life", 32 | ] 33 | 34 | license = {file = "LICENSE.txt"} 35 | 36 | [project.urls] 37 | Homepage = "https://github.com/microsoft/TextWorld" 38 | Issues = "https://github.com/microsoft/TextWorld/issues" -------------------------------------------------------------------------------- /scripts/check_generated_games.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) Microsoft Corporation. All rights reserved. 4 | # Licensed under the MIT license. 5 | 6 | 7 | import argparse 8 | 9 | import textworld 10 | import textworld.agents 11 | 12 | 13 | def parse_args(): 14 | parser = argparse.ArgumentParser() 15 | parser.add_argument("games", metavar="game", nargs="+") 16 | parser.add_argument("-v", "--verbose", action="store_true") 17 | return parser.parse_args() 18 | 19 | 20 | def main(): 21 | args = parse_args() 22 | agent = textworld.agents.WalkthroughAgent() 23 | 24 | for i, game in enumerate(args.games, start=1): 25 | print("{}. Testing {} ...".format(i, game)) 26 | env = textworld.start(game) 27 | env.request_infos.admissible_commands = True 28 | agent.reset(env) 29 | game_state = env.reset() 30 | 31 | if args.verbose: 32 | env.render() 33 | 34 | reward = 0 35 | done = False 36 | while not done: 37 | command = agent.act(game_state, reward, done) 38 | assert command in game_state.admissible_commands 39 | game_state, reward, done = env.step(command) 40 | 41 | if args.verbose: 42 | env.render() 43 | 44 | 45 | if __name__ == "__main__": 46 | main() 47 | -------------------------------------------------------------------------------- /textworld/render/tmpl/slideshow.handlebars: -------------------------------------------------------------------------------- 1 | 2 | 3 | TextWorld 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |

19 | 28 | 29 | 30 |
31 | 32 | 33 |