Skip to content

SomeoneElse37/pddl-parser

 
 

Repository files navigation

Relevant files and directories:

  • sokoban/
    • sokoban.pddl
    • level*.lvl
    • level*.pddl
    • converter.py
  • soko2/
    • soko2.pddl
    • level*.lvl
    • level*.pddl
    • converter2.py
  • soko3/
    • soko3.py
    • level*.pddl
  • engine.py
  • engine2.py
  • engine3.py
  • trajectory.py
  • trajectory2.py

Most important here are the contents of the soko3/ directory, engine3.py, and the two trajectory*.py scripts.

soko3/soko3.pddl is a copy of the sokoban from the 2011 International Planning Competition, published here, edited to remove any reference to action costs, because my code doesn't know how to deal with those. The other PDDL files in soko3/ are copies of problem files from the same source, also edited to remove action costs and to work around some bugs in the PUCRS parser.

sokoban/sokoban.pddl is the first Sokoban domain I created, with eight different actions for moving and pushing in each of the cardinal directions. The other PDDL files in sokoban/ are problem files containing levels for that domain. The level*.lvl files are human-readable depictions of levels, in the same ASCII format displayed by the engine scripts. sokoban/converter.py is a script that translates a lvl file into a PDDL problem file combatible with this domain, and is how most of the sokoban/level*.pddl files were generated. Invoke it as such:

cd sokoban
python converter.py lvl_file pddl_file

soko2/ contains the second Sokoban domain I created before adopting the IPC domain, which is much more concise and flexible than my earlier attempt. It only has three actions, it adds pits into which pushable stones can be dropped to create a normal floor (demonstrated in soko2/level3.lvl and soko2/level3.pddl), and it allows problem (and lvl) files to specify custom movement directions (demonstrated in soko2/level4.lvl and soko2/level4.pddl).

The engine*.py scripts allow the user to interactively play Sokoban, while executing PDDL code behind the scenes to compute the results of each action. Use WASD to move, U to undo your last move, and R to restart the level. You'll also need to press Enter after every letter to send your move to the engine script. I know this isn't particularly user-friendly, but I couldn't figure out how to get key listeners to work.

Launch them from the command line like so:

python -B engine_script domain_file problem_file [trajectory_file] [--verbose]

  • engine_script: engine.py, engine2.py, or engine3.py, depending on which domain you intend to use.
  • domain_file: The domain file. Should be sokoban/sokoban.pddl for engine.py; soko2/soko2.pddl for engine2.py, or soko3/soko3.pddl for engine3.py.
  • problem_file: One of the level*.pddl files in the same directory as the domain file. This determines which level you'll play.
  • trajectory_file: Where the engine script should save a trajectory file containing a log of all the actions taken and the game states before and after each one. If you name a file that already exists, it will be overwritten. Optional. Not available in engine.py.
  • --verbose: If absent, the trajectory will only list actions that changed the game state, and will not include undoes or restarts. If present, the trajectory will also include actions that could not be carried out because their preconditions were not met, as well as undoes, restarts, and all game states before and after all of the above. These additions are not standard in any way, so son't expect these trajectories to be compatible with any code outside this repository. Only available in engine3.py.

All engine scripts display the current game state to the user in the same ASCII-art format, with two characters representing each grid cell.
[] Wall
() Pushable stone
:) Player
// Goal (get a stone onto each of these to solve the puzzle)
{} Stone on goal
%) Player on goal
   Walkable floor
\/ Pit (only available in soko2/level3.pddl; push a stone into it to transform both into floor)

The trajectory*.py scripts take as input a trajectory file, and attempt to recreate the domain file from it. They should work with all three domains, but have only been thoroughly tested with soko3. Both have the same command-line interface:

python -B trajectory_script trajectory_file output_domain_file [domain_name]

  • trajectory_script: Either trajectory.py or trajectory2.py
  • trajectory_file: The trajectory file generated by one of the engine scripts
  • output_domain_file: Where the script should store the domain it generates
  • domain_name: The domain name to be stated in the output domain file. Should match that of the domain and problem files originally fed into the engine script. Use sokoban for sokoban/, soko2for soko2/, or sokoban-sequential for soko3/. Defaults to reconstructed if not given.

trajectory.py will tag the actions in the domain files it generates with all concievable preconditions, except for those that would have made an action listed in the trajectory impossible to complete. It tends to list too many preconditions, oftentimes making other levels impossible to solve, as actions necessary to complete them are marked as impossible. Intended to be used with non-verbose trajectory files, though it is compatible with verbose trajectories and will ignore the additional information contained within them.

trajectory2.py will tag the actions in domain files it generates with only the preconditions that the script can prove must exist, because it can pin down each of those preconditions as the singular reason why some action in the trajectory file could not be carried out. This script tends to include too few predicates in the domain files it generates, making actions able to be used in situations where they really should not be, oftentimes leading to strange behavior.

Usage example:
python -B engine3.py soko3/soko3.pddl soko3/level2.pddl log.log --verbose
// gameplay omitted for brevity
python -B trajectory.py log.log output.pddl sokoban-sequential
python -B engine3.py output.pddl soko3/levelp3.pddl
// level cannot be solved; use ctrl-C to exit
python -B trajectory2.py log.log output.pddl sokoban-sequential
python -B engine3.py output.pddl soko3/levelp3.pddl

The following is the README inherited from pucrs-automated-planning/pddl-parser, the Python-based PDDL parser and planner upon which the work described above is built.

PDDL Parser Build Status DOI

Planning in Python

Source

Parser execution

# Parser can be used separately
cd pddl-parser
python -B PDDL.py examples/dinner/dinner.pddl examples/dinner/pb1.pddl
# Output
----------------------------
['define',
 ['domain', 'dinner'],
 [':requirements', ':strips'],
 [':predicates', ['clean'], ['dinner'], ['quiet'], ['present'], ['garbage']],
 [':action', 'cook', ':precondition', ['clean'], ':effect', ['dinner']],
 [':action', 'wrap', ':precondition', ['quiet'], ':effect', ['present']],
 [':action',
  'carry',
  ':precondition',
  ['garbage'],
  ':effect',
  ['and', ['not', ['garbage']], ['not', ['clean']]]],
 [':action',
  'dolly',
  ':precondition',
  ['garbage'],
  ':effect',
  ['and', ['not', ['garbage']], ['not', ['quiet']]]]]
----------------------------
['define',
 ['problem', 'pb1'],
 [':domain', 'dinner'],
 [':init', ['garbage'], ['clean'], ['quiet']],
 [':goal', ['and', ['dinner'], ['present'], ['not', ['garbage']]]]]
----------------------------
Domain name: dinner
action: cook
  parameters: []
  positive_preconditions: [['clean']]
  negative_preconditions: []
  add_effects: [['dinner']]
  del_effects: []

action: wrap
  parameters: []
  positive_preconditions: [['quiet']]
  negative_preconditions: []
  add_effects: [['present']]
  del_effects: []

action: carry
  parameters: []
  positive_preconditions: [['garbage']]
  negative_preconditions: []
  add_effects: []
  del_effects: [['garbage'], ['clean']]

action: dolly
  parameters: []
  positive_preconditions: [['garbage']]
  negative_preconditions: []
  add_effects: []
  del_effects: [['garbage'], ['quiet']]

----------------------------
Problem name: pb1
Objects: {}
State: [['garbage'], ['clean'], ['quiet']]
Positive goals: [['dinner'], ['present']]
Negative goals: [['garbage']]

Planner execution

# Planning using BFS
cd pddl-parser
python -B planner.py examples/dinner/dinner.pddl examples/dinner/pb1.pddl
# Output
Time: 0.00200009346008s
plan:
action: cook
  parameters: []
  positive_preconditions: [['clean']]
  negative_preconditions: []
  add_effects: [['dinner']]
  del_effects: []

action: wrap
  parameters: []
  positive_preconditions: [['quiet']]
  negative_preconditions: []
  add_effects: [['present']]
  del_effects: []

action: carry
  parameters: []
  positive_preconditions: [['garbage']]
  negative_preconditions: []
  add_effects: []
  del_effects: [['garbage'], ['clean']]

About

🐍 Planning in Python

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Python 100.0%