Tool for reading, formatting, and manipulating exploration graphs, which are graphs (or graph-sequences) that describe exploration of a game space, principally designed with Metroidvania games in mind.
Project description
Exploration
Overview
This program provides data types for representing the exploration of spaces that can defined (or abstracted) in terms of discrete decisions, such as videogame levels with multiple rooms and also other things like conversation trees or a city block grid. It also has the beginnings of code for representing open-world exploration in terms of districts, nodes, paths, edges, and landmarks, although this code is not yet complete.
The discrete code represents space using a DecisionGraph
, which is a
multi-di-graph indicating the transition(s) between decisions, which can
include information about prerequisites for transitions as well as
effects a transition might have on the world. There is also a convention
for representing unexplored options using specially-tagged nodes of the
graph. A DiscreteExploration
is a sequence of DecisionGraph
s, along
with a sequence of exploration actions indicating what the explorer did
at each step, including which transition (if any) was taken. Exploration
State
is tracked in terms of capabilities gained, tokens accumulated,
and also mechanism states throughout the graph.
These representations were developed with Metroidvania games in mind but should apply to a variety of game genres and even real-life situations.
Core capabilities include:
- Representing exploration processes as a series of decisions including partial information about not-yet-explored decisions.
- Creating maps and explorations from various text formats, including exploration journal formats.
- Reasoning about reachability modulo transition requirements in terms of powers that must be possessed and/or tokens that must be spent for a transition. TODO
- The ability to represent fairly sophisticated game logic in the
DecisionGraph
, and even construct playable maps. Game logic that can't be captured this way can still be represented through making custom changes to maps between exploration steps.
Dependencies:
- Python version 3.8+
networkx
For underlying graph structures.pytest
for testing, install with[test]
option to get it automatically.
Installing
Just run pip install exploration
. The egtool
script should be
installed along with the module.
You can then run python -m exploration.tests
to run tests (use pip install exploration[test]
if this doesn't work out-of-the-box).
Getting Started:
The egtool
script provides a command-line interface to core
functionality. The exploration.main
module provides equivalent entry
points from Python. exploration.core
provides the main types and
explains how they fit together.
Plans
- Better support for open-world games, where decisions are not as closely linked to virtual space structure.
Changelog
- v0.7.4 fixes some minor issues:
- Fixes a bug with mechanism search where relevant transitions were not being used as the search basis in some cases.
- v0.7.3 adds a bit more:
- Journal support for tagging and annotating zones.
ReqTag
requirements for requiring the presence of a certain tag (or a certain tag value) on some active decision or zone.ReqLevel
requirements for requiring a minimum skill level.- Removes the restriction on entering relative mode in an empty/unstarted graph.
- Respects current domain when creating new nodes via warps or when there's no current decision.
- Adds 'inventory', 'equivalences', and 'mechanisms' debug options.
- v0.7.2 offers a few more improvements and more API changes (including
breaking ones):
replaceUnexplored
is nowreplaceUnconfirmed
.unvisited
tag is nowunconfirmed
.core.DecisionGraph.hasBeenVisited
is nowcore.DecisionGraph.isConfirmed
. Finally a good naming distinction between graph confirmation & exploration visited status.- Adds 'inspect' mode to the
egtool.py
script and aninspect
entry point inmain.py
, allowing you to interactively examine an exploration on the command line. - Fixes an issue with 'unvisited' tags on endings.
- Adds zone inference to a lot more code paths, such that things like revisits and obviates no longer need to re-specify the current zone.
- Adds decision type specifiers for journal entries, and changes + expands the available decision types.
- Adds special behavior for the 'trigger' tag when applied to action
transitions: When
core.DiscreteExploration.advanceSituation
is called, each trigger action at an active decision whose requirements are satisfied will have its consequences applied. - Prevents using 'a'/'action' to take an existing action, requiring the use of 't'/'retrace' with the 'actionPart' target instead (typically 'ta'). This helps catch issues with action name misspellings, and location confusion, among others.
- Endings are now warps by default instead of transitions, use 'actionPart' (e.g., 'Ea') to mark a voluntary ending.
- v0.7.1 fixes major bugs with v0.7 and adds a few more nice/important
things:
- Transitions may include outcome specifiers, so that in a journal you can annotate taking the same transition multiple times and getting different results each time for challenges.
- A new 'save' effect copies game state, which can be restored (in
whole or in part) via a new 'revertTo' / 'revert'
ExplorationAction
/ journal entry. Custom combinations indicating which state parts to revert can be stored in an exploration for later re-use. - Fixed up some fuzziness around bounce/follow effects, and added a
primaryDecision
slot to theState
structure, so there's always a per-situation idea of a single primary decision (except when it'sNone
). - Warnings for 'at:' annotations, along with 'active:', 'has:', 'level:', 'can:', 'state:', and 'exists:' so these can be used to help with journal debugging.
- Auto-slots for journal aliases, for example
__here__
and__transition__
. base.Requirement.walk
, to support auto-creation of mentioned mechanisms in journals.AnyEffectValue
union type.- Substantially cleaned up handling of exploration statues, and introduced the new 'status' journal entry type to set them, which can also disable the new automatic update-to-'explored' feature which normally triggers when leaving a decision.
- Many more contexts allow you to omit zone information, although there are still some that require it.
- More consistency with when to use 'x' vs. 'r': 'r' is only used when the exploration status of a node is 'exploring' or higher, regardless of its 'unvisited' tag status.
- v0.7 is a MAJOR overhaul, and breaks compatibility with previous
versions. It's a solid alpha version, and may soon be upgraded to a 1.0
beta, but it needs a bit more use with longer journals first. It adds:
- The first nascent support for open-world exploration in
geographic.py
, but this is still far from complete. - Zone prefixing is gone, and instead
Decision
s have IDs and may freely share names.DecisionSpecifier
s may identify a decision by domain, zone, and/or name. - Domains with different focalization modes, focal contexts, and
focal points. In most cases these can be safely ignored, but they
are useful for:
- Representing multiple concurrent active decisions (e.g., an
omnipresent menu option that affects exploration in the main
game world) via multiple
Domain
s. - Representing control over multiple units, via
FocalPointSpecifier
s and 'plural'-focalized domains. - Representing control that can swap between different
factions/protagonists, via
FocalContext
s. - Representing domains in which a transition at any discovered decision point can be taken, via 'spreading'-focalized domains. Note that unfortunately, this complicates the view of position, since there may be multiple active decisions or even no active decisions at a particular step.
- Representing multiple concurrent active decisions (e.g., an
omnipresent menu option that affects exploration in the main
game world) via multiple
Consequence
s replaceEffect
s, retaining the latter as one sub-type.Challenge
andCondition
nodes and containment can be used to represent very complex outcomes from a transition, including outcomes that depend onSkill
s. An entire new syntax for writing out complexConsequence
s has been introduced (see theparsing.ParseFormat.parseConsequence
examples).- Parsing code has been stripped out from much of the core libraries
to simplify their code, and put into a new
parsing.py
. Sadly, this does mean that in a few contexts where before you could use a compound decision name with a zone part you must now explicitly use something like aDecisionSpecifier
rather than just a string that will be parsed into one. - In addition to
Capability
s andToken
s, mechanisms now allow for specifying game state that is attached to decisions rather than being part of the player's focal context. This mainly makes naming easier, as mechanisms haveMechanismID
s and can share names, but requirements look them up according to nearby decisions allowing (in most cases) for a name like 'lever' to be re-used across many different decisions. - ALL volatile game state that can be modified by effects (other than
'edit') is now stored in the
State
, including taken-counts for transitions to enforce delay and charges restrictions and a deactivated-map for 'deactivate' effects. This will help in contexts like search where you can maintain a singleDecisionGraph
and search throughState
possibilities. It also helps with from a final explorationSituation
to approximate what the full form of an initial game graph would have been. - Steps in a
DiscreteExploration
are now categorized asExplorationAction
s, with more clarity in representing things like warps. - In journals, zone information as part of an exploration or observation should now be included as part of the destination specifier, rather than taking up an extra argument slot which had been awkwardly positioned.
- Several
DiscreteExploration
methods have been eliminated in favor of centralizinggetSituation
and accessing the various sub-parts of the situation. Several other -AtStep methods have been eliminated, in favor of adding defaultstep
arguments to base fetch methods.
- The first nascent support for open-world exploration in
- v0.6.1 fixes egtool.py script to include new optional command-line args instead of mandatory args.
- v0.6.0 adds Graphviz Dot format support (both import and export) and
fixes up some bugs with the JSON import/export. Also changes tags so
that they have values instead of just being part of a set. Analysis
tools have expanded a bit and a system of metafunctions for
automatically applying smallest-unit analysis tools to larger units
has been added so we don't have to re-write "apply this to each
situation" a bunch of times. Analysis tools are set up to run every
tool on a file and write results to a CSV file (see
main.py
for analysis tool configuration). Theegtool.py
script now accepts command-line options but falls back to interactive prompting. Finally finished describeProgress and overhauled analysis tests so that we don't have any xfails right now. Adds 'extinguish' and 'complicate' journal entry types to better support mistaken impressions. - v0.5.1 reorganizes some testing code out of the import-module run path.
- v0.5 includes a few bugfixes over 0.4, and most notably a stable syntax for entering relative mode at the current location, as well as an 'F' entry type for "fulfills" to note power equivalence. It also introduces the first real analysis tool, which just counts the number of unexplored options at each step of the graph.
- v0.4 introduces the 'actionPart' target type so that you can do 'oa' to
observe an action without taking it. It also introduces long-form
entry types and targets: you can just write out the full name of an
entry type, possibly followed by an @ and either a full or
abbreviated target type. Hopefully this helps make things more
accessible for beginners. There are also now a few built-in debug
commands available for printing relvant stuff. More may be added as
they become popular. It also introduces equivalences, stored in the
DecisionGraph
, which allow powers (but not tokens) to count as being obtained when one of a set of other requirements is met instead. The 'fulfills' journal entry can add these. - v0.3 is a pretty big overhaul. Changes journal format a bit (zones are
now easier to deal with). Adds command-line interface (
__main__.py
via API inmain.py
). Adds interactive scriptegtool
. Adds JSON serialization and__eq__
methods forDecisionGraph
andExploration
types. Fills out 'edit' effect type with a newCommand
syntax which is it's own tiny DSL for editing graphs/explorations. Also adds aliases in the journal format so that it's easier to store/recall complex but repeated patterns. Extends testing code quite a bit and fixes a fair number of bugs found via those tests, although coverage is still incomplete. This version pushes module compatibility up to 3.10 since the type checking code is to tightly intertwined with the actual runtime code in places to be easily separable and it uses 3.10 features. One final big change: the default journal format has changed so that 'g' is for tag, 't' (which used to be tag) is for 'retrace', and 'r' (which used to be retrace) is for 'return'). 'R' is no longer used by the default format. Note that until 1.0, there may continue to be some instability in the default journal format. - v0.2 Journal functionality (
journal.py
) is working at a basic level, with a few things still to-do (e.g., edit effects). Design has changed since previous versions. The zone system now works, although needs more testing. Design will be iterated on so the API and particularly the journal format is not 100% stable yet. Changed version support from 3.7+ to 3.8+ because of needing typing.Literal. - v0.1.2 Core functionality (
core.py
) is working & tested, with the exception of the zones system. Journals are not working, and tests for those have been disabled for now. Could be used for representation purposes, but is not yet complete. This version is effectively the first alpha release since I'm demoing at the PCG workshop. Note most of the 'core capabilities' are still TODO. - v0.1.1 Still pre-alpha as it's in the process of being re-architected a
bit, but some core functionality is present if rough (e.g.,
core.DecisionGraph
andcore.Exploration
). - v0.1 Initial pre-alpha upload.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file exploration-0.7.4.tar.gz
.
File metadata
- Download URL: exploration-0.7.4.tar.gz
- Upload date:
- Size: 299.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.0.0 CPython/3.11.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ec4714176663d9ad42ac66171a37d1ed6415e4254551f196480ad6a7ec513f95 |
|
MD5 | d0cdfd9c0db9fc475712065c5f8f7a9c |
|
BLAKE2b-256 | 8a2dea257cba9541a27f350f334f7e7741bc790c599fd08bcac43725a3c66ab1 |
File details
Details for the file exploration-0.7.4-py3-none-any.whl
.
File metadata
- Download URL: exploration-0.7.4-py3-none-any.whl
- Upload date:
- Size: 301.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.0.0 CPython/3.11.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2ea8e7a2e62069ec1c21223d31243209e7d02c91a57b0a66faca1ab20a8dac30 |
|
MD5 | 63dbadd10c133411e68ef4918318ddad |
|
BLAKE2b-256 | 7d559044fd4713727ab076b1034f8f17f593437da1636373502faa927c29fe51 |