artificial-intelligenceriver-crossing-puzzlepddl

PDDL - The Goat, Wolf and the Cabbage


I've been asked to write a solution to the famous "Goat, Wolf and the Cabbage" scernario. The scenario goes as follows:

The farmer wants to transport all three across the river. However, if:

So one solution to the problem is as follows:

However, I'm having trouble projecting this into PDDL. I've been give the problem definition:

(define 
(problem boat1)
(:domain boat)
; only needs two objects, namely representing
; either banke side of the river, [w]est and [e]ast
(:objects  w e)
(:INIT 
    ; wolf, goat, cabbage, boat are all on 
    ; the west side to start with
    (config w w w w)

    ; represent all valid states
    ; these two are the special case,
    ; representing that wolf and cabbage are
    ; safe together even if the boat is away
    (valid w e w e)
    (valid e w e w)

    ; these are all cases where two entities
    ; are always safe as long as the boat is 
    ; with them. In other words, a single entity
    ; on the other side is also always safe
    ; for west side
    (valid w w w w)
    (valid w w e w)
    (valid w e w w)
    (valid e w w w)
    ; for east side
    (valid e e e e)
    (valid e e w e)
    (valid e w e e)
    (valid w e e e)
    ; these are all valid states that are
    ; ever allowed


)

(:goal (AND 
        ; they all have to move to the east side
        (config e e e e)
    )
)

Finally, we've been given only 1 predicate, and have been told that this can be done with 4 actions. Move_empty, move_goat, move_wolf, move_cabbage.

The predicate is:

(config ?wolf ?goat ?cabbage ?boat) (valid ?wolf ?goat ?cabbage ?boat)

and I've tried to start on move_empty with:

    (:action move_empty
     :parameters (?from ?to)
     :precondition (and (valid ?x ?y ?z ?w) (on_left ?from) (on_right ?to))                      
     :effect (and (valid ?x ?y ?z ?w)))

I do not wish for answers, only help and advice on how to solve this as there is not a lot of information on PDDL, from what I can find.


Solution

  • NOTE: I don't know the pddl language, this is what I achieved by looking at your code.


    MAIN IDEA

    In your problem, each entity is described as either being on the west or east bank of the river and entities are identified using their relative position within the predicates config and valid.

    Each action starts from a given configuration and must end into another configuration. In addition, we must require the end configuration to be valid.

    So move_empty from the east to the west side of the bank is as simple as:

      (:action move_empty_ew :parameters (?x ?y ?z)
       :precondition (and (config ?x ?y ?z e) (valid ?x ?y ?z w))
       :effect (and (not (config ?x ?y ?z e)) (config ?x ?y ?z w))
      )
    

    Here, we let the positions of all other entities (the wolf, the goat and the cabbage) to be undetermined, while we require that initially the boat is on the east bank and that letting the boat go to the west bank while leaving the animals unattended is a valid move. If all these conditions are met, then we move to the desired configuration.


    SOLUTION

    Notice that i refined the name of the actions so that they are more informative wrt. the actual action that is being taken.

    boat-domain.pddl

    (define (domain boat)
      (:requirements :equality)
    
      (:predicates
        (config ?wolf ?goat ?cabbage ?boat)
        (valid ?wolf ?goat ?cabbage ?boat)
      )
    
      (:action move_empty_ew :parameters (?x ?y ?z)
       :precondition (and (config ?x ?y ?z e) (valid ?x ?y ?z w))
       :effect (and (not (config ?x ?y ?z e)) (config ?x ?y ?z w))
      )
      (:action move_empty_we :parameters (?x ?y ?z)
       :precondition (and (config ?x ?y ?z w) (valid ?x ?y ?z e))
       :effect (and (not (config ?x ?y ?z w)) (config ?x ?y ?z e))
      )
    
      (:action move_wolf_ew :parameters (?y ?z)
       :precondition (and (config e ?y ?z e) (valid w ?y ?z w))
       :effect (and (not (config e ?y ?z e)) (config w ?y ?z w))
      )
      (:action move_wolf_we :parameters (?y ?z)
       :precondition (and (config w ?y ?z w) (valid e ?y ?z e))
       :effect (and (not (config w ?y ?z w)) (config e ?y ?z e))
      )
    
      (:action move_goat_ew :parameters (?x ?z)
       :precondition (and (config ?x e ?z e) (valid ?x w ?z w))
       :effect (and (not (config ?x e ?z e)) (config ?x w ?z w))
      )
      (:action move_goat_we :parameters (?x ?z)
       :precondition (and (config ?x w ?z w) (valid ?x e ?z e))
       :effect (and (not (config ?x w ?z w)) (config ?x e ?z e))
      )
    
      (:action move_cabbage_ew :parameters (?x ?y)
       :precondition (and (config ?x ?y e e) (valid ?x ?y w w))
       :effect (and (not (config ?x ?y e e)) (config ?x ?y w w))
      )
      (:action move_cabbage_we :parameters (?x ?y)
       :precondition (and (config ?x ?y w w) (valid ?x ?y e e))
       :effect (and (not (config ?x ?y w w)) (config ?x ?y e e))
      )
    )
    

    boat-prob.pddl

    (define (problem boat)
      (:domain boat)
      (:objects w e)
    
      (:INIT (config w w w w)
        (valid w e w e) (valid e w e w)
        (valid w w w w) (valid w w e w)
        (valid w e w w) (valid e w w w)
        (valid e e e e) (valid e e w e)
        (valid e w e e) (valid w e e e)
      )
    
      (:goal (config e e e e))
    )
    

    I used fast-downward to find a minimum-length solution:

    ~$ fast-downward.py --alias seq-opt-bjolp boat-domain.pddl boat-prob.pddl
    

    which actually is:

    move_goat_we w w (1)
    move_empty_ew w e w (1)
    move_cabbage_we w e (1)
    move_goat_ew w e (1)
    move_wolf_we w e (1)
    move_empty_ew e w e (1)
    move_goat_we e e (1)
    Plan length: 7 step(s).
    Plan cost: 7